Skip to content

Commit

Permalink
P2077R3 Heterogeneous Erasure Overloads (#2350)
Browse files Browse the repository at this point in the history
Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
  • Loading branch information
AlexGuteniev and StephanTLavavej authored Dec 17, 2021
1 parent f3ab9de commit 2ff8149
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 33 deletions.
67 changes: 50 additions & 17 deletions stl/inc/xhash
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ struct _Uhash_choose_transparency<_Kty, _Hasher, _Keyeq,
// transparency selector for transparent hashed containers
template <class _Keyty>
using _Deduce_key = const _Keyty&;

using _Transparent = void;
};
#endif // _HAS_CXX20

Expand Down Expand Up @@ -1063,24 +1065,14 @@ private:
return _Last;
}

public:
template <class _Iter = iterator, enable_if_t<!is_same_v<_Iter, const_iterator>, int> = 0>
iterator erase(iterator _Plist) noexcept(_Nothrow_hash<_Traits, key_type>) /* strengthened */ {
return _List._Make_iter(_Unchecked_erase(_Plist._Ptr));
template <class _Kx>
static constexpr bool _Noexcept_heterogeneous_erasure() {
return _Nothrow_hash<_Traits, _Kx> //
&& (!_Multi || (_Nothrow_compare<_Traits, key_type, _Kx> && _Nothrow_compare<_Traits, _Kx, key_type>) );
}

iterator erase(const_iterator _Plist) noexcept(_Nothrow_hash<_Traits, key_type>) /* strengthened */ {
return _List._Make_iter(_Unchecked_erase(_Plist._Ptr));
}

iterator erase(const_iterator _First, const_iterator _Last) noexcept(
_Nothrow_hash<_Traits, key_type>) /* strengthened */ {
return _List._Make_iter(_Unchecked_erase(_First._Ptr, _Last._Ptr));
}

size_type erase(const key_type& _Keyval) noexcept(
_Nothrow_hash<_Traits, key_type> //
&& (!_Multi || _Nothrow_compare<_Traits, key_type, key_type>) ) /* strengthened */ {
template <class _Keytype>
size_type _Erase(const _Keytype& _Keyval) noexcept(_Noexcept_heterogeneous_erasure<_Keytype>()) /* strengthened */ {
const size_t _Hashval = _Traitsobj(_Keyval);
if constexpr (_Multi) {
const auto _Where = _Equal_range(_Keyval, _Hashval);
Expand All @@ -1098,6 +1090,33 @@ public:
}
}

public:
template <class _Iter = iterator, enable_if_t<!is_same_v<_Iter, const_iterator>, int> = 0>
iterator erase(iterator _Plist) noexcept(_Nothrow_hash<_Traits, key_type>) /* strengthened */ {
return _List._Make_iter(_Unchecked_erase(_Plist._Ptr));
}

iterator erase(const_iterator _Plist) noexcept(_Nothrow_hash<_Traits, key_type>) /* strengthened */ {
return _List._Make_iter(_Unchecked_erase(_Plist._Ptr));
}

iterator erase(const_iterator _First, const_iterator _Last) noexcept(
_Nothrow_hash<_Traits, key_type>) /* strengthened */ {
return _List._Make_iter(_Unchecked_erase(_First._Ptr, _Last._Ptr));
}

size_type erase(const key_type& _Keyval) noexcept(noexcept(_Erase(_Keyval))) /* strengthened */ {
return _Erase(_Keyval);
}

#if _HAS_CXX23
template <class _Kx, class _Mytraits = _Traits, class = typename _Mytraits::_Transparent,
enable_if_t<!disjunction_v<is_convertible<_Kx, const_iterator>, is_convertible<_Kx, iterator>>, int> = 0>
size_type erase(_Kx&& _Keyval) noexcept(noexcept(_Erase(_Keyval))) /* strengthened */ {
return _Erase(_Keyval);
}
#endif // _HAS_CXX23

void clear() noexcept {
// TRANSITION, ABI:
// LWG-2550 requires implementations to make clear() O(size()), independent of bucket_count().
Expand Down Expand Up @@ -1330,6 +1349,19 @@ public:
return node_type::_Make(_Ptr, _List._Getal());
}

#if _HAS_CXX23
template <class _Kx, class _Mytraits = _Traits, class = typename _Mytraits::_Transparent,
enable_if_t<!disjunction_v<is_convertible<_Kx, const_iterator>, is_convertible<_Kx, iterator>>, int> = 0>
node_type extract(_Kx&& _Keyval) {
const auto _Ptr = _Extract(_Keyval);
if (!_Ptr) {
return node_type{};
}

return node_type::_Make(_Ptr, _List._Getal());
}
#endif // _HAS_CXX23

iterator insert(const_iterator _Hint, node_type&& _Handle) {
if (_Handle.empty()) {
return end();
Expand Down Expand Up @@ -1436,7 +1468,8 @@ protected:
return _List._Mypair._Myval2._Unlinknode(_Where._Ptr);
}

_Nodeptr _Extract(const key_type& _Keyval) {
template <class _Kx>
_Nodeptr _Extract(const _Kx& _Keyval) {
const size_t _Hashval = _Traitsobj(_Keyval);
_Nodeptr _Target;
if constexpr (_Traits::_Multi) {
Expand Down
36 changes: 30 additions & 6 deletions stl/inc/xtree
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,14 @@ private:
return _Last._Ptr;
}

size_type _Erase(const pair<_Nodeptr, _Nodeptr> _Where) noexcept {
const _Unchecked_const_iterator _First(_Where.first, nullptr);
const _Unchecked_const_iterator _Last(_Where.second, nullptr);
const auto _Num = static_cast<size_type>(_STD distance(_First, _Last));
_Erase_unchecked(_First, _Last);
return _Num;
}

public:
template <class _Iter = iterator, enable_if_t<!is_same_v<_Iter, const_iterator>, int> = 0>
iterator erase(iterator _Where) noexcept /* strengthened */ {
Expand All @@ -1321,13 +1329,16 @@ public:
}

size_type erase(const key_type& _Keyval) noexcept(noexcept(_Eqrange(_Keyval))) /* strengthened */ {
const auto _Where = _Eqrange(_Keyval);
const _Unchecked_const_iterator _First(_Where.first, nullptr);
const _Unchecked_const_iterator _Last(_Where.second, nullptr);
const auto _Num = static_cast<size_type>(_STD distance(_First, _Last));
_Erase_unchecked(_First, _Last);
return _Num;
return _Erase(_Eqrange(_Keyval));
}

#if _HAS_CXX23
template <class _Kx, class _Mycomp = key_compare, class = typename _Mycomp::is_transparent,
enable_if_t<!disjunction_v<is_convertible<_Kx, const_iterator>, is_convertible<_Kx, iterator>>, int> = 0>
size_type erase(_Kx&& _Keyval) noexcept(noexcept(_Eqrange(_Keyval))) /* strengthened */ {
return _Erase(_Eqrange(_Keyval));
}
#endif // _HAS_CXX23

void clear() noexcept {
const auto _Scary = _Get_scary();
Expand Down Expand Up @@ -1729,6 +1740,19 @@ public:
return extract(_Where);
}

#if _HAS_CXX23
template <class _Kx, class _Mycomp = key_compare, class = typename _Mycomp::is_transparent,
enable_if_t<!disjunction_v<is_convertible<_Kx, const_iterator>, is_convertible<_Kx, iterator>>, int> = 0>
node_type extract(_Kx&& _Keyval) {
const const_iterator _Where = find(_Keyval);
if (_Where == end()) {
return node_type{};
}

return extract(_Where);
}
#endif // _HAS_CXX23

auto insert(node_type&& _Handle) {
if (_Handle.empty()) {
if constexpr (_Multi) {
Expand Down
14 changes: 10 additions & 4 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@
// P1682R3 to_underlying() For Enumerations
// P1951R1 Default Template Arguments For pair's Forwarding Constructor
// P1989R2 Range Constructor For string_view
// P2077R3 Heterogeneous Erasure Overloads For Associative Containers
// P2136R3 invoke_r()
// P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr
// P2186R2 Removing Garbage Collection Support
Expand Down Expand Up @@ -1383,13 +1384,18 @@
#define __cpp_lib_allocate_at_least 202106L
#endif // __cpp_lib_concepts

#define __cpp_lib_byteswap 202110L
#define __cpp_lib_invoke_r 202106L
#define __cpp_lib_is_scoped_enum 202011L
#define __cpp_lib_associative_heterogeneous_erasure 202110L
#define __cpp_lib_byteswap 202110L
#define __cpp_lib_invoke_r 202106L
#define __cpp_lib_is_scoped_enum 202011L

#ifdef __cpp_lib_concepts
#define __cpp_lib_monadic_optional 202110L
#endif // __cpp_lib_concepts

#define __cpp_lib_move_only_function 202110L

#ifdef __cpp_lib_concepts
#define __cpp_lib_monadic_optional 202110L
#define __cpp_lib_out_ptr 202106L
#define __cpp_lib_ranges_starts_ends_with 202106L
#endif // __cpp_lib_concepts
Expand Down
98 changes: 98 additions & 0 deletions tests/std/tests/Dev11_0823534_transparent_lookup/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,4 +269,102 @@ int main() {
assert(ce.equal_range(8) == make_pair(next(ce.begin(), 9), next(ce.begin(), 11)));
assert(ce.equal_range(9) == make_pair(next(ce.begin(), 11), next(ce.begin(), 11)));
}

#if _HAS_CXX23
{
multiset<string, Ke> e(begin(arr), end(arr));
set<string, Ke> f(begin(arr), end(arr));
multimap<string, int, Ke> g{{"ape", 0}, {"bat", 1}, {"cat", 2}, {"bear", 3}, {"wolf", 4}, {"raven", 5},
{"giraffe", 6}, {"panther", 7}, {"unicorn", 8}, {"direwolf", 9}, {"elephant", 10}};
map<string, int, Ke> h{{"ape", 0}, {"bat", 1}, {"cat", 2}, {"bear", 3}, {"wolf", 4}, {"raven", 5},
{"giraffe", 6}, {"panther", 7}, {"unicorn", 8}, {"direwolf", 9}, {"elephant", 10}};

assert(e.erase(2) == 0);
assert(e.erase(3) == 3);
assert(e.erase(4) == 2);
assert(e.erase(5) == 1);
assert(e.erase(6) == 0);
assert(e.erase(7) == 3);
assert(e.erase(8) == 2);
assert(e.erase(9) == 0);
assert(e.empty());

assert(f.erase(2) == 0);
assert(f.erase(3) == 3);
assert(f.erase(4) == 2);
assert(f.erase(5) == 1);
assert(f.erase(6) == 0);
assert(f.erase(7) == 3);
assert(f.erase(8) == 2);
assert(f.erase(9) == 0);
assert(f.empty());

assert(g.erase(2) == 0);
assert(g.erase(3) == 3);
assert(g.erase(4) == 2);
assert(g.erase(5) == 1);
assert(g.erase(6) == 0);
assert(g.erase(7) == 3);
assert(g.erase(8) == 2);
assert(g.erase(9) == 0);
assert(g.empty());

assert(h.erase(2) == 0);
assert(h.erase(3) == 3);
assert(h.erase(4) == 2);
assert(h.erase(5) == 1);
assert(h.erase(6) == 0);
assert(h.erase(7) == 3);
assert(h.erase(8) == 2);
assert(h.erase(9) == 0);
assert(h.empty());
}

{
multiset<string, Ke> i(begin(arr), end(arr));
set<string, Ke> j(begin(arr), end(arr));
multimap<string, int, Ke> k{{"ape", 0}, {"bat", 1}, {"cat", 2}, {"bear", 3}, {"wolf", 4}, {"raven", 5},
{"giraffe", 6}, {"panther", 7}, {"unicorn", 8}, {"direwolf", 9}, {"elephant", 10}};
map<string, int, Ke> l{{"ape", 0}, {"bat", 1}, {"cat", 2}, {"bear", 3}, {"wolf", 4}, {"raven", 5},
{"giraffe", 6}, {"panther", 7}, {"unicorn", 8}, {"direwolf", 9}, {"elephant", 10}};

auto test_extract = []<typename C>(C& c) {
auto n2 = c.extract(2);
auto n3 = c.extract(3);
auto n4 = c.extract(4);
auto n5 = c.extract(5);
auto n6 = c.extract(6);
auto n7 = c.extract(7);
auto n8 = c.extract(8);
auto n9 = c.extract(9);

assert(!n2);
assert(n3);
assert(n4);
assert(n5);
assert(!n6);
assert(n7);
assert(n8);
assert(!n9);

C d;

d.insert(move(n2));
d.insert(move(n3));
d.insert(move(n4));
d.insert(move(n5));
d.insert(move(n6));
d.insert(move(n7));
d.insert(move(n8));
d.insert(move(n9));

assert(c.size() == 6);
assert(d.size() == 5);
};
test_extract(i);
test_extract(j);
test_extract(k);
test_extract(l);
}
#endif // _HAS_CXX23
}
Loading

0 comments on commit 2ff8149

Please sign in to comment.