From 85f5713b2dd0a907d040924ea6c2fe689c64c02a Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Sun, 23 Sep 2018 18:22:52 -0700 Subject: [PATCH] Add a slot_map::partition(Pred) member function. Just like the standard `std::partition` algorithm, this member function reorders the slot_map's elements in such a way that all elements for which the predicate `pred` returns `true` precede the elements for which `pred` returns `false`. The relative order of the elements is not preserved. The function returns an iterator to the first element of the second group (which may be `end()`, in the case that all elements belong to the first group). Addresses part of #131, although I'm not sure whether this really addresses whatever use case @p-groarke is thinking of. --- SG14/slot_map.h | 34 +++++++++++++++++++++++++++++++ SG14_test/slot_map_test.cpp | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/SG14/slot_map.h b/SG14/slot_map.h index 87616f21..6c857b24 100644 --- a/SG14/slot_map.h +++ b/SG14/slot_map.h @@ -278,6 +278,40 @@ class slot_map return 1; } + template + constexpr iterator partition(const Pred& pred) { + iterator it = this->begin(); + iterator jt = this->end(); + if (it == jt) return it; + while (true) { + --jt; + if (it == jt) return it; + while (pred(*it)) { + ++it; + if (it == jt) return it; + } + while (!pred(*jt)) { + --jt; + if (it == jt) return it; + } + // Swap *it and *jt in the underlying container, + // but then fix up their keys so they don't appear to move. + auto it_value_index = std::distance(values_.begin(), it); + auto it_reversemap_iter = std::next(reverse_map_.begin(), it_value_index); + auto it_slot_iter = std::next(slots_.begin(), *it_reversemap_iter); + auto jt_value_index = std::distance(values_.begin(), jt); + auto jt_reversemap_iter = std::next(reverse_map_.begin(), jt_value_index); + auto jt_slot_iter = std::next(slots_.begin(), *jt_reversemap_iter); + + using std::swap; + swap(*it, *jt); + swap(*it_slot_iter, *jt_slot_iter); + swap(*it_reversemap_iter, *jt_reversemap_iter); + ++it; + if (it == jt) return it; + } + } + // clear() has O(n) time complexity and O(1) space complexity. // It also has semantics differing from erase(begin(), end()) // in that it also resets the generation counter of every slot diff --git a/SG14_test/slot_map_test.cpp b/SG14_test/slot_map_test.cpp index 4bd2a496..ac81302d 100644 --- a/SG14_test/slot_map_test.cpp +++ b/SG14_test/slot_map_test.cpp @@ -278,6 +278,39 @@ static void EraseRangeTest() } } +template +static void PartitionTest() +{ + using T = typename SM::mapped_type; + SM sm; + auto key3 = sm.insert(Monad::from_value(3)); + auto key1 = sm.insert(Monad::from_value(1)); + auto key4 = sm.insert(Monad::from_value(4)); + auto key5 = sm.insert(Monad::from_value(5)); + auto key9 = sm.insert(Monad::from_value(9)); + auto key2 = sm.insert(Monad::from_value(2)); + auto key6 = sm.insert(Monad::from_value(6)); + + auto pivot = sm.partition([](const auto& elt) { + return Monad::value_of(elt) >= 5; + }); + + for (auto it = sm.begin(); it != pivot; ++it) { + assert(Monad::value_of(*it) >= 5); + } + for (auto it = pivot; it != sm.end(); ++it) { + assert(Monad::value_of(*it) < 5); + } + + assert(Monad::value_of(*sm.find(key3)) == 3); + assert(Monad::value_of(*sm.find(key1)) == 1); + assert(Monad::value_of(*sm.find(key4)) == 4); + assert(Monad::value_of(*sm.find(key5)) == 5); + assert(Monad::value_of(*sm.find(key9)) == 9); + assert(Monad::value_of(*sm.find(key2)) == 2); + assert(Monad::value_of(*sm.find(key6)) == 6); +} + template static void ReserveTest() { @@ -430,6 +463,7 @@ void sg14_test::slot_map_test() InsertEraseStressTest([i=3]() mutable { return ++i; }); EraseInLoopTest(); EraseRangeTest(); + PartitionTest(); ReserveTest(); VerifyCapacityExists(true); @@ -440,6 +474,7 @@ void sg14_test::slot_map_test() InsertEraseStressTest([i=5]() mutable { return ++i; }); EraseInLoopTest(); EraseRangeTest(); + PartitionTest(); ReserveTest(); VerifyCapacityExists(true); @@ -451,6 +486,7 @@ void sg14_test::slot_map_test() InsertEraseStressTest([i=3]() mutable { return ++i; }); EraseInLoopTest(); EraseRangeTest(); + PartitionTest(); ReserveTest(); VerifyCapacityExists(true); #endif // __cplusplus >= 201703L @@ -462,6 +498,7 @@ void sg14_test::slot_map_test() InsertEraseStressTest([i=7]() mutable { return ++i; }); EraseInLoopTest(); EraseRangeTest(); + PartitionTest(); ReserveTest(); VerifyCapacityExists(false); @@ -472,6 +509,7 @@ void sg14_test::slot_map_test() InsertEraseStressTest([i=7]() mutable { return ++i; }); EraseInLoopTest(); EraseRangeTest(); + PartitionTest(); ReserveTest(); VerifyCapacityExists(false); @@ -482,6 +520,7 @@ void sg14_test::slot_map_test() InsertEraseStressTest([i=7]() mutable { return ++i; }); EraseInLoopTest(); EraseRangeTest(); + PartitionTest(); ReserveTest(); VerifyCapacityExists(false); @@ -497,6 +536,7 @@ void sg14_test::slot_map_test() InsertEraseStressTest([i=7]() mutable { return std::make_unique(++i); }); EraseInLoopTest(); EraseRangeTest(); + PartitionTest(); ReserveTest(); VerifyCapacityExists(false); }