// map standard header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once #ifndef _MAP_ #define _MAP_ #include #if _STL_COMPILER_PREPROCESSOR #include #include #if _HAS_CXX17 #include #endif // _HAS_CXX17 #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new _STD_BEGIN // CLASS TEMPLATE _Tmap_traits template // true if multiple equivalent keys are permitted class _Tmap_traits { // traits required to make _Tree behave like a map public: using key_type = _Kty; using value_type = pair; using key_compare = _Pr; using allocator_type = _Alloc; #if _HAS_CXX17 using node_type = _Node_handle<_Tree_node::void_pointer>, _Alloc, _Node_handle_map_base, _Kty, _Ty>; #endif // _HAS_CXX17 static constexpr bool _Multi = _Mfl; template using _In_place_key_extractor = _In_place_key_extract_map<_Kty, _Args...>; class value_compare { public: _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef value_type first_argument_type; _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef value_type second_argument_type; _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool result_type; _NODISCARD bool operator()(const value_type& _Left, const value_type& _Right) const { // test if _Left precedes _Right by comparing just keys return comp(_Left.first, _Right.first); } protected: friend _Tree<_Tmap_traits>; value_compare(key_compare _Pred) : comp(_Pred) {} key_compare comp; // the comparator predicate for keys }; template static const _Kty& _Kfn(const pair<_Ty1, _Ty2>& _Val) { // extract key from element value return _Val.first; } }; // CLASS TEMPLATE map template , class _Alloc = allocator>> class map : public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false>> { // ordered red-black tree of {key, mapped} values, unique keys public: static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v, typename _Alloc::value_type>, _MISMATCHED_ALLOCATOR_MESSAGE("map", "pair")); using _Mybase = _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false>>; using _Nodeptr = typename _Mybase::_Nodeptr; using key_type = _Kty; using mapped_type = _Ty; using key_compare = _Pr; using value_compare = typename _Mybase::value_compare; using value_type = pair; using allocator_type = typename _Mybase::allocator_type; using size_type = typename _Mybase::size_type; using difference_type = typename _Mybase::difference_type; using pointer = typename _Mybase::pointer; using const_pointer = typename _Mybase::const_pointer; using reference = value_type&; using const_reference = const value_type&; using iterator = typename _Mybase::iterator; using const_iterator = typename _Mybase::const_iterator; using reverse_iterator = typename _Mybase::reverse_iterator; using const_reverse_iterator = typename _Mybase::const_reverse_iterator; using _Alnode = typename _Mybase::_Alnode; using _Alnode_traits = typename _Mybase::_Alnode_traits; #if _HAS_CXX17 using insert_return_type = _Insert_return_type; #endif // _HAS_CXX17 map() : _Mybase(key_compare()) {} explicit map(const allocator_type& _Al) : _Mybase(key_compare(), _Al) {} map(const map& _Right) : _Mybase(_Right, _Alnode_traits::select_on_container_copy_construction(_Right._Getal())) {} map(const map& _Right, const allocator_type& _Al) : _Mybase(_Right, _Al) {} explicit map(const key_compare& _Pred) : _Mybase(_Pred) {} map(const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) {} template map(_Iter _First, _Iter _Last) : _Mybase(key_compare()) { insert(_First, _Last); } template map(_Iter _First, _Iter _Last, const key_compare& _Pred) : _Mybase(_Pred) { insert(_First, _Last); } template map(_Iter _First, _Iter _Last, const allocator_type& _Al) : _Mybase(key_compare(), _Al) { insert(_First, _Last); } template map(_Iter _First, _Iter _Last, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) { insert(_First, _Last); } map& operator=(const map& _Right) { _Mybase::operator=(_Right); return *this; } map(map&& _Right) : _Mybase(_STD move(_Right)) {} map(map&& _Right, const allocator_type& _Al) : _Mybase(_STD move(_Right), _Al) {} map& operator=(map&& _Right) noexcept(_Alnode_traits::is_always_equal::value&& is_nothrow_move_assignable_v<_Pr>) { _Mybase::operator=(_STD move(_Right)); return *this; } mapped_type& operator[](key_type&& _Keyval) { // find element matching _Keyval or insert value-initialized value return _Try_emplace(_STD move(_Keyval)).first->_Myval.second; } void swap(map& _Right) noexcept(noexcept(_Mybase::swap(_Right))) { _Mybase::swap(_Right); } using _Mybase::insert; template , int> = 0> pair insert(_Valty&& _Val) { return this->emplace(_STD forward<_Valty>(_Val)); } template , int> = 0> iterator insert(const_iterator _Where, _Valty&& _Val) { return this->emplace_hint(_Where, _STD forward<_Valty>(_Val)); } private: template pair<_Nodeptr, bool> _Try_emplace(_Keyty&& _Keyval, _Mappedty&&... _Mapval) { const auto _Loc = _Mybase::_Find_lower_bound(_Keyval); if (_Mybase::_Lower_bound_duplicate(_Loc._Bound, _Keyval)) { return {_Loc._Bound, false}; } _Mybase::_Check_grow_by_1(); const auto _Scary = _Mybase::_Get_scary(); const auto _Inserted = _Tree_temp_node<_Alnode>(_Mybase::_Getal(), _Scary->_Myhead, piecewise_construct, _STD forward_as_tuple(_STD forward<_Keyty>(_Keyval)), _STD forward_as_tuple(_STD forward<_Mappedty>(_Mapval)...)) ._Release(); // nothrow hereafter return {_Scary->_Insert_node(_Loc._Location, _Inserted), true}; } template _Nodeptr _Try_emplace_hint(const _Nodeptr _Hint, _Keyty&& _Keyval, _Mappedty&&... _Mapval) { const auto _Loc = _Mybase::_Find_hint(_Hint, _Keyval); if (_Loc._Duplicate) { return _Loc._Location._Parent; } _Mybase::_Check_grow_by_1(); const auto _Scary = _Mybase::_Get_scary(); const auto _Inserted = _Tree_temp_node<_Alnode>(_Mybase::_Getal(), _Scary->_Myhead, piecewise_construct, _STD forward_as_tuple(_STD forward<_Keyty>(_Keyval)), _STD forward_as_tuple(_STD forward<_Mappedty>(_Mapval)...)) ._Release(); // nothrow hereafter return _Scary->_Insert_node(_Loc._Location, _Inserted); } public: template pair try_emplace(const key_type& _Keyval, _Mappedty&&... _Mapval) { const auto _Result = _Try_emplace(_Keyval, _STD forward<_Mappedty>(_Mapval)...); return {iterator(_Result.first, _Mybase::_Get_scary()), _Result.second}; } template iterator try_emplace(const const_iterator _Hint, const key_type& _Keyval, _Mappedty&&... _Mapval) { return iterator( _Try_emplace_hint(_Hint._Ptr, _Keyval, _STD forward<_Mappedty>(_Mapval)...), _Mybase::_Get_scary()); } template pair try_emplace(key_type&& _Keyval, _Mappedty&&... _Mapval) { const auto _Result = _Try_emplace(_STD move(_Keyval), _STD forward<_Mappedty>(_Mapval)...); return {iterator(_Result.first, _Mybase::_Get_scary()), _Result.second}; } template iterator try_emplace(const const_iterator _Hint, key_type&& _Keyval, _Mappedty&&... _Mapval) { return iterator(_Try_emplace_hint(_Hint._Ptr, _STD move(_Keyval), _STD forward<_Mappedty>(_Mapval)...), _Mybase::_Get_scary()); } private: template pair<_Nodeptr, bool> _Insert_or_assign(_Keyty&& _Keyval, _Mappedty&& _Mapval) { const auto _Loc = _Mybase::_Find_lower_bound(_Keyval); if (_Mybase::_Lower_bound_duplicate(_Loc._Bound, _Keyval)) { _Loc._Bound->_Myval.second = _STD forward<_Mappedty>(_Mapval); return {_Loc._Bound, false}; } _Mybase::_Check_grow_by_1(); const auto _Scary = _Mybase::_Get_scary(); const auto _Inserted = _Tree_temp_node<_Alnode>( _Mybase::_Getal(), _Scary->_Myhead, _STD forward<_Keyty>(_Keyval), _STD forward<_Mappedty>(_Mapval)) ._Release(); // nothrow hereafter return {_Scary->_Insert_node(_Loc._Location, _Inserted), true}; } template _Nodeptr _Insert_or_assign_hint(const _Nodeptr _Hint, _Keyty&& _Keyval, _Mappedty&& _Mapval) { const auto _Loc = _Mybase::_Find_hint(_Hint, _Keyval); if (_Loc._Duplicate) { _Loc._Location._Parent->_Myval.second = _STD forward<_Mappedty>(_Mapval); return _Loc._Location._Parent; } _Mybase::_Check_grow_by_1(); const auto _Scary = _Mybase::_Get_scary(); const auto _Inserted = _Tree_temp_node<_Alnode>( _Mybase::_Getal(), _Scary->_Myhead, _STD forward<_Keyty>(_Keyval), _STD forward<_Mappedty>(_Mapval)) ._Release(); // nothrow hereafter return _Scary->_Insert_node(_Loc._Location, _Inserted); } public: template pair insert_or_assign(const key_type& _Keyval, _Mappedty&& _Mapval) { const auto _Result = _Insert_or_assign(_Keyval, _STD forward<_Mappedty>(_Mapval)); return {iterator(_Result.first, _Mybase::_Get_scary()), _Result.second}; } template iterator insert_or_assign(const const_iterator _Hint, const key_type& _Keyval, _Mappedty&& _Mapval) { return iterator( _Insert_or_assign_hint(_Hint._Ptr, _Keyval, _STD forward<_Mappedty>(_Mapval)), _Mybase::_Get_scary()); } template pair insert_or_assign(key_type&& _Keyval, _Mappedty&& _Mapval) { const auto _Result = _Insert_or_assign(_STD move(_Keyval), _STD forward<_Mappedty>(_Mapval)); return {iterator(_Result.first, _Mybase::_Get_scary()), _Result.second}; } template iterator insert_or_assign(const const_iterator _Hint, key_type&& _Keyval, _Mappedty&& _Mapval) { return iterator(_Insert_or_assign_hint(_Hint._Ptr, _STD move(_Keyval), _STD forward<_Mappedty>(_Mapval)), _Mybase::_Get_scary()); } map(initializer_list _Ilist) : _Mybase(key_compare()) { insert(_Ilist); } map(initializer_list _Ilist, const key_compare& _Pred) : _Mybase(_Pred) { insert(_Ilist); } map(initializer_list _Ilist, const allocator_type& _Al) : _Mybase(key_compare(), _Al) { insert(_Ilist); } map(initializer_list _Ilist, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) { insert(_Ilist); } map& operator=(initializer_list _Ilist) { _Mybase::clear(); insert(_Ilist); return *this; } mapped_type& operator[](const key_type& _Keyval) { return _Try_emplace(_Keyval).first->_Myval.second; } _NODISCARD mapped_type& at(const key_type& _Keyval) { const auto _Loc = _Mybase::_Find_lower_bound(_Keyval); if (!_Mybase::_Lower_bound_duplicate(_Loc._Bound, _Keyval)) { _Xout_of_range("invalid map key"); } return _Loc._Bound->_Myval.second; } _NODISCARD const mapped_type& at(const key_type& _Keyval) const { const auto _Loc = _Mybase::_Find_lower_bound(_Keyval); if (!_Mybase::_Lower_bound_duplicate(_Loc._Bound, _Keyval)) { _Xout_of_range("invalid map key"); } return _Loc._Bound->_Myval.second; } using _Mybase::_Unchecked_begin; using _Mybase::_Unchecked_end; }; #if _HAS_CXX17 template >, class _Alloc = allocator<_Guide_pair_t<_Iter>>, enable_if_t, negation<_Is_allocator<_Pr>>, _Is_allocator<_Alloc>>, int> = 0> map(_Iter, _Iter, _Pr = _Pr(), _Alloc = _Alloc())->map<_Guide_key_t<_Iter>, _Guide_val_t<_Iter>, _Pr, _Alloc>; template , class _Alloc = allocator>, enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> map(initializer_list>, _Pr = _Pr(), _Alloc = _Alloc())->map<_Kty, _Ty, _Pr, _Alloc>; template , _Is_allocator<_Alloc>>, int> = 0> map(_Iter, _Iter, _Alloc)->map<_Guide_key_t<_Iter>, _Guide_val_t<_Iter>, less<_Guide_key_t<_Iter>>, _Alloc>; template ::value, int> = 0> map(initializer_list>, _Alloc)->map<_Kty, _Ty, less<_Kty>, _Alloc>; #endif // _HAS_CXX17 template void swap(map<_Kty, _Ty, _Pr, _Alloc>& _Left, map<_Kty, _Ty, _Pr, _Alloc>& _Right) noexcept( noexcept(_Left.swap(_Right))) { _Left.swap(_Right); } #if _HAS_CXX20 template void erase_if(map<_Kty, _Ty, _Keylt, _Alloc>& _Cont, _Pr _Pred) { _Erase_nodes_if(_Cont, _Pass_fn(_Pred)); } #endif // _HAS_CXX20 // CLASS TEMPLATE multimap template , class _Alloc = allocator>> class multimap : public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, true>> { // ordered red-black tree of {key, mapped} values, non-unique keys public: static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v, typename _Alloc::value_type>, _MISMATCHED_ALLOCATOR_MESSAGE("multimap", "pair")); using _Mybase = _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, true>>; using key_type = _Kty; using mapped_type = _Ty; using key_compare = _Pr; using value_compare = typename _Mybase::value_compare; using value_type = pair; using allocator_type = typename _Mybase::allocator_type; using size_type = typename _Mybase::size_type; using difference_type = typename _Mybase::difference_type; using pointer = typename _Mybase::pointer; using const_pointer = typename _Mybase::const_pointer; using reference = value_type&; using const_reference = const value_type&; using iterator = typename _Mybase::iterator; using const_iterator = typename _Mybase::const_iterator; using reverse_iterator = typename _Mybase::reverse_iterator; using const_reverse_iterator = typename _Mybase::const_reverse_iterator; using _Alnode = typename _Mybase::_Alnode; using _Alnode_traits = typename _Mybase::_Alnode_traits; multimap() : _Mybase(key_compare()) {} explicit multimap(const allocator_type& _Al) : _Mybase(key_compare(), _Al) {} multimap(const multimap& _Right) : _Mybase(_Right, _Alnode_traits::select_on_container_copy_construction(_Right._Getal())) {} multimap(const multimap& _Right, const allocator_type& _Al) : _Mybase(_Right, _Al) {} explicit multimap(const key_compare& _Pred) : _Mybase(_Pred) {} multimap(const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) {} template multimap(_Iter _First, _Iter _Last) : _Mybase(key_compare()) { insert(_First, _Last); } template multimap(_Iter _First, _Iter _Last, const key_compare& _Pred) : _Mybase(_Pred) { insert(_First, _Last); } template multimap(_Iter _First, _Iter _Last, const allocator_type& _Al) : _Mybase(key_compare(), _Al) { insert(_First, _Last); } template multimap(_Iter _First, _Iter _Last, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) { insert(_First, _Last); } multimap& operator=(const multimap& _Right) { _Mybase::operator=(_Right); return *this; } multimap(multimap&& _Right) : _Mybase(_STD move(_Right)) {} multimap(multimap&& _Right, const allocator_type& _Al) : _Mybase(_STD move(_Right), _Al) {} multimap& operator=(multimap&& _Right) noexcept( _Alnode_traits::is_always_equal::value&& is_nothrow_move_assignable_v<_Pr>) { _Mybase::operator=(_STD move(_Right)); return *this; } template iterator emplace(_Valty&&... _Val) { return _Mybase::emplace(_STD forward<_Valty>(_Val)...).first; } void swap(multimap& _Right) noexcept(noexcept(_Mybase::swap(_Right))) { _Mybase::swap(_Right); } using _Mybase::insert; template , int> = 0> iterator insert(_Valty&& _Val) { return this->emplace(_STD forward<_Valty>(_Val)); } template , int> = 0> iterator insert(const_iterator _Where, _Valty&& _Val) { return this->emplace_hint(_Where, _STD forward<_Valty>(_Val)); } multimap(initializer_list _Ilist) : _Mybase(key_compare()) { insert(_Ilist); } multimap(initializer_list _Ilist, const key_compare& _Pred) : _Mybase(_Pred) { insert(_Ilist); } multimap(initializer_list _Ilist, const allocator_type& _Al) : _Mybase(key_compare(), _Al) { insert(_Ilist); } multimap(initializer_list _Ilist, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) { insert(_Ilist); } multimap& operator=(initializer_list _Ilist) { _Mybase::clear(); insert(_Ilist); return *this; } using _Mybase::_Unchecked_begin; using _Mybase::_Unchecked_end; }; #if _HAS_CXX17 template >, class _Alloc = allocator<_Guide_pair_t<_Iter>>, enable_if_t, negation<_Is_allocator<_Pr>>, _Is_allocator<_Alloc>>, int> = 0> multimap(_Iter, _Iter, _Pr = _Pr(), _Alloc = _Alloc())->multimap<_Guide_key_t<_Iter>, _Guide_val_t<_Iter>, _Pr, _Alloc>; template , class _Alloc = allocator>, enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> multimap(initializer_list>, _Pr = _Pr(), _Alloc = _Alloc())->multimap<_Kty, _Ty, _Pr, _Alloc>; template , _Is_allocator<_Alloc>>, int> = 0> multimap(_Iter, _Iter, _Alloc)->multimap<_Guide_key_t<_Iter>, _Guide_val_t<_Iter>, less<_Guide_key_t<_Iter>>, _Alloc>; template ::value, int> = 0> multimap(initializer_list>, _Alloc)->multimap<_Kty, _Ty, less<_Kty>, _Alloc>; #endif // _HAS_CXX17 template void swap(multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) noexcept( noexcept(_Left.swap(_Right))) { _Left.swap(_Right); } #if _HAS_CXX20 template void erase_if(multimap<_Kty, _Ty, _Keylt, _Alloc>& _Cont, _Pr _Pred) { _Erase_nodes_if(_Cont, _Pass_fn(_Pred)); } #endif // _HAS_CXX20 #if _HAS_CXX17 namespace pmr { template > using map = _STD map<_Kty, _Ty, _Pr, polymorphic_allocator>>; template > using multimap = _STD multimap<_Kty, _Ty, _Pr, polymorphic_allocator>>; } // namespace pmr #endif // _HAS_CXX17 _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR #endif // _MAP_