#pragma once #include #include #include #include #include #include #include namespace algo { class MergeSort_v1 { private: template static auto merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start) -> void { Iterator start_m = start; Iterator begin = output_start; Iterator start2 = middle + 1; //merge from input until one half completes while (start <= middle && start2 <= end) { if (cmp(*start, *start2)) { *output_start = *start; start++; } else { *output_start = *start2; start2++; } output_start++; } //try to finish first half while (start <= middle) { *output_start = *start; start++; output_start++; } while (start2 <= end) { *output_start = *start2; start2++; output_start++; } const auto size = std::distance(start_m, end); for (auto i = 0; i <= size; i++, start_m++, begin++) { *start_m = *begin; } } template static auto ms_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start) -> void { Iterator mid = start; Iterator begin = output_start; if (std::distance(start, end) < 1) { return; } else { //move mid iterator litterally to the mid std::advance(mid, std::distance(start, end) / 2); //sort the first half within an recursion ms_split(output_vec, start, mid, cmp, output_start); //move output iterator std::advance(output_start, std::distance(start, mid + 1)); //sort the second half within a recursion ms_split(output_vec, mid + 1, end, cmp, output_start); //merge everything together starting from the complete beginning merge(start, mid, end, cmp, begin); } } public: template static auto sort(Iterator start, Iterator end, Comparator cmp) -> void { using valtype = typename std::iterator_traits::value_type; std::vector temporary_dataset(std::distance(start, end)); ms_split(temporary_dataset, start, end - 1, cmp, temporary_dataset.begin()); } }; class MergeSort_v2 { private: template static auto mt_merge(Container left, Container right, Comparator cmp) -> Container { //using Iterator = typename std::iterator_traits::value_type; Container output; auto lefti = left.begin(); auto righti = right.begin(); while (lefti < left.end() && righti < right.end()) { if (cmp(*lefti, *righti)) { output.emplace_back(std::move(*lefti)); lefti++; } else { output.emplace_back(std::move(*righti)); righti++; } } while (lefti < left.end()) { output.emplace_back(std::move(*lefti)); lefti++; } while (righti < right.end()) { output.emplace_back(std::move(*righti)); righti++; } return output; } template static auto merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start, std::recursive_mutex &dataset_guard) -> void { Iterator start_m = start; Iterator begin = output_start; Iterator start2 = middle + 1; //merge from input until one half completes while (start <= middle && start2 <= end) { if (cmp(*start, *start2)) { *output_start = *start; start++; } else { *output_start = *start2; start2++; } output_start++; } //try to finish first half while (start <= middle) { *output_start = *start; start++; output_start++; } while (start2 <= end) { *output_start = *start2; start2++; output_start++; } dataset_guard.lock(); const auto size = std::distance(start_m, end); for (auto i = 0; i <= size; i++, start_m++, begin++) { *start_m = *begin; } dataset_guard.unlock(); } template static auto mt_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start, int &nthreads, std::recursive_mutex &dataset_guard, std::mutex &depth_guard) -> void { Iterator mid = start; Iterator to_start = output_start; if (std::distance(start, end) < 1) { return; } bool rem_threads; { std::lock_guard guard(depth_guard); //RAII guard rem_threads = nthreads > 1; } if (rem_threads) { { std::lock_guard guard(depth_guard); //RAII guard nthreads -= 2; } std::advance(mid, std::distance(start, end) / 2); std::thread t1([&]() { mt_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); }); std::advance(output_start, std::distance(start, mid + 1)); std::thread t2([&]() { mt_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); }); //merge everything together starting from the complete beginning t1.join(); t2.join(); std::vector left; left.assign(start, mid); std::vector right; right.assign(mid + 1, end); mt_merge(left, right, cmp); } else { //move mid iterator litterally to the mid std::advance(mid, std::distance(start, end) / 2); //sort the first half within an recursion mt_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); //move output iterator std::advance(output_start, std::distance(start, mid + 1)); //sort the second half within a recursion mt_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); std::vector left; left.assign(start, mid); std::vector right; right.assign(mid + 1, end); mt_merge(left, right, cmp); } } template static auto ms_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start, int &nthreads, std::recursive_mutex &dataset_guard, std::mutex &depth_guard) -> void { Iterator mid = start; Iterator begin = output_start; if (std::distance(start, end) < 1) { //Quit on smalles list size (one element is always sorted) return; } else { if (nthreads > 1) { depth_guard.lock(); nthreads -= 2; depth_guard.unlock(); //move mid iterator litterally to the mid std::advance(mid, std::distance(start, end) / 2); //sort the first half within an recursion std::thread t1([&]() { ms_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); }); //move output iteratoroutput_vec, start, mid, cmp, output_start std::advance(output_start, std::distance(start, mid + 1)); //sort the second half within a recursion std::thread t2([&]() { ms_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); }); //merge everything together starting from the complete beginning t1.join(); t2.join(); merge(start, mid, end, cmp, begin, dataset_guard); } else { //move mid iterator litterally to the mid std::advance(mid, std::distance(start, end) / 2); //sort the first half within an recursion ms_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); //move output iterator std::advance(output_start, std::distance(start, mid + 1)); //sort the second half within a recursion ms_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); //merge everything together starting from the complete beginning merge(start, mid, end, cmp, begin, dataset_guard); } } } public: template static auto sort(Iterator start, Iterator end, Comparator cmp, int nthreads) -> void { using valtype = typename std::iterator_traits::value_type; std::vector temporary_dataset(std::distance(start, end)); std::recursive_mutex dataset_guard; std::mutex depth_guard; mt_split(temporary_dataset, start, end - 1, cmp, temporary_dataset.begin(), nthreads, dataset_guard, depth_guard); } }; class MergeSort_mt { template static auto merge(std::vector left, std::vector right, Comparator cmp, std::mutex &mut) -> std::vector { std::vector output; output.reserve(left.size() + right.size()); auto l = left.begin(); auto r = right.begin(); auto o = output.begin(); while (l < left.end() && r < right.end()) { if (cmp(*l, *r)) { outpbufut.insert(o, *l); l++; } else { output.insert(o, *r); r++; } o++; } while (l < left.end()) { output.insert(o, *l); o++; l++; } while (r < right.end()) { output.insert(o, *r); o++; r++; } return output; } template static auto split(std::vector data, Comparator cmp, int depth, int &max_depth, std::mutex &mut) -> std::vector{ if (data.size() <= 1) { return data; } else if (data.size() == 2) { if(cmp(data[0], data[1])) { return std::vector {data[0], data[1]}; } else { return std::vector {data[1], data[0]}; } } std::vector output; output.reserve(data.size()); auto mid = data.begin(); std::advance(mid, std::distance(data.begin(), data.end()) / 2); std::vector left(data.begin(), mid); std::vector right(mid, data.end()); if (depth < max_depth) { std::thread left_thread([&]() { left = split(left, cmp, depth + 1, max_depth, mut); }); std::thread right_thread([&]() { right = split(right, cmp, depth + 1, max_depth, mut); }); left_thread.join(); right_thread.join(); } else { left = split(left, cmp, depth + 1, max_depth, mut); right = split(right, cmp, depth + 1, max_depth, mut); } return merge(left, right, cmp, mut); } public: template static auto sort(std::vector &data, Comparator cmp, int max_depth = 0) -> void { std::mutex local_result_lock; std::vector output; output.reserve(data.size()); output = split(data, cmp, 0, max_depth, local_result_lock); data.assign(output.begin(), output.end()); } }; }