Skip to content
Merged
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
4 changes: 3 additions & 1 deletion stl/inc/flat_map
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,7 @@ private:
}

void _Make_invariants_fulfilled() {
if (empty()) { // FIXME maybe consider if (begin() == end()) for consistency with flat_set
if (empty()) {
return;
}

Expand Down Expand Up @@ -1130,6 +1130,8 @@ private:

void _Erase_dupes_if_not_multi() {
if constexpr (_IsUnique) {
// No _Clear_guard needed. The only callers are _Insert_range() (which has a _Clear_guard)
// and _Make_invariants_fulfilled() (which is called only by constructors).
auto _Sorted_view = _View_to_mutate();
const auto _New_last = _RANGES unique(_Sorted_view, _Erase_dupes_if_not_multi_pred()).begin();

Expand Down
24 changes: 15 additions & 9 deletions stl/inc/flat_set
Original file line number Diff line number Diff line change
Expand Up @@ -377,12 +377,12 @@ public:
_Guard._Target = nullptr;
}

// FIXME, the "erase" member functions need clear guards to restore the invariant when the underlying
// container doesn't provide the strong guarantee for its "erase" member functions.

// NB: `erase(iterator)` is identical to `erase(const_iterator)`
iterator erase(const const_iterator _Where) {
return _Mycont.erase(_Where);
_Clear_guard _Guard{this};
const auto _Ret = _Mycont.erase(_Where);
_Guard._Target = nullptr;
return _Ret;
}
size_type erase(const _Kty& _Val) {
return _Erase(_Val);
Expand All @@ -393,7 +393,10 @@ public:
return _Erase(_Val);
}
iterator erase(const const_iterator _First, const const_iterator _Last) {
return _Mycont.erase(_First, _Last);
_Clear_guard _Guard{this};
const auto _Ret = _Mycont.erase(_First, _Last);
_Guard._Target = nullptr;
return _Ret;
}

void swap(_Derived& _Other) noexcept(is_nothrow_swappable_v<_Container> && is_nothrow_swappable_v<_Keylt>) {
Expand Down Expand Up @@ -536,8 +539,6 @@ private:
return pair{_STD _Emplace_with_clear_guard(_Mycont, _Where, _STD forward<_Ty>(_Val)), true};
} else {
// heterogeneous insertion
// FIXME: The standard only requires `find(_Val) == find(_Keyval)` (per N4958 [flat.set.modifiers]/2),
// which cannot guarantee `_Can_insert(_Where, _Keyval)`.
_STL_INTERNAL_STATIC_ASSERT(_Transparent<key_compare> && is_constructible_v<_Kty, _Ty>);
_Kty _Keyval(_STD forward<_Ty>(_Val));
_STL_ASSERT(_Can_insert(_Where, _Keyval),
Expand Down Expand Up @@ -580,8 +581,6 @@ private:
return _STD _Emplace_with_clear_guard(_Mycont, _Where, _STD forward<_Ty>(_Val));
} else {
// heterogeneous insertion
// FIXME: The standard only requires `find(_Val) == find(_Keyval)` (per N4958 [flat.set.modifiers]/2),
// which cannot guarantee `_Can_insert(_Where, _Keyval)`.
_STL_INTERNAL_STATIC_ASSERT(_Transparent<key_compare> && is_constructible_v<_Kty, _Ty>);
_Kty _Keyval(_STD forward<_Ty>(_Val));
_STL_ASSERT(_Can_insert(_Where, _Keyval),
Expand Down Expand Up @@ -640,15 +639,19 @@ private:
if constexpr (_IsUnique && is_same_v<_Ty, key_type>) { // Optimization restricted due to GH-5992
const const_iterator _Where = lower_bound(_Val);
if (_Where != cend() && !_Compare(_Val, *_Where)) {
_Clear_guard _Guard{this};
_Mycont.erase(_Where);
_Guard._Target = nullptr;
return 1;
}
return 0;
} else {
const auto [_First, _Last] = equal_range(_Val);

const auto _Removed = static_cast<size_type>(_Last - _First);
_Clear_guard _Guard{this};
_Mycont.erase(_First, _Last);
_Guard._Target = nullptr;
return _Removed;
}
}
Expand Down Expand Up @@ -717,6 +720,9 @@ private:

void _Erase_dupes_if_not_multi() {
if constexpr (_IsUnique) {
// No _Clear_guard needed. The only callers are _Restore_invariants_after_insert() (which is called
// only by _Insert_range() which has a _Clear_guard) and _Make_invariants_fulfilled() (which is called
// only by constructors which don't need guards and operator=() which has a _Clear_guard).
const auto _End = _Mycont.end();
_Mycont.erase(_STD unique(_Mycont.begin(), _End, _Erase_dupes_if_not_multi_pred()), _End);
}
Expand Down
96 changes: 92 additions & 4 deletions tests/std/tests/P0429R9_flat_map/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <print>
#include <ranges>
#include <type_traits>
#include <utility>
#include <vector>

#include <test_container_requirements.hpp>
Expand Down Expand Up @@ -278,9 +279,36 @@ void test_construction() {
}
}
{
// Test flat_map(key_cont, mapped_cont, comp = key_comp())
// Test flat_map(const alloc&)
// and flat_map(const key_comp&, const alloc&)
{
MyAllocatorCounter allocation_counter;
flat_map<int, int> fmap(MyAllocator<int>{});
assert(!allocation_counter.check_then_reset());
flat_map<int, int> fmap1(less<int>{}, MyAllocator<int>{});
assert(!allocation_counter.check_then_reset());

assert(check_key_content(fmap, {}));
assert(check_value_content(fmap, {}));
assert(fmap == fmap1);
}
{
MyAllocatorCounter allocation_counter;
flat_multimap<int, int> fmmap(MyAllocator<int>{});
assert(!allocation_counter.check_then_reset());
flat_multimap<int, int> fmmap1(less<int>{}, MyAllocator<int>{});
assert(!allocation_counter.check_then_reset());

assert(check_key_content(fmmap, {}));
assert(check_value_content(fmmap, {}));
assert(fmmap == fmmap1);
}
}
{
KeyCont<int> keys = {0, 1, 2, 3, 4, 2};
MappedCont<int> vals = {44, 2324, 635462, 433, 5, 7};

// Test flat_map(key_cont, mapped_cont, comp = key_comp())
{
flat_map fmap(keys, vals);
flat_map fmap1(keys, vals, less<int>{});
Expand All @@ -302,12 +330,39 @@ void test_construction() {
}));
assert(fmmap == fmmap1);
}

// Test flat_map(const flat_map&)
// and flat_map(flat_map&&)
{
flat_map fmap(keys, vals);
flat_map fmap1(fmap);
flat_map fmap2(move(fmap));

assert(check_key_content(fmap1, {0, 1, 2, 3, 4}));
assert(check_value_content(fmap1, {44, 2324, 635462, 433, 5}));
assert(fmap1 == fmap2);
}
{
flat_multimap fmmap(keys, vals);
flat_multimap fmmap1(fmmap);
flat_multimap fmmap2(move(fmmap));

assert(check_key_content(fmmap1, {0, 1, 2, 2, 3, 4}));
assert(check_value_content(fmmap1, {44, 2324, 635462, 7, 433, 5},
{
{0, 1, subrange_type::equal},
{2, 3, subrange_type::permutation},
{4, 5, subrange_type::equal},
}));
assert(fmmap1 == fmmap2);
}
}
{
// Test flat_map(const key_cont&, const mapped_cont&, const key_comp&, const alloc&)
// and flat_map(const key_cont&, const mapped_cont&, const alloc&)
KeyCont<int, MyAllocator<int>> keys = {0, 1, 2, 3, 4, 2};
MappedCont<int, MyAllocator<int>> vals = {44, 2324, 635462, 433, 5, 7};

// Test flat_map(const key_cont&, const mapped_cont&, const key_comp&, const alloc&)
// and flat_map(const key_cont&, const mapped_cont&, const alloc&)
{
MyAllocatorCounter allocation_counter;
flat_map fmap(keys, vals, MyAllocator<int>{});
Expand Down Expand Up @@ -335,6 +390,40 @@ void test_construction() {
}));
assert(fmmap == fmmap1);
}

// Test flat_map(const flat_map&, const alloc&)
// and flat_map(flat_map&&, const alloc&)
{
MyAllocatorCounter allocation_counter;
flat_map fmap(keys, vals, MyAllocator<int>{});
assert(allocation_counter.check_then_reset());
flat_map fmap1(fmap);
assert(allocation_counter.check_then_reset());
flat_map fmap2(move(fmap));
assert(!allocation_counter.check_then_reset());

assert(check_key_content(fmap1, {0, 1, 2, 3, 4}));
assert(check_value_content(fmap1, {44, 2324, 635462, 433, 5}));
assert(fmap1 == fmap2);
}
{
MyAllocatorCounter allocation_counter;
flat_multimap fmmap(keys, vals, MyAllocator<int>{});
assert(allocation_counter.check_then_reset());
flat_multimap fmmap1(fmmap);
assert(allocation_counter.check_then_reset());
flat_multimap fmmap2(move(fmmap));
assert(!allocation_counter.check_then_reset());

assert(check_key_content(fmmap1, {0, 1, 2, 2, 3, 4}));
assert(check_value_content(fmmap1, {44, 2324, 635462, 7, 433, 5},
{
{0, 1, subrange_type::equal},
{2, 3, subrange_type::permutation},
{4, 5, subrange_type::equal},
}));
assert(fmmap1 == fmmap2);
}
}
{
// Test flat_map(_Sorted_t, key_cont, mapped_cont, comp = key_comp())
Expand Down Expand Up @@ -667,7 +756,6 @@ void test_construction() {
assert(fmmap == fmmap1);
}
}
// FIXME, verify that all flat_map and flat_multimap constructors are tested
{
PackagedCompare<int> comp;
{
Expand Down