Replacements mergeReplacements(const Replacements &First, const Replacements &Second) { if (First.empty() || Second.empty()) return First.empty() ? Second : First; // Delta is the amount of characters that replacements from 'Second' need to // be shifted so that their offsets refer to the original text. int Delta = 0; Replacements Result; // Iterate over both sets and always add the next element (smallest total // Offset) from either 'First' or 'Second'. Merge that element with // subsequent replacements as long as they overlap. See more details in the // comment on MergedReplacement. for (auto FirstI = First.begin(), SecondI = Second.begin(); FirstI != First.end() || SecondI != Second.end();) { bool NextIsFirst = SecondI == Second.end() || (FirstI != First.end() && FirstI->getOffset() < SecondI->getOffset() + Delta); MergedReplacement Merged(NextIsFirst ? *FirstI : *SecondI, NextIsFirst, Delta); ++(NextIsFirst ? FirstI : SecondI); while ((Merged.mergeSecond() && SecondI != Second.end()) || (!Merged.mergeSecond() && FirstI != First.end())) { auto &I = Merged.mergeSecond() ? SecondI : FirstI; if (Merged.endsBefore(*I)) break; Merged.merge(*I); ++I; } Delta -= Merged.deltaFirst(); Result.insert(Merged.asReplacement()); } return Result; }
std::vector<PartialSolution*> LHConstraintKit::solveLeastMT(std::vector<std::string> kinds, bool useDefaultSinks) { assert(leastSolutions.count("default")); PartialSolution *P = leastSolutions["default"]; PartialSolution *DS = leastSolutions["default-sinks"]; std::vector<PartialSolution*> ToMerge; for (std::vector<std::string>::iterator kind = kinds.begin(), end = kinds.end(); kind != end; ++kind) { assert(lockedConstraintKinds.insert(*kind).second && "Already solved"); assert(!leastSolutions.count(*kind)); leastSolutions[*kind] = new PartialSolution(getOrCreateConstraintSet(*kind), false); ToMerge.push_back(new PartialSolution(*leastSolutions[*kind])); } // Make copy of the set of solutions for returning when we're done std::vector<PartialSolution*> Merged(ToMerge); const unsigned T = 16; // Now kick off up to 'T' jobs, each with a vector of merges to do MergeInfo MI[T]; // Make sure all threads know the default solution: for (unsigned i = 0; i < T; ++i) { MI[i].Default = P; MI[i].DefaultSinks = DS; MI[i].useDefaultSinks = useDefaultSinks; } // And round-robin hand out merge jobs: unsigned TID = 0; while (!ToMerge.empty()) { MergeInfo* M = &MI[TID]; TID = (TID + 1) % T; M->Mergees.push_back(ToMerge.back()); ToMerge.pop_back(); } // Finally, kick off all the threads // with non-empty work queues std::vector<pthread_t> Threads; for (unsigned i = 0; i < T; ++i) { MergeInfo *M = &MI[i]; if (!M->Mergees.empty()) { pthread_t Thread; if (::pthread_create(&Thread, NULL, merge, M)) { assert(0 && "Failed to create thread!"); } Threads.push_back(Thread); } } // Wait for them all to finish while (!Threads.empty()) { ::pthread_join(Threads.back(), NULL); Threads.pop_back(); } return Merged; }