#pragma once #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 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 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; ms_split(temporary_dataset, start, end - 1, cmp, temporary_dataset.begin(), nthreads, dataset_guard, depth_guard); } }; }