From 9d19dd179e7c17fc6bd382fc2aed021e6929b62f Mon Sep 17 00:00:00 2001 From: Morwenn Date: Mon, 6 Dec 2021 18:49:47 +0100 Subject: [PATCH] Make dmsort work with bidirectional iterators --- drop_merge_sort.hpp | 32 +++++++++++++++----------------- tests.cpp | 28 ++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/drop_merge_sort.hpp b/drop_merge_sort.hpp index 7b507cf..85f4988 100644 --- a/drop_merge_sort.hpp +++ b/drop_merge_sort.hpp @@ -30,9 +30,7 @@ namespace detail { // with-trivial-copies version template void dmsort(Iter begin, Iter end, Comp comp, std::true_type) { - size_t size = end - begin; - - if (size < 2) + if (begin == end || std::next(begin) == end) return; using Value = typename std::iterator_traits::value_type; @@ -45,11 +43,12 @@ namespace detail { constexpr size_t recency = 8; while (read != end) { - if (begin != write && comp(*read, *(write - 1))) { + if (begin != write && comp(*read, *std::prev(write))) { - if (double_comparison && num_dropped_in_row == 0 && write > begin+1 && !comp(*read, *(write-2))) { - dropped.push_back(*(write-1)); - *(write-1) = *read; + if (double_comparison && num_dropped_in_row == 0 && write != std::next(begin) + && !comp(*read, *std::prev(write, 2))) { + dropped.push_back(*std::prev(write)); + *std::prev(write) = *read; ++read; continue; } @@ -62,7 +61,7 @@ namespace detail { for (int i = 0; i < num_dropped_in_row; ++i) { dropped.pop_back(); } - read -= num_dropped_in_row; + std::advance(read, -num_dropped_in_row); --write; dropped.push_back(*write); @@ -86,7 +85,7 @@ namespace detail { while (!dropped.empty()) { auto & last_dropped = dropped.back(); - while (begin != write && comp(last_dropped, *(write - 1))) { + while (begin != write && comp(last_dropped, *std::prev(write))) { --back; --write; *back = std::move(*write); @@ -100,9 +99,7 @@ namespace detail { // move-only version template void dmsort(Iter begin, Iter end, Comp comp, std::false_type) { - size_t size = end - begin; - - if (size < 2) + if (begin == end || std::next(begin) == end) return; using Value = typename std::iterator_traits::value_type; @@ -115,11 +112,12 @@ namespace detail { constexpr size_t recency = 8; while (read != end) { - if (begin != write && comp(*read, *(write - 1))) { + if (begin != write && comp(*read, *std::prev(write))) { - if (double_comparison && num_dropped_in_row == 0 && write > begin+1 && !comp(*read, *(write-2))) { - dropped.push_back(std::move(*(write-1))); - *(write-1) = std::move(*read); + if (double_comparison && num_dropped_in_row == 0 && write != std::next(begin) + && !comp(*read, *std::prev(write, 2))) { + dropped.push_back(std::move(*std::prev(write))); + *std::prev(write) = std::move(*read); ++read; continue; } @@ -157,7 +155,7 @@ namespace detail { while (!dropped.empty()) { auto & last_dropped = dropped.back(); - while (begin != write && comp(last_dropped, *(write - 1))) { + while (begin != write && comp(last_dropped, *std::prev(write))) { --back; --write; *back = std::move(*write); diff --git a/tests.cpp b/tests.cpp index 3270791..a890cb9 100644 --- a/tests.cpp +++ b/tests.cpp @@ -1,7 +1,10 @@ -#include -#include #include +#include +#include +#include #include +#include +#include #include "drop_merge_sort.hpp" /* @@ -59,6 +62,24 @@ void test_counts(){ PRINT(moveass); } +/* + Check that dmsort can sort bidirectional iterators +*/ + +void test_list(){ + std::vector vec; + for(int i = 0; i < 500000; ++i) + vec.push_back(i); + + // Create a shuffled list + std::minstd_rand engine(123456); + std::shuffle(vec.begin(), vec.end(), engine); + std::list li(vec.begin(), vec.end()); + + dmsort(li.begin(), li.end()); + std::cout << std::is_sorted(li.begin(), li.end()) << std::endl; +} + /* Check that the move-only version actually works with move-only types */ @@ -106,7 +127,10 @@ void test_non_default_constructible(){ } int main(){ + std::cout << std::boolalpha; + test_counts(); + test_list(); test_noncopyable(); test_non_default_constructible(); }