diff --git a/stl/inc/flat_map b/stl/inc/flat_map index facdd5474e5..c73b25e9e1b 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -29,11 +29,11 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN -template - requires same_as<_FlatMap_Key, typename _FlatMap_KeyContainer::value_type> - && same_as<_FlatMap_T, typename _FlatMap_MappedContainer::value_type> -class _Flat_Map_Base; +template + requires same_as<_Key, typename _KeyContainer::value_type> + && same_as<_Mapped, typename _MappedContainer::value_type> +class _Flat_map_base; template , class _KeyContainer = vector<_Key>, class _MappedContainer = vector<_Mapped>> @@ -54,33 +54,33 @@ struct sorted_equivalent_t { inline constexpr sorted_equivalent_t sorted_equivalent{}; template -concept _Valid_Allocator_for_flat_map = +concept _Valid_allocator_for_flat_map = uses_allocator_v<_Key_container, _Alloc> && uses_allocator_v<_Mapped_container, _Alloc>; template -concept _Valid_Compare_for_container = is_invocable_v; -template -struct _Flat_value_compare { +template +struct _Flat_map_value_compare_provider { struct value_compare { public: - bool operator()(pair _X, pair _Y) const { - return _Key_compare_for_val(_X.first, _Y.first); + bool operator()(pair _Left, pair _Right) const { + return _Key_comparator(_Left.first, _Right.first); } - value_compare(_Key_compare _Comp) : _Key_compare_for_val(_Comp) {} + value_compare(_KeyCompare _Comp) : _Key_comparator(_Comp) {} private: - _Key_compare _Key_compare_for_val; + _KeyCompare _Key_comparator; }; }; -template -struct _Flat_Container { - struct container { - _Key_container keys; - _Mapped_container values; +template +struct _Flat_map_container_provider { + struct containers { + _KeyContainer keys; + _MappedContainer values; }; }; @@ -98,36 +98,29 @@ struct _NODISCARD _Clear_flat_map_scope_guard { // Implementation -enum class _Paring_iterator_kind : unsigned char { - _Sort, - _Mutable, - _Const, -}; - -template -struct _Paring_iterator_provider { - using _Key_iterator_t = conditional_t<_Kind == _Paring_iterator_kind::_Sort, typename _KeyContainer::iterator, - typename _KeyContainer::const_iterator>; - using _Mapped_iterator_t = conditional_t<_Kind == _Paring_iterator_kind::_Const, - typename _MappedContainer::const_iterator, typename _MappedContainer::iterator>; - +template +struct _Pairing_iterator_provider { class _Iterator { public: - template - requires same_as<_FlatMap_Key, typename _FlatMap_KeyContainer::value_type> - && same_as<_FlatMap_T, typename _FlatMap_MappedContainer::value_type> - friend class _Flat_Map_Base; + template + requires same_as<_Key, typename _KeyContainer::value_type> + && same_as<_Mapped, typename _MappedContainer::value_type> + friend class _Flat_map_base; + _Iterator() = default; - _Iterator(_Key_iterator_t _Key_it, _Mapped_iterator_t _Mapped_it) : _Key_it(_Key_it), _Mapped_it(_Mapped_it) {} + _Iterator(_KeyIter _Key_iter, _MappedIter _Mapped_iter) : _Key_it(_Key_iter), _Mapped_it(_Mapped_iter) {} using iterator_category = input_iterator_tag; using iterator_concept = random_access_iterator_tag; using difference_type = ptrdiff_t; - using value_type = pair, iter_value_t<_Mapped_iterator_t>>; - using reference = pair, iter_reference_t<_Mapped_iterator_t>>; + using value_type = pair, iter_value_t<_MappedIter>>; + using reference = pair, iter_reference_t<_MappedIter>>; private: + using _Const_iterator = + typename _Pairing_iterator_provider<_KeyIter, _MappedConvIter, _MappedConvIter>::_Iterator; + class _Arrow_proxy { public: explicit _Arrow_proxy(const reference& _Rx) noexcept : _Ref{_Rx} {} @@ -219,218 +212,218 @@ struct _Paring_iterator_provider { return _Right + _Off; } - operator typename _Paring_iterator_provider<_KeyContainer, _MappedContainer, - _Paring_iterator_kind::_Const>::_Iterator() const - requires (_Kind == _Paring_iterator_kind::_Mutable) + operator _Const_iterator() const + requires (!is_same_v<_MappedIter, _MappedConvIter>) { - return typename _Paring_iterator_provider<_KeyContainer, _MappedContainer, - _Paring_iterator_kind::_Const>::_Iterator{_Key_it, _Mapped_it}; + return _Const_iterator{_Key_it, _Mapped_it}; } private: - _Key_iterator_t _Key_it; - _Mapped_iterator_t _Mapped_it; + _KeyIter _Key_it; + _MappedIter _Mapped_it; }; _STL_INTERNAL_STATIC_ASSERT(swappable<_Iterator>); }; _EXPORT_STD -template - requires same_as<_FlatMap_Key, typename _FlatMap_KeyContainer::value_type> - && same_as<_FlatMap_T, typename _FlatMap_MappedContainer::value_type> -class _Flat_Map_Base { +template + requires same_as<_Key, typename _KeyContainer::value_type> + && same_as<_Mapped, typename _MappedContainer::value_type> +class _Flat_map_base { private: - using _Sorted_t = conditional_t<_Is_Multi, sorted_equivalent_t, sorted_unique_t>; + using _Sorted_t = conditional_t<_IsMulti, sorted_equivalent_t, sorted_unique_t>; public: - using key_type = _FlatMap_Key; - using mapped_type = _FlatMap_T; - using value_type = pair; - using key_compare = _FlatMap_Compare; - using reference = pair; - using const_reference = pair; - using size_type = size_t; - using difference_type = ptrdiff_t; - using key_container_type = _FlatMap_KeyContainer; - using mapped_container_type = _FlatMap_MappedContainer; - using iterator = _Paring_iterator_provider::_Iterator; - using const_iterator = - _Paring_iterator_provider::_Iterator; + using key_type = _Key; + using mapped_type = _Mapped; + using value_type = pair; + using key_compare = _Compare; + using reference = pair; + using const_reference = pair; + using size_type = size_t; + using difference_type = ptrdiff_t; + using key_container_type = _KeyContainer; + using mapped_container_type = _MappedContainer; + using iterator = _Pairing_iterator_provider::_Iterator; + using const_iterator = _Pairing_iterator_provider::_Iterator; using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; _STL_INTERNAL_STATIC_ASSERT(random_access_iterator); _STL_INTERNAL_STATIC_ASSERT(convertible_to); - using value_compare = _Flat_value_compare::value_compare; - using containers = _Flat_Container::container; + using value_compare = _Flat_map_value_compare_provider::value_compare; + using containers = _Flat_map_container_provider::containers; public: // [flat.map.cons] Constructors - explicit _Flat_Map_Base(const key_compare& _Comp) : _Key_compare(_Comp), _Data() {} - _Flat_Map_Base() : _Flat_Map_Base(key_compare()) {} + explicit _Flat_map_base(const key_compare& _Comp) : _Key_compare(_Comp), _Data() {} + _Flat_map_base() : _Flat_map_base(key_compare()) {} - template <_Valid_Allocator_for_flat_map Allocator> - explicit _Flat_Map_Base(const Allocator& _Alloc) : _Flat_Map_Base(key_compare(), _Alloc) {} + template <_Valid_allocator_for_flat_map _Allocator> + explicit _Flat_map_base(const _Allocator& _Alloc) : _Flat_map_base(key_compare(), _Alloc) {} - template <_Valid_Allocator_for_flat_map Allocator> - explicit _Flat_Map_Base(const key_compare& _Comp, const Allocator& _Alloc) + template <_Valid_allocator_for_flat_map _Allocator> + explicit _Flat_map_base(const key_compare& _Comp, const _Allocator& _Alloc) : _Key_compare(_Comp), _Data{.keys = _STD make_obj_using_allocator(_Alloc), .values = _STD make_obj_using_allocator(_Alloc)} {} - _Flat_Map_Base( + _Flat_map_base( key_container_type _Key_cont, mapped_container_type _Mapped_cont, const key_compare& _Comp = key_compare()) - : _Flat_Map_Base(_Sorted_t(), _Key_cont, _Mapped_cont, _Comp) { + : _Flat_map_base(_Sorted_t(), _Key_cont, _Mapped_cont, _Comp) { _Sort(); - if constexpr (!_Is_Multi) { + if constexpr (!_IsMulti) { _Dedup(); } } - template <_Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base( - const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, const Allocator& _Alloc) - : _Flat_Map_Base(_Sorted_t(), _Key_cont, _Mapped_cont, _Alloc) { + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base( + const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, const _Allocator& _Alloc) + : _Flat_map_base(_Sorted_t(), _Key_cont, _Mapped_cont, _Alloc) { _Sort(); - if constexpr (!_Is_Multi) { + if constexpr (!_IsMulti) { _Dedup(); } } - template <_Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base(const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, - const key_compare& _Comp, const Allocator& _Alloc) - : _Flat_Map_Base(_Sorted_t(), _Key_cont, _Mapped_cont, _Comp, _Alloc) { + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, + const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Sorted_t(), _Key_cont, _Mapped_cont, _Comp, _Alloc) { _Sort(); - if constexpr (!_Is_Multi) { + if constexpr (!_IsMulti) { _Dedup(); } } - _Flat_Map_Base(_Sorted_t, key_container_type _Key_cont, mapped_container_type _Mapped_cont, + _Flat_map_base(_Sorted_t, key_container_type _Key_cont, mapped_container_type _Mapped_cont, const key_compare& _Comp = key_compare()) : _Key_compare(_Comp), _Data{.keys = _STD move(_Key_cont), .values = _STD move(_Mapped_cont)} {} - template <_Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base(_Sorted_t, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, - const Allocator& _Alloc) + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(_Sorted_t, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, + const _Allocator& _Alloc) : _Key_compare(key_compare()), _Data{.keys = _STD make_obj_using_allocator(_Alloc, _Key_cont), .values = _STD make_obj_using_allocator(_Alloc, _Mapped_cont)} {} - template <_Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base(_Sorted_t, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, - const key_compare& _Comp, const Allocator& _Alloc) + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(_Sorted_t, const key_container_type& _Key_cont, const mapped_container_type& _Mapped_cont, + const key_compare& _Comp, const _Allocator& _Alloc) : _Key_compare(_Comp), _Data{.keys = _STD make_obj_using_allocator(_Alloc, _Key_cont), .values = _STD make_obj_using_allocator(_Alloc, _Mapped_cont)} {} template requires _Is_iterator_v<_InputIterator> - _Flat_Map_Base(_InputIterator _First, _InputIterator _Last, const key_compare& _Comp = key_compare()) - : _Flat_Map_Base(_Comp) { + _Flat_map_base(_InputIterator _First, _InputIterator _Last, const key_compare& _Comp = key_compare()) + : _Flat_map_base(_Comp) { insert(_First, _Last); } - template Allocator> + template _Allocator> requires _Is_iterator_v<_InputIterator> - _Flat_Map_Base(_InputIterator _First, _InputIterator _Last, const key_compare& _Comp, const Allocator& _Alloc) - : _Flat_Map_Base(_Comp, _Alloc) { + _Flat_map_base(_InputIterator _First, _InputIterator _Last, const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Comp, _Alloc) { insert(_First, _Last); } - template <_Container_compatible_range R> - _Flat_Map_Base(from_range_t _From_range, R&& _Range) - : _Flat_Map_Base(_From_range, _STD forward(_Range), key_compare()) {} + template <_Container_compatible_range _Rng> + _Flat_map_base(from_range_t _From_range, _Rng&& _Range) + : _Flat_map_base(_From_range, _STD forward<_Rng>(_Range), key_compare()) {} - template <_Container_compatible_range R, - _Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base(from_range_t _From_range, R&& _Range, const Allocator& _Alloc) - : _Flat_Map_Base(_From_range, _STD forward(_Range), key_compare(), _Alloc) {} + template <_Container_compatible_range _Rng, + _Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(from_range_t _From_range, _Rng&& _Range, const _Allocator& _Alloc) + : _Flat_map_base(_From_range, _STD forward<_Rng>(_Range), key_compare(), _Alloc) {} - template <_Container_compatible_range R> - _Flat_Map_Base(from_range_t, R&& _Range, const key_compare& _Comp) : _Flat_Map_Base(_Comp) { - insert_range(_STD forward(_Range)); + template <_Container_compatible_range _Rng> + _Flat_map_base(from_range_t, _Rng&& _Range, const key_compare& _Comp) : _Flat_map_base(_Comp) { + insert_range(_STD forward<_Rng>(_Range)); } - template <_Container_compatible_range R, - _Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base(from_range_t, R&& _Range, const key_compare& _Comp, const Allocator& _Alloc) - : _Flat_Map_Base(_Comp, _Alloc) { - insert_range(_STD forward(_Range)); + template <_Container_compatible_range _Rng, + _Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(from_range_t, _Rng&& _Range, const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Comp, _Alloc) { + insert_range(_STD forward<_Rng>(_Range)); } template requires _Is_iterator_v<_InputIterator> - _Flat_Map_Base(_Sorted_t _S, _InputIterator _First, _InputIterator _Last, const key_compare& _Comp = key_compare()) - : _Flat_Map_Base(_Comp) { - insert(_S, _First, _Last); + _Flat_map_base( + _Sorted_t _Tag, _InputIterator _First, _InputIterator _Last, const key_compare& _Comp = key_compare()) + : _Flat_map_base(_Comp) { + insert(_Tag, _First, _Last); } - template Allocator> + template _Allocator> requires _Is_iterator_v<_InputIterator> - _Flat_Map_Base( - _Sorted_t _S, _InputIterator _First, _InputIterator _Last, const key_compare& _Comp, const Allocator& _Alloc) - : _Flat_Map_Base(_Comp, _Alloc) { - insert(_S, _First, _Last); + _Flat_map_base( + _Sorted_t _Tag, _InputIterator _First, _InputIterator _Last, const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Comp, _Alloc) { + insert(_Tag, _First, _Last); } - template Allocator> + template _Allocator> requires _Is_iterator_v<_InputIterator> - _Flat_Map_Base(_Sorted_t _S, _InputIterator _First, _InputIterator _Last, const Allocator& _Alloc) - : _Flat_Map_Base(_S, _First, _Last, key_compare(), _Alloc) {} + _Flat_map_base(_Sorted_t _Tag, _InputIterator _First, _InputIterator _Last, const _Allocator& _Alloc) + : _Flat_map_base(_Tag, _First, _Last, key_compare(), _Alloc) {} - _Flat_Map_Base(initializer_list _I, const key_compare& _Comp = key_compare()) - : _Flat_Map_Base(_I.begin(), _I.end(), _Comp) {} + _Flat_map_base(initializer_list _Ilist, const key_compare& _Comp = key_compare()) + : _Flat_map_base(_Ilist.begin(), _Ilist.end(), _Comp) {} - template <_Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base(initializer_list _I, const key_compare& _Comp, const Allocator& _Alloc) - : _Flat_Map_Base(_I.begin(), _I.end(), _Comp, _Alloc) {} + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Ilist.begin(), _Ilist.end(), _Comp, _Alloc) {} - template <_Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base(initializer_list _I, const Allocator& _Alloc) - : _Flat_Map_Base(_I, key_compare(), _Alloc) {} + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(initializer_list _Ilist, const _Allocator& _Alloc) + : _Flat_map_base(_Ilist, key_compare(), _Alloc) {} - _Flat_Map_Base(_Sorted_t _S, initializer_list _I, const key_compare& _Comp = key_compare()) - : _Flat_Map_Base(_S, _I.begin(), _I.end(), _Comp) {} + _Flat_map_base(_Sorted_t _Tag, initializer_list _Ilist, const key_compare& _Comp = key_compare()) + : _Flat_map_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp) {} - template <_Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base(_Sorted_t _S, initializer_list _I, const key_compare& _Comp, const Allocator& _Alloc) - : _Flat_Map_Base(_S, _I.begin(), _I.end(), _Comp, _Alloc) {} + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base( + _Sorted_t _Tag, initializer_list _Ilist, const key_compare& _Comp, const _Allocator& _Alloc) + : _Flat_map_base(_Tag, _Ilist.begin(), _Ilist.end(), _Comp, _Alloc) {} - template <_Valid_Allocator_for_flat_map Allocator> - _Flat_Map_Base(_Sorted_t _S, initializer_list _I, const Allocator& _Alloc) - : _Flat_Map_Base(_S, _I, key_compare(), _Alloc) {} + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(_Sorted_t _Tag, initializer_list _Ilist, const _Allocator& _Alloc) + : _Flat_map_base(_Tag, _Ilist, key_compare(), _Alloc) {} // Copy constructors - _Flat_Map_Base(const _Derived& _Other) : _Key_compare(_Other._Key_compare), _Data(_Other._Data) {} + _Flat_map_base(const _Derived& _Other) : _Key_compare(_Other._Key_compare), _Data(_Other._Data) {} - template <_Valid_Allocator_for_flat_map _Allocator> - _Flat_Map_Base(const _Derived& _Other, const _Allocator& _Alloc) + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(const _Derived& _Other, const _Allocator& _Alloc) : _Key_compare(_Other._Key_compare), _Data{.keys = _STD make_obj_using_allocator(_Alloc, _Other._Data.keys), .values = _STD make_obj_using_allocator(_Alloc, _Other._Data.values)} {} // Move constructors - _Flat_Map_Base(_Derived&& _Other) noexcept(is_nothrow_move_constructible_v + _Flat_map_base(_Derived&& _Other) noexcept(is_nothrow_move_constructible_v && is_nothrow_move_constructible_v && is_nothrow_move_constructible_v) : _Key_compare(move(_Other._Key_compare)), _Data(move(_Other).extract()) {} - template <_Valid_Allocator_for_flat_map _Allocator> - _Flat_Map_Base(_Derived&& _Other, const _Allocator& _Alloc) noexcept( + template <_Valid_allocator_for_flat_map _Allocator> + _Flat_map_base(_Derived&& _Other, const _Allocator& _Alloc) noexcept( is_nothrow_move_constructible_v && is_nothrow_move_constructible_v && is_nothrow_move_constructible_v) : _Key_compare(move(_Other._Key_compare)), _Data{.keys = _STD make_obj_using_allocator(_Alloc, move(_Other._Data.keys)), .values = _STD make_obj_using_allocator(_Alloc, move(_Other._Data.values))} {} - _Derived& operator=(initializer_list _I) { + _Derived& operator=(initializer_list _Ilist) { clear(); - insert(_I.begin(), _I.end()); + insert(_Ilist.begin(), _Ilist.end()); return static_cast<_Derived&>(*this); // Use "deducing this" when it is supported } @@ -508,138 +501,52 @@ public: return _STD min(_Data.keys.max_size(), _Data.values.max_size()); } - // [flat.map.access] Access - template - _NODISCARD mapped_type& operator[](_K&& _Key_val) - requires same_as, key_type> - || (_Is_transparent_v && constructible_from) + template + iterator emplace_hint(const_iterator _Position, _ArgTypes&&... _Args) + requires is_constructible_v { - return try_emplace(_STD forward<_K>(_Key_val)).first->second; + value_type _Val(_STD forward<_ArgTypes>(_Args)...); + return _Emplace_hint(_Position, _STD move(_Val.first), _STD move(_Val.second)); } - _NODISCARD mapped_type& at(const key_type& _Key_val) { - return _At(_Key_val); + iterator insert(const_iterator _Position, const value_type& _Pair_val) { + return emplace_hint(_Position, _Pair_val); } - template - _NODISCARD const mapped_type& at(const _K& _Key_val) const - requires _Is_transparent_v - { - return _At(_Key_val); + iterator insert(const_iterator _Position, value_type&& _Pair_val) { + return emplace_hint(_Position, _STD move(_Pair_val)); } - // [flat.map.modifiers] Modifiers - template - pair emplace(_Args_t&&... _Args) - requires is_constructible_v + template + iterator insert(const_iterator _Position, _PairValTy&& _Pair_val) + requires is_constructible_v { - value_type _Val(_STD forward<_Args_t>(_Args)...); - return try_emplace(_STD move(_Val.first), _STD move(_Val.second)); - } - - template - iterator emplace_hint(const_iterator _Position, _Args_t&&... _Args) - requires is_constructible_v - { - value_type _Val(_STD forward<_Args_t>(_Args)...); - - return _Emplace_hint(_Position, _STD move(_Val.first), _STD move(_Val.second)); - } - - template - pair insert(_V&& _X) - requires (same_as, value_type> || constructible_from) - { - return emplace(_STD forward<_V>(_X)); - } - - template - iterator insert(const_iterator _Position, _V&& _X) - requires (same_as, value_type> || constructible_from) - { - return emplace_hint(_Position, _STD forward<_V>(_X)); + return emplace_hint(_Position, _STD forward<_PairValTy>(_Pair_val)); } template requires _Is_iterator_v<_InputIterator> void insert(_InputIterator _First, _InputIterator _Last) { - _Insert_range(_First, _Last); + _Insert_range(_First, _Last); } template requires _Is_iterator_v<_InputIterator> void insert(_Sorted_t, _InputIterator _First, _InputIterator _Last) { - _Insert_range(_First, _Last); + _Insert_range(_First, _Last); } - template <_Container_compatible_range R> - void insert_range(R&& _Range) { + template <_Container_compatible_range _Rng> + void insert_range(_Rng&& _Range) { insert(_RANGES begin(_Range), _RANGES end(_Range)); } - void insert(initializer_list _I) { - insert(_I.begin(), _I.end()); - } - - void insert(_Sorted_t _S, initializer_list _I) { - insert(_S, _I.begin(), _I.end()); - } - - template - pair try_emplace(_Key_constructible_t&& _Key_constructible, _Args_t&&... _Args) - requires constructible_from - && (same_as, key_type> - || (constructible_from && _Is_transparent_v - && !convertible_to<_Key_constructible_t &&, const_iterator> - && !convertible_to<_Key_constructible_t &&, iterator>) ) - { - auto _Key_It = _STD lower_bound(_Data.keys.begin(), _Data.keys.end(), _Key_constructible, _Key_compare); - if (_Key_It != _Data.keys.end() - && _Key_equal(*_Key_It, _STD forward<_Key_constructible_t>(_Key_constructible))) { - // Already exists - return {begin() + _STD distance(_Data.keys.begin(), _Key_It), false}; - } else { - // Need to insert - auto _Index = _STD distance(_Data.keys.begin(), _Key_It); - _Insert_exact(cbegin() + _Index, key_type{_STD forward<_Key_constructible_t>(_Key_constructible)}, - mapped_type{_STD forward<_Args_t>(_Args)...}); - return {begin() + _Index, true}; - } - } - - template - iterator try_emplace(const_iterator _Position, _K&& _Key_val, _Args_t&&... _Args) - requires constructible_from - && (same_as, key_type> - || (constructible_from && _Is_transparent_v) ) - { - return _Emplace_hint(_Position, _STD forward<_K>(_Key_val), _STD forward<_Args_t>(_Args)...); + void insert(initializer_list _Ilist) { + insert(_Ilist.begin(), _Ilist.end()); } - template - pair insert_or_assign(_K&& _Key_val, _M&& _Obj) - requires assignable_from && constructible_from - && (same_as, key_type> - || (constructible_from && _Is_transparent_v) ) - { - auto _Res = try_emplace(_STD forward<_K>(_Key_val), _STD forward<_M>(_Obj)); - if (_Res.second) { - // Insertion took place - return _Res; - } else { - // Already exists - *(_Res.first._Mapped_it) = _STD forward<_M>(_Obj); - return _Res; - } - } - - template - iterator insert_or_assign(const_iterator _Position, _K&& _Key_val, _M&& _Obj) - requires assignable_from && constructible_from - && (same_as, key_type> - || (constructible_from && _Is_transparent_v) ) - { - return _Emplace_hint(_Position, _STD forward<_K>(_Key_val), _STD forward<_M>(_Obj)); + void insert(_Sorted_t _Tag, initializer_list _Ilist) { + insert(_Tag, _Ilist.begin(), _Ilist.end()); } iterator erase(iterator _Position) { @@ -662,17 +569,15 @@ public: return iterator{_STD move(_Key_it), _STD move(_Val_it)}; } - template - size_type erase(_K&& _Key_val) - requires convertible_to<_K&&, const key_type&> - || (_Is_transparent_v && !convertible_to<_K &&, iterator> - && !convertible_to<_K &&, const_iterator>) - { - const_iterator _Pos_begin = lower_bound(_STD forward<_K>(_Key_val)); - const_iterator _Pos_end = upper_bound(_STD forward<_K>(_Key_val)); - size_type _Count = _Pos_end - _Pos_begin; - erase(_Pos_begin, _Pos_end); - return _Count; + size_type erase(const key_type& _Key_val) { + return _Erase_key(_Key_val); + } + + template + requires _Is_transparent_v + && (!is_convertible_v<_OtherKey, iterator>) && (!is_convertible_v<_OtherKey, const_iterator>) + size_type erase(_OtherKey&& _Key_val) { + return _Erase_key(_STD forward<_OtherKey>(_Key_val)); } containers extract() && { @@ -705,188 +610,209 @@ public: } // map operations - iterator find(const key_type& _X) { - return _Find(_X); + iterator find(const key_type& _Key_val) { + return _Find(_Key_val); } - template - iterator find(const _K& _X) + template + iterator find(const _OtherKey& _Key_val) requires _Is_transparent_v { - return _Find(_X); + return _Find(_Key_val); } - const_iterator find(const key_type& _X) const { - return _Find(_X); + const_iterator find(const key_type& _Key_val) const { + return _Find(_Key_val); } - template - const_iterator find(const _K& _X) const + template + const_iterator find(const _OtherKey& _Key_val) const requires _Is_transparent_v { - return _Find(_X); + return _Find(_Key_val); } - size_type count(const key_type& _X) const { - return _Count(_X); + size_type count(const key_type& _Key_val) const { + return _Count(_Key_val); } - template - size_type count(const _K& _X) const + template + size_type count(const _OtherKey& _Key_val) const requires _Is_transparent_v { - return _Count(_X); + return _Count(_Key_val); } - bool contains(const key_type& _X) const { - return _Contains(_X); + bool contains(const key_type& _Key_val) const { + return _Contains(_Key_val); } - template - bool contains(const _K& _X) const + template + bool contains(const _OtherKey& _Key_val) const requires _Is_transparent_v { - return _Contains(_X); + return _Contains(_Key_val); } - iterator lower_bound(const key_type& _X) { - return _Lower_bound(_X); + iterator lower_bound(const key_type& _Key_val) { + return _Lower_bound(_Key_val); } - template - iterator lower_bound(const _K& _X) + template + iterator lower_bound(const _OtherKey& _Key_val) requires _Is_transparent_v { - return _Lower_bound(_X); + return _Lower_bound(_Key_val); } - const_iterator lower_bound(const key_type& _X) const { - return _Lower_bound(_X); + const_iterator lower_bound(const key_type& _Key_val) const { + return _Lower_bound(_Key_val); } - template - const_iterator lower_bound(const _K& _X) const + template + const_iterator lower_bound(const _OtherKey& _Key_val) const requires _Is_transparent_v { - return _Lower_bound(_X); + return _Lower_bound(_Key_val); } - iterator upper_bound(const key_type& _X) { - return _Upper_bound(_X); + iterator upper_bound(const key_type& _Key_val) { + return _Upper_bound(_Key_val); } - template - iterator upper_bound(const _K& _X) + template + iterator upper_bound(const _OtherKey& _Key_val) requires _Is_transparent_v { - return _Upper_bound(_X); + return _Upper_bound(_Key_val); } - const_iterator upper_bound(const key_type& _X) const { - return _Upper_bound(_X); + const_iterator upper_bound(const key_type& _Key_val) const { + return _Upper_bound(_Key_val); } - template - const_iterator upper_bound(const _K& _X) const + template + const_iterator upper_bound(const _OtherKey& _Key_val) const requires _Is_transparent_v { - return _Upper_bound(_X); + return _Upper_bound(_Key_val); } - pair equal_range(const key_type& _X) { - return _Equal_range(_X); + pair equal_range(const key_type& _Key_val) { + return _Equal_range(_Key_val); } - template - pair equal_range(const _K& _X) + template + pair equal_range(const _OtherKey& _Key_val) requires _Is_transparent_v { - return _Equal_range(_X); + return _Equal_range(_Key_val); } - pair equal_range(const key_type& _X) const { - return _Equal_range(_X); + pair equal_range(const key_type& _Key_val) const { + return _Equal_range(_Key_val); } - template - pair equal_range(const _K& _X) const + template + pair equal_range(const _OtherKey& _Key_val) const requires _Is_transparent_v { - return _Equal_range(_X); + return _Equal_range(_Key_val); } - friend bool operator==(const _Derived& _X, const _Derived& _Y) { - return _RANGES equal(_X._Data.keys, _Y._Data.keys) && _RANGES equal(_X._Data.values, _Y._Data.values); + friend bool operator==(const _Derived& _Left, const _Derived& _Right) { + return _RANGES equal(_Left._Data.keys, _Right._Data.keys) + && _RANGES equal(_Left._Data.values, _Right._Data.values); } - friend auto operator<=>(const _Derived& _X, const _Derived& _Y) { + friend auto operator<=>(const _Derived& _Left, const _Derived& _Right) { return _STD lexicographical_compare_three_way( - _X.cbegin(), _X.cend(), _Y.cbegin(), _Y.cend(), _Synth_three_way{}); + _Left.cbegin(), _Left.cend(), _Right.cbegin(), _Right.cend(), _Synth_three_way{}); } - friend void swap(_Derived& _X, _Derived& _Y) noexcept { - _X.swap(_Y); + friend void swap(_Derived& _Left, _Derived& _Right) noexcept { + _Left.swap(_Right); } -private: +protected: key_compare _Key_compare; containers _Data; - template - requires (same_as, key_type> && same_as, key_type>) - || (constructible_from && constructible_from + template + size_type _Erase_if(_Predicate _Pred) { + _Clear_flat_map_scope_guard<_Flat_map_base> _Guard{this}; + + auto _View = _View_to_mutate(); + auto _Mut_first = _View.begin(); + auto _Mut_last = _View.end(); + const auto _Old_size = size(); + + _STD _Seek_wrapped(_Mut_first, _RANGES remove_if(_View, _Pred).begin()); + + erase(const_iterator{_Mut_first._Key_it, _Mut_first._Mapped_it}, + const_iterator{_Mut_last._Key_it, _Mut_last._Mapped_it}); + + _Guard._Clearable = nullptr; + return _Old_size - size(); + } + +private: + template + requires (same_as, key_type> && same_as, key_type>) + || (constructible_from && constructible_from && _Is_transparent_v) - bool _Key_equal(_K1&& _X, _K2&& _Y) const { - return !_Key_compare(_STD forward<_K1>(_X), _STD forward<_K2>(_Y)) - && !_Key_compare(_STD forward<_K2>(_Y), _STD forward<_K1>(_X)); + bool _Key_equal(_KeyTy1&& _Left, _KeyTy2&& _Right) const { + return !_Key_compare(_STD forward<_KeyTy1>(_Left), _STD forward<_KeyTy2>(_Right)) + && !_Key_compare(_STD forward<_KeyTy2>(_Right), _STD forward<_KeyTy1>(_Left)); } - auto _View_to_sort() { - using _Sorting_iterator = _Paring_iterator_provider::_Iterator; - return _RANGES subrange<_Sorting_iterator>{_Sorting_iterator{_Data.keys.begin(), _Data.values.begin()}, - _Sorting_iterator{_Data.keys.end(), _Data.values.end()}}; + auto _View_to_mutate() { + using _Mutating_iterator = _Pairing_iterator_provider::_Iterator; + return _RANGES subrange<_Mutating_iterator>{_Mutating_iterator{_Data.keys.begin(), _Data.values.begin()}, + _Mutating_iterator{_Data.keys.end(), _Data.values.end()}}; } void _Sort() { _Clear_flat_map_scope_guard _Guard{this}; - _RANGES sort(_View_to_sort(), value_compare(_Key_compare)); + _RANGES sort(_View_to_mutate(), value_compare(_Key_compare)); _Guard._Clearable = nullptr; } void _Dedup() { _Clear_flat_map_scope_guard _Guard{this}; - auto _Sorted_view = _View_to_sort(); - auto _Subrange = _RANGES unique(_Sorted_view, - [this](const_reference _X, const_reference _Y) { return this->_Key_equal(_X.first, _Y.first); }); + auto _Sorted_view = _View_to_mutate(); + auto _Subrange = _RANGES unique(_Sorted_view, [this](const_reference _Left, const_reference _Right) { + return this->_Key_equal(_Left.first, _Right.first); + }); auto _Remaining_count = _STD distance(_Sorted_view.begin(), _Subrange.begin()); _Data.keys.erase(_Data.keys.begin() + _Remaining_count, _Data.keys.end()); _Data.values.erase(_Data.values.begin() + _Remaining_count, _Data.values.end()); _Guard._Clearable = nullptr; } - void _Insert_exact(const_iterator _Position, key_type&& _Key_val, mapped_type&& _Mapped) { + void _Insert_exact(const_iterator _Position, key_type&& _Key_val, mapped_type&& _Mapped_val) { _Clear_flat_map_scope_guard _Guard{this}; _Data.keys.insert(_Position._Key_it, _STD move(_Key_val)); - _Data.values.insert(_Position._Mapped_it, _STD move(_Mapped)); + _Data.values.insert(_Position._Mapped_it, _STD move(_Mapped_val)); _Guard._Clearable = nullptr; } - template - iterator _Emplace_hint(const_iterator _Position, _K&& _Key_val, _Mapped_args_t&&... _Args) - requires is_constructible_v - && (same_as, key_type> - || (constructible_from && _Is_transparent_v) ) + template + iterator _Emplace_hint(const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Args) + requires is_constructible_v + && (same_as, key_type> + || (constructible_from && _Is_transparent_v) ) { - static_assert(!(_Multi && _Overwrite_if_exists), + static_assert(!(_IsMulti && _OverwriteIfExists), "Overwriting is not supported when the container allows multiple copies of a key."); const const_iterator _Begin = cbegin(); const const_iterator _End = cend(); bool _Insert_before_position = false; bool _Insert_after_position_minus_1 = false; - if constexpr (_Multi) { + if constexpr (_IsMulti) { _Insert_before_position = (_Position == _End) || !_Key_compare(*(_Position._Key_it), _Key_val); _Insert_after_position_minus_1 = (_Position == _Begin) || !_Key_compare(_Key_val, *(_Position._Key_it - 1)); } else { @@ -897,29 +823,29 @@ private: if (_Hint_is_accurate) { auto _Dist = _STD distance(_Begin._Key_it, _Position._Key_it); - _Insert_exact( - _Position, key_type{_STD forward<_K>(_Key_val)}, mapped_type{_STD forward<_Mapped_args_t>(_Args)...}); + _Insert_exact(_Position, key_type{_STD forward<_OtherKey>(_Key_val)}, + mapped_type{_STD forward<_MappedArgTypes>(_Args)...}); return begin() + _Dist; } else { - if constexpr (_Overwrite_if_exists) { + if constexpr (_OverwriteIfExists) { if (_Key_equal(_Key_val, *(_Position._Key_it))) { auto _Dist = _STD distance(_Begin._Key_it, _Position._Key_it); auto _It = begin() + _Dist; - *(_It._Mapped_it) = mapped_type{_STD forward<_Mapped_args_t>(_Args)...}; + *(_It._Mapped_it) = mapped_type{_STD forward<_MappedArgTypes>(_Args)...}; return _It; } } _Position = lower_bound(_Key_val); - if (_Overwrite_if_exists && _Position != _End && _Key_equal(_Key_val, *(_Position._Key_it))) { + if (_OverwriteIfExists && _Position != _End && _Key_equal(_Key_val, *(_Position._Key_it))) { auto _Dist = _STD distance(_Begin._Key_it, _Position._Key_it); auto _It = begin() + _Dist; - *(_It._Mapped_it) = mapped_type{_STD forward<_Mapped_args_t>(_Args)...}; + *(_It._Mapped_it) = mapped_type{_STD forward<_MappedArgTypes>(_Args)...}; return _It; } else { auto _Dist = _STD distance(_Begin._Key_it, _Position._Key_it); - _Insert_exact(_Position, key_type{_STD forward<_K>(_Key_val)}, - mapped_type{_STD forward<_Mapped_args_t>(_Args)...}); + _Insert_exact(_Position, key_type{_STD forward<_OtherKey>(_Key_val)}, + mapped_type{_STD forward<_MappedArgTypes>(_Args)...}); return begin() + _Dist; } } @@ -943,7 +869,7 @@ private: } // Sort the newly inserted elements - auto _Sorted_view = _View_to_sort(); + auto _Sorted_view = _View_to_mutate(); if constexpr (_NeedSorting) { auto _Sorted_new_elements = _Sorted_view; _Sorted_new_elements.advance(_OldSize); @@ -960,210 +886,530 @@ private: _Guard._Clearable = nullptr; } - template - _NODISCARD mapped_type& _At(const _K& _Key_val) - requires same_as<_K, key_type> || _Is_transparent_v - { - iterator _Position = find(_Key_val); - if (_Position == end()) { - _Xout_of_range("std::flat_map::at: the specified key does not exist."); - } else { - return _Position->second; - } + template + size_type _Erase_key(_KeyTy&& _Key_val) { + const_iterator _Pos_begin = lower_bound(_STD forward<_KeyTy>(_Key_val)); + const_iterator _Pos_end = upper_bound(_STD forward<_KeyTy>(_Key_val)); + size_type _Count = _Pos_end - _Pos_begin; + erase(_Pos_begin, _Pos_end); + return _Count; } - template - iterator _Find(const _K& _X) - requires same_as<_K, key_type> || _Is_transparent_v + template + iterator _Find(const _KeyTy& _Key_val) + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - iterator _Position = lower_bound(_X); - if (_Position != end() && _Key_equal(_Position->first, _X)) { + iterator _Position = lower_bound(_Key_val); + if (_Position != end() && _Key_equal(_Position->first, _Key_val)) { return _Position; } else { return end(); } } - template - const_iterator _Find(const _K& _X) const - requires same_as<_K, key_type> || _Is_transparent_v + template + const_iterator _Find(const _KeyTy& _Key_val) const + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - const_iterator _Position = lower_bound(_X); - if (_Position != cend() && _Key_equal(_Position->first, _X)) { + const_iterator _Position = lower_bound(_Key_val); + if (_Position != cend() && _Key_equal(_Position->first, _Key_val)) { return _Position; } else { return cend(); } } - template - size_type _Count(const _K& _X) const - requires same_as<_K, key_type> || _Is_transparent_v + template + size_type _Count(const _KeyTy& _Key_val) const + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - return upper_bound(_X) - lower_bound(_X); + return upper_bound(_Key_val) - lower_bound(_Key_val); } - template - bool _Contains(const _K& _X) const - requires same_as<_K, key_type> || _Is_transparent_v + template + bool _Contains(const _KeyTy& _Key_val) const + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - return find(_X) != cend(); + return find(_Key_val) != cend(); } - template - iterator _Lower_bound(const _K& _X) - requires same_as<_K, key_type> || _Is_transparent_v + template + iterator _Lower_bound(const _KeyTy& _Key_val) + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - auto _Key_it = _STD lower_bound(_Data.keys.cbegin(), _Data.keys.cend(), _X, _Key_compare); + auto _Key_it = _STD lower_bound(_Data.keys.cbegin(), _Data.keys.cend(), _Key_val, _Key_compare); auto _Dist = _STD distance(_Data.keys.cbegin(), _Key_it); auto _Val_it = _Data.values.begin() + _Dist; return iterator{_STD move(_Key_it), _STD move(_Val_it)}; } - template - const_iterator _Lower_bound(const _K& _X) const - requires same_as<_K, key_type> || _Is_transparent_v + template + const_iterator _Lower_bound(const _KeyTy& _Key_val) const + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - auto _Key_it = _STD lower_bound(_Data.keys.cbegin(), _Data.keys.cend(), _X, _Key_compare); + auto _Key_it = _STD lower_bound(_Data.keys.cbegin(), _Data.keys.cend(), _Key_val, _Key_compare); auto _Dist = _STD distance(_Data.keys.cbegin(), _Key_it); auto _Val_it = _Data.values.cbegin() + _Dist; return const_iterator{_STD move(_Key_it), _STD move(_Val_it)}; } - template - iterator _Upper_bound(const _K& _X) - requires same_as<_K, key_type> || _Is_transparent_v + template + iterator _Upper_bound(const _KeyTy& _Key_val) + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - auto _Key_it = _STD upper_bound(_Data.keys.cbegin(), _Data.keys.cend(), _X, _Key_compare); + auto _Key_it = _STD upper_bound(_Data.keys.cbegin(), _Data.keys.cend(), _Key_val, _Key_compare); auto _Dist = _STD distance(_Data.keys.cbegin(), _Key_it); auto _Val_it = _Data.values.begin() + _Dist; return iterator{_STD move(_Key_it), _STD move(_Val_it)}; } - template - const_iterator _Upper_bound(const _K& _X) const - requires same_as<_K, key_type> || _Is_transparent_v + template + const_iterator _Upper_bound(const _KeyTy& _Key_val) const + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - auto _Key_it = _STD upper_bound(_Data.keys.cbegin(), _Data.keys.cend(), _X, _Key_compare); + auto _Key_it = _STD upper_bound(_Data.keys.cbegin(), _Data.keys.cend(), _Key_val, _Key_compare); auto _Dist = _STD distance(_Data.keys.cbegin(), _Key_it); auto _Val_it = _Data.values.cbegin() + _Dist; return const_iterator{_STD move(_Key_it), _STD move(_Val_it)}; } - template - pair _Equal_range(const _K& _X) - requires same_as<_K, key_type> || _Is_transparent_v + template + pair _Equal_range(const _KeyTy& _Key_val) + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - return {lower_bound(_X), upper_bound(_X)}; + return {lower_bound(_Key_val), upper_bound(_Key_val)}; } - template - pair _Equal_range(const _K& _X) const - requires same_as<_K, key_type> || _Is_transparent_v + template + pair _Equal_range(const _KeyTy& _Key_val) const + requires same_as<_KeyTy, key_type> || _Is_transparent_v { - return {lower_bound(_X), upper_bound(_X)}; + return {lower_bound(_Key_val), upper_bound(_Key_val)}; } }; template -class flat_map : public _Flat_Map_Base<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer, false, +class flat_map : public _Flat_map_base<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer, false, flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>> { private: - using _MyBase = _Flat_Map_Base<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer, false, + using _MyBase = _Flat_map_base<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer, false, flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>>; + using _MyBase::_Data; + using _MyBase::_Key_compare; + public: + using typename _MyBase::const_iterator; + using typename _MyBase::iterator; + using typename _MyBase::key_compare; + using typename _MyBase::key_type; + using typename _MyBase::mapped_type; + using typename _MyBase::value_type; + using _MyBase::_MyBase; using _MyBase::operator=; -}; -template -class flat_multimap : public _Flat_Map_Base<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer, true, - flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>> { + // [flat.map.access] Access + _NODISCARD mapped_type& operator[](const key_type& _Key_val) { + return this->try_emplace(_Key_val).first->second; + } + _NODISCARD mapped_type& operator[](key_type&& _Key_val) { + return this->try_emplace(_STD move(_Key_val)).first->second; + } + + template + _NODISCARD mapped_type& operator[](_OtherKey&& _Key_val) + requires _Is_transparent_v + { + return this->try_emplace(_STD forward<_OtherKey>(_Key_val)).first->second; + } + + _NODISCARD mapped_type& at(const key_type& _Key_val) { + return _At(_Key_val); + } + + _NODISCARD const mapped_type& at(const key_type& _Key_val) const { + return _At(_Key_val); + } + + template + _NODISCARD mapped_type& at(const _OtherKey& _Key_val) + requires _Is_transparent_v + { + return _At(_Key_val); + } + + template + _NODISCARD const mapped_type& at(const _OtherKey& _Key_val) const + requires _Is_transparent_v + { + return _At(_Key_val); + } + + // [flat.map.modifiers] Modifiers + template + pair emplace(_ArgTypes&&... _Args) + requires is_constructible_v + { + value_type _Val(_STD forward<_ArgTypes>(_Args)...); + return try_emplace(_STD move(_Val.first), _STD move(_Val.second)); + } + + pair insert(const value_type& _Pair_val) { + return try_emplace(_Pair_val.first, _Pair_val.second); + } + + pair insert(value_type&& _Pair_val) { + return try_emplace(_STD move(_Pair_val.first), _STD move(_Pair_val.second)); + } + + template + pair insert(_PairValTy&& _Pair_val) + requires is_constructible_v + { + return emplace(_STD forward<_PairValTy>(_Pair_val)); + } + + template + requires is_constructible_v + pair try_emplace(const key_type& _Key_val, _MappedArgTypes&&... _Mapped_args) { + return _Try_emplace(_Key_val, _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + requires is_constructible_v + pair try_emplace(key_type&& _Key_val, _MappedArgTypes&&... _Mapped_args) { + return _Try_emplace(_STD move(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + requires _Is_transparent_v && is_constructible_v + && is_constructible_v + && (!is_convertible_v<_OtherKey, const_iterator>) && (!is_convertible_v<_OtherKey, iterator>) + pair try_emplace(_OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) { + return _Try_emplace(_STD forward<_OtherKey>(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + iterator try_emplace(const_iterator _Position, const key_type& _Key_val, _MappedArgTypes&&... _Mapped_args) + requires is_constructible_v + { + return this->template _Emplace_hint(_Position, _Key_val, _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + iterator try_emplace(const_iterator _Position, key_type&& _Key_val, _MappedArgTypes&&... _Mapped_args) + requires is_constructible_v + { + return this->template _Emplace_hint( + _Position, _STD move(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + iterator try_emplace(const_iterator _Position, _OtherKey&& _Key_val, _MappedArgTypes&&... _Mapped_args) + requires _Is_transparent_v && is_constructible_v + && is_constructible_v + { + return this->template _Emplace_hint( + _Position, _STD forward<_OtherKey>(_Key_val), _STD forward<_MappedArgTypes>(_Mapped_args)...); + } + + template + pair insert_or_assign(const key_type& _Key_val, _MappedTy&& _Mapped_val) + requires is_assignable_v && is_constructible_v + { + return _Insert_or_assign(_Key_val, _STD forward<_MappedTy>(_Mapped_val)); + } + + template + pair insert_or_assign(key_type&& _Key_val, _MappedTy&& _Mapped_val) + requires is_assignable_v && is_constructible_v + { + return _Insert_or_assign(_STD move(_Key_val), _STD forward<_MappedTy>(_Mapped_val)); + } + + template + pair insert_or_assign(_OtherKey&& _Key_val, _MappedTy&& _Mapped_val) + requires _Is_transparent_v && is_constructible_v + && is_assignable_v && is_constructible_v + { + return _Insert_or_assign(_STD forward<_OtherKey>(_Key_val), _STD forward<_MappedTy>(_Mapped_val)); + } + + template + iterator insert_or_assign(const_iterator _Position, const key_type& _Key_val, _MappedTy&& _Mapped_val) + requires is_assignable_v && is_constructible_v + { + return this->_Emplace_hint(_Position, _Key_val, _STD forward<_MappedTy>(_Mapped_val)); + } + + template + iterator insert_or_assign(const_iterator _Position, key_type&& _Key_val, _MappedTy&& _Mapped_val) + requires is_assignable_v && is_constructible_v + { + return this->_Emplace_hint(_Position, _STD move(_Key_val), _STD forward<_MappedTy>(_Mapped_val)); + } + + template + iterator insert_or_assign(const_iterator _Position, _OtherKey&& _Key_val, _MappedTy&& _Mapped_val) + requires _Is_transparent_v && is_constructible_v + && is_assignable_v && is_constructible_v + { + return this->_Emplace_hint( + _Position, _STD forward<_OtherKey>(_Key_val), _STD forward<_MappedTy>(_Mapped_val)); + } + private: - using _MyBase = _Flat_Map_Base<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer, true, - flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>>; + using _MyBase::_Erase_if; -public: - using _MyBase::_MyBase; - using _MyBase::operator=; + template + friend typename flat_map<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>::size_type erase_if( + flat_map<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>&, _Pred); + + template + _NODISCARD mapped_type& _At(const _KeyTy& _Key_val) + requires same_as<_KeyTy, key_type> || _Is_transparent_v + { + const auto _Position = this->find(_Key_val); + if (_Position == this->end()) { + _Xout_of_range("std::flat_map::at: the specified key does not exist."); + } else { + return _Position->second; + } + } + + template + _NODISCARD const mapped_type& _At(const _KeyTy& _Key_val) const + requires same_as<_KeyTy, key_type> || _Is_transparent_v + { + const auto _Position = this->find(_Key_val); + if (_Position == this->end()) { + _Xout_of_range("std::flat_map::at: the specified key does not exist."); + } else { + return _Position->second; + } + } + + template + pair _Try_emplace(_KeyTy&& _Key_val, _MappedArgTypes&&... _Mapped_args) { + auto _Key_it = _STD lower_bound(_Data.keys.begin(), _Data.keys.end(), _Key_val, _Key_compare); + if (_Key_it != _Data.keys.end() && _Key_equal(*_Key_it, _STD forward<_KeyTy>(_Key_val))) { + // Already exists + return {this->begin() + _STD distance(_Data.keys.begin(), _Key_it), false}; + } else { + // Need to insert + auto _Index = _STD distance(_Data.keys.begin(), _Key_it); + this->_Insert_exact(this->cbegin() + _Index, key_type{_STD forward<_KeyTy>(_Key_val)}, + mapped_type{_STD forward<_MappedArgTypes>(_Mapped_args)...}); + return {this->begin() + _Index, true}; + } + } + + template + pair _Insert_or_assign(_KeyTy&& _Key_val, _MappedTy&& _Mapped_val) { + auto _Res = _Try_emplace(_STD forward<_KeyTy>(_Key_val), _STD forward<_MappedTy>(_Mapped_val)); + if (!_Res.second) { // Already exists + _Res.first->second = _STD forward<_MappedTy>(_Mapped_val); + } + return _Res; + } }; template _Compare = less> + _Valid_compare_for_container<_KeyContainer> _Compare = less> flat_map(_KeyContainer, _MappedContainer, _Compare = _Compare()) -> flat_map; template _Allocator> + _Valid_allocator_for_flat_map<_KeyContainer, _MappedContainer> _Allocator> flat_map(_KeyContainer, _MappedContainer, _Allocator) -> flat_map, _KeyContainer, _MappedContainer>; -template _Compare, - _Valid_Allocator_for_flat_map<_KeyContainer, _MappedContainer> _Allocator> +template _Compare, + _Valid_allocator_for_flat_map<_KeyContainer, _MappedContainer> _Allocator> flat_map(_KeyContainer, _MappedContainer, _Compare, _Allocator) -> flat_map; template _Compare = less> + _Valid_compare_for_container<_KeyContainer> _Compare = less> flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Compare = _Compare()) -> flat_map; template _Allocator> + _Valid_allocator_for_flat_map<_KeyContainer, _MappedContainer> _Allocator> flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Allocator) -> flat_map, _KeyContainer, _MappedContainer>; -template _Compare, - _Valid_Allocator_for_flat_map<_KeyContainer, _MappedContainer> _Allocator> +template _Compare, + _Valid_allocator_for_flat_map<_KeyContainer, _MappedContainer> _Allocator> flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Compare, _Allocator) -> flat_map; -template ::first_type>> +template >> flat_map(_InputIterator, _InputIterator, _Compare = _Compare()) - -> flat_map::first_type, typename iter_value_t<_InputIterator>::second_type, - _Compare>; + -> flat_map<_Guide_key_t<_InputIterator>, _Guide_val_t<_InputIterator>, _Compare>; -template ::first_type>> +template >> flat_map(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) - -> flat_map::first_type, typename iter_value_t<_InputIterator>::second_type, - _Compare>; - -template <_RANGES input_range _R, class _Compare = less::first_type>, - class _Allocator = allocator> -flat_map(from_range_t, _R&&, _Compare = _Compare(), _Allocator = _Allocator()) - -> flat_map::first_type, typename _RANGES range_value_t<_R>::second_type, - _Compare, - vector::first_type, - _Rebind_alloc_t<_Allocator, typename _RANGES range_value_t<_R>::first_type>>, - vector::second_type, - _Rebind_alloc_t<_Allocator, typename _RANGES range_value_t<_R>::second_type>>>; - -template <_RANGES input_range _R, class _Allocator> -flat_map(from_range_t, _R&&, _Allocator) -> flat_map::first_type, - typename _RANGES range_value_t<_R>::second_type, less::first_type>, - vector::first_type, - _Rebind_alloc_t<_Allocator, typename _RANGES range_value_t<_R>::first_type>>, - vector::second_type, - _Rebind_alloc_t<_Allocator, typename _RANGES range_value_t<_R>::second_type>>>; - -template > -flat_map(initializer_list>, _Compare = _Compare()) -> flat_map<_Key, _T, _Compare>; - -template > -flat_map(sorted_unique_t, initializer_list>, _Compare = _Compare()) -> flat_map<_Key, _T, _Compare>; + -> flat_map<_Guide_key_t<_InputIterator>, _Guide_val_t<_InputIterator>, _Compare>; + +#ifdef __cpp_lib_byte +template <_RANGES input_range _Rng, class _Compare = less<_Range_key_type<_Rng>>, class _Allocator = allocator> +flat_map(from_range_t, _Rng&&, _Compare = _Compare(), _Allocator = _Allocator()) + -> flat_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Compare, + vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Allocator, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Allocator, _Range_mapped_type<_Rng>>>>; +#endif // defined(__cpp_lib_byte) + +template <_RANGES input_range _Rng, class _Allocator> +flat_map(from_range_t, _Rng&&, _Allocator) -> flat_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, + less<_Range_key_type<_Rng>>, vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Allocator, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Allocator, _Range_mapped_type<_Rng>>>>; + +template > +flat_map(initializer_list>, _Compare = _Compare()) -> flat_map<_Key, _Mapped, _Compare>; + +template > +flat_map(sorted_unique_t, initializer_list>, _Compare = _Compare()) + -> flat_map<_Key, _Mapped, _Compare>; // Specialization of uses_allocator -template -struct uses_allocator, _Allocator> +template +struct uses_allocator, _Allocator> : bool_constant && uses_allocator_v<_MappedContainer, _Allocator>> {}; -template -struct uses_allocator, _Allocator> +_EXPORT_STD template +typename flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>::size_type erase_if( + flat_map<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>& _Cont, _Predicate _Pred) { + return _Cont._Erase_if(_STD _Pass_fn(_Pred)); +} + +template +class flat_multimap : public _Flat_map_base<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer, true, + flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>> { +private: + using _MyBase = _Flat_map_base<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer, true, + flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>>; + + using _MyBase::_Data; + using _MyBase::_Key_compare; + +public: + using typename _MyBase::iterator; + using typename _MyBase::value_type; + + using _MyBase::_MyBase; + using _MyBase::operator=; + + // [flat.multimap.modifiers] Modifiers + template + iterator emplace(_ArgTypes&&... _Args) { + value_type _Val(_STD forward<_ArgTypes>(_Args)...); + return _Emplace_key_mapped(_STD move(_Val.first), _STD move(_Val.second)); + } + + iterator insert(const value_type& _Px) { + return _Emplace_key_mapped(_Px.first, _Px.second); + } + + iterator insert(value_type&& _Px) { + return _Emplace_key_mapped(_STD move(_Px.first), _STD move(_Px.second)); + } + + template + iterator insert(_PairValTy&& _Pair_val) + requires is_constructible_v + { + return emplace(_STD forward<_PairValTy>(_Pair_val)); + } + +private: + using _MyBase::_Erase_if; + + template + friend typename flat_multimap<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>::size_type erase_if( + flat_multimap<_KTy, _MTy, _Comp, _KeyCont, _MappedCont>&, _Pred); + + template + iterator _Emplace_key_mapped(_KeyTy&& _Key_val, _MappedTy&& _Mapped_val) { + auto _Key_it = _STD lower_bound(_Data.keys.begin(), _Data.keys.end(), _Key_val, _Key_compare); + auto _Index = _STD distance(_Data.keys.begin(), _Key_it); + + this->_Insert_exact( + this->cbegin() + _Index, _STD forward<_KeyTy>(_Key_val), _STD forward<_MappedTy>(_Mapped_val)); + return this->begin() + _Index; + } +}; + +template > +flat_multimap(_KeyContainer, _MappedContainer, _Compare = _Compare()) + -> flat_multimap; + +template +flat_multimap(_KeyContainer, _MappedContainer, _Allocator) -> flat_multimap, _KeyContainer, _MappedContainer>; +template +flat_multimap(_KeyContainer, _MappedContainer, _Compare, _Allocator) + -> flat_multimap; + +template > +flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Compare = _Compare()) + -> flat_multimap; + +template +flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Allocator) + -> flat_multimap, _KeyContainer, _MappedContainer>; +template +flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Compare, _Allocator) + -> flat_multimap; + +template >> +flat_multimap(_InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_multimap<_Guide_key_t<_InputIterator>, _Guide_val_t<_InputIterator>, _Compare>; + +template >> +flat_multimap(sorted_equivalent_t, _InputIterator, _InputIterator, _Compare = _Compare()) + -> flat_multimap<_Guide_key_t<_InputIterator>, _Guide_val_t<_InputIterator>, _Compare>; + +#ifdef __cpp_lib_byte +template <_RANGES input_range _Rng, class _Compare = less<_Range_key_type<_Rng>>, class _Allocator = allocator> +flat_multimap(from_range_t, _Rng&&, _Compare = _Compare(), _Allocator = _Allocator()) + -> flat_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Compare, + vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Allocator, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Allocator, _Range_mapped_type<_Rng>>>>; +#endif // defined(__cpp_lib_byte) + +template <_RANGES input_range _Rng, class _Allocator> +flat_multimap(from_range_t, _Rng&&, _Allocator) -> flat_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, + less<_Range_key_type<_Rng>>, vector<_Range_key_type<_Rng>, _Rebind_alloc_t<_Allocator, _Range_key_type<_Rng>>>, + vector<_Range_mapped_type<_Rng>, _Rebind_alloc_t<_Allocator, _Range_mapped_type<_Rng>>>>; + +template > +flat_multimap(initializer_list>, _Compare = _Compare()) -> flat_multimap<_Key, _Mapped, _Compare>; + +template > +flat_multimap(sorted_equivalent_t, initializer_list>, _Compare = _Compare()) + -> flat_multimap<_Key, _Mapped, _Compare>; + +// Specialization of uses_allocator +template +struct uses_allocator, _Allocator> : bool_constant && uses_allocator_v<_MappedContainer, _Allocator>> {}; +_EXPORT_STD template +typename flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>::size_type erase_if( + flat_multimap<_Key, _Mapped, _Compare, _KeyContainer, _MappedContainer>& _Cont, _Predicate _Pred) { + return _Cont._Erase_if(_STD _Pass_fn(_Pred)); +} _STD_END #pragma pop_macro("new") diff --git a/tests/std/tests/P0429R9_flat_map/test.cpp b/tests/std/tests/P0429R9_flat_map/test.cpp index b5cfda070f3..428855a4849 100644 --- a/tests/std/tests/P0429R9_flat_map/test.cpp +++ b/tests/std/tests/P0429R9_flat_map/test.cpp @@ -28,20 +28,18 @@ bool check_container_requirements(T&&) { template consteval bool check_reversible_container_requirements() { using map_t = remove_cvref_t; - bool result = true; - result &= is_same_v, typename map_t::reverse_iterator>; - result &= is_same_v, typename map_t::const_reverse_iterator>; - result &= is_same_v().begin()), typename map_t::iterator>; - result &= is_same_v().end()), typename map_t::iterator>; - result &= is_same_v().cbegin()), typename map_t::const_iterator>; - result &= is_same_v().cend()), typename map_t::const_iterator>; - result &= is_same_v().rbegin()), typename map_t::reverse_iterator>; - result &= is_same_v().rend()), typename map_t::reverse_iterator>; - result &= is_same_v().crbegin()), typename map_t::const_reverse_iterator>; - result &= is_same_v().crend()), typename map_t::const_reverse_iterator>; - result &= is_convertible_v; - result &= is_convertible_v; - return result; + return is_same_v, typename map_t::reverse_iterator> + && is_same_v, typename map_t::const_reverse_iterator> + && is_same_v().begin()), typename map_t::iterator> + && is_same_v().end()), typename map_t::iterator> + && is_same_v().cbegin()), typename map_t::const_iterator> + && is_same_v().cend()), typename map_t::const_iterator> + && is_same_v().rbegin()), typename map_t::reverse_iterator> + && is_same_v().rend()), typename map_t::reverse_iterator> + && is_same_v().crbegin()), typename map_t::const_reverse_iterator> + && is_same_v().crend()), typename map_t::const_reverse_iterator> + && is_convertible_v + && is_convertible_v; } template @@ -120,21 +118,13 @@ class Packaged { value = t; } - friend bool operator==(const Packaged& lhs, const Packaged& rhs) { - return lhs.value == rhs.value; - } + friend bool operator==(const Packaged&, const Packaged&) = default; friend bool operator==(const Packaged& lhs, const T& rhs) { return lhs.value == rhs; } - friend bool operator==(const T& lhs, const Packaged& rhs) { - return lhs == rhs.value; - } - - friend auto operator<=>(const Packaged& lhs, const Packaged& rhs) { - return lhs.value <=> rhs.value; - } + friend auto operator<=>(const Packaged&, const Packaged&) = default; }; template @@ -246,6 +236,19 @@ void test_construction() { } } +void test_erase_if() { + { + vector keys = {0, 1, 2, 3, 4, 2}; + vector vals = {44, 2324, 635462, 433, 5, 7}; + flat_map fmap(keys, vals); + const auto erased_num = erase_if( + fmap, [](pair refpr) { return refpr.first % 2 == 0 && refpr.second % 2 != 0; }); + assert(erased_num == 1); + assert(fmap.size() == 4); + assert(check_key_content(fmap, {0, 1, 2, 3})); + assert(check_value_content(fmap, {44, 2324, 635462, 433})); + } +} struct Incomplete; template @@ -265,7 +268,40 @@ void test_pointer_to_incomplete_type() { flat_map, shared_ptr>> fmap; } +// Test MSVC STL-specific SCARY-ness +namespace scary_test { + static_assert(is_same_v::iterator, flat_map>::iterator>); + static_assert(is_same_v::iterator, + flat_map, vector>, vector>>::iterator>); + static_assert(is_same_v::const_iterator, flat_map>::const_iterator>); + static_assert(is_same_v::const_iterator, + flat_map, vector>, vector>>::const_iterator>); + + static_assert(is_same_v::iterator, flat_multimap>::iterator>); + static_assert(is_same_v::iterator, + flat_multimap, vector>, vector>>::iterator>); + static_assert( + is_same_v::const_iterator, flat_multimap>::const_iterator>); + static_assert(is_same_v::const_iterator, + flat_multimap, vector>, vector>>::const_iterator>); + + static_assert(is_same_v::iterator, flat_multimap::iterator>); + static_assert(is_same_v::const_iterator, flat_multimap::const_iterator>); + + static_assert(is_same_v::containers, flat_map>::containers>); + static_assert(is_same_v::containers, flat_multimap>::containers>); + static_assert(is_same_v::containers, flat_multimap::containers>); + + static_assert(is_same_v::value_compare, + flat_map, vector>, vector>>::value_compare>); + static_assert(is_same_v::value_compare, + flat_multimap, vector>, + vector>>::value_compare>); + static_assert(is_same_v::value_compare, flat_multimap::value_compare>); +} // namespace scary_test + int main() { test_construction(); test_pointer_to_incomplete_type(); + test_erase_if(); }