Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a slot_map::partition(Pred) member function #133

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions SG14/slot_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,46 @@ class slot_map
return 1;
}

constexpr void underlying_swap(const_iterator cit, const_iterator cjt) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment and complexity would be nice to conform to the rest of the header.

// 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(this->cbegin(), cit);
auto it = std::next(this->begin(), it_value_index);
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(this->cbegin(), cjt);
auto jt = std::next(this->begin(), jt_value_index);
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);
}

template<class Pred>
constexpr iterator partition(const Pred& pred) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments and complexity would be welcome.

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;
}
this->underlying_swap(it, jt);
++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
Expand Down
40 changes: 40 additions & 0 deletions SG14_test/slot_map_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,39 @@ static void EraseRangeTest()
}
}

template<class SM>
static void PartitionTest()
{
using T = typename SM::mapped_type;
SM sm;
auto key3 = sm.insert(Monad<T>::from_value(3));
auto key1 = sm.insert(Monad<T>::from_value(1));
auto key4 = sm.insert(Monad<T>::from_value(4));
auto key5 = sm.insert(Monad<T>::from_value(5));
auto key9 = sm.insert(Monad<T>::from_value(9));
auto key2 = sm.insert(Monad<T>::from_value(2));
auto key6 = sm.insert(Monad<T>::from_value(6));

auto pivot = sm.partition([](const auto& elt) {
return Monad<T>::value_of(elt) >= 5;
});

for (auto it = sm.begin(); it != pivot; ++it) {
assert(Monad<T>::value_of(*it) >= 5);
}
for (auto it = pivot; it != sm.end(); ++it) {
assert(Monad<T>::value_of(*it) < 5);
}

assert(Monad<T>::value_of(*sm.find(key3)) == 3);
assert(Monad<T>::value_of(*sm.find(key1)) == 1);
assert(Monad<T>::value_of(*sm.find(key4)) == 4);
assert(Monad<T>::value_of(*sm.find(key5)) == 5);
assert(Monad<T>::value_of(*sm.find(key9)) == 9);
assert(Monad<T>::value_of(*sm.find(key2)) == 2);
assert(Monad<T>::value_of(*sm.find(key6)) == 6);
}

template<class SM>
static void ReserveTest()
{
Expand Down Expand Up @@ -430,6 +463,7 @@ void sg14_test::slot_map_test()
InsertEraseStressTest<slot_map_1>([i=3]() mutable { return ++i; });
EraseInLoopTest<slot_map_1>();
EraseRangeTest<slot_map_1>();
PartitionTest<slot_map_1>();
ReserveTest<slot_map_1>();
VerifyCapacityExists<slot_map_1>(true);

Expand All @@ -440,6 +474,7 @@ void sg14_test::slot_map_test()
InsertEraseStressTest<slot_map_2>([i=5]() mutable { return ++i; });
EraseInLoopTest<slot_map_2>();
EraseRangeTest<slot_map_2>();
PartitionTest<slot_map_2>();
ReserveTest<slot_map_2>();
VerifyCapacityExists<slot_map_2>(true);

Expand All @@ -451,6 +486,7 @@ void sg14_test::slot_map_test()
InsertEraseStressTest<slot_map_3>([i=3]() mutable { return ++i; });
EraseInLoopTest<slot_map_3>();
EraseRangeTest<slot_map_3>();
PartitionTest<slot_map_3>();
ReserveTest<slot_map_3>();
VerifyCapacityExists<slot_map_3>(true);
#endif // __cplusplus >= 201703L
Expand All @@ -462,6 +498,7 @@ void sg14_test::slot_map_test()
InsertEraseStressTest<slot_map_4>([i=7]() mutable { return ++i; });
EraseInLoopTest<slot_map_4>();
EraseRangeTest<slot_map_4>();
PartitionTest<slot_map_4>();
ReserveTest<slot_map_4>();
VerifyCapacityExists<slot_map_4>(false);

Expand All @@ -472,6 +509,7 @@ void sg14_test::slot_map_test()
InsertEraseStressTest<slot_map_5>([i=7]() mutable { return ++i; });
EraseInLoopTest<slot_map_5>();
EraseRangeTest<slot_map_5>();
PartitionTest<slot_map_5>();
ReserveTest<slot_map_5>();
VerifyCapacityExists<slot_map_5>(false);

Expand All @@ -482,6 +520,7 @@ void sg14_test::slot_map_test()
InsertEraseStressTest<slot_map_6>([i=7]() mutable { return ++i; });
EraseInLoopTest<slot_map_6>();
EraseRangeTest<slot_map_6>();
PartitionTest<slot_map_6>();
ReserveTest<slot_map_6>();
VerifyCapacityExists<slot_map_6>(false);

Expand All @@ -497,6 +536,7 @@ void sg14_test::slot_map_test()
InsertEraseStressTest<slot_map_7>([i=7]() mutable { return std::make_unique<int>(++i); });
EraseInLoopTest<slot_map_7>();
EraseRangeTest<slot_map_7>();
PartitionTest<slot_map_7>();
ReserveTest<slot_map_7>();
VerifyCapacityExists<slot_map_7>(false);
}
Expand Down