зеркало из https://github.com/microsoft/STL.git
706 строки
30 KiB
C++
706 строки
30 KiB
C++
// map standard header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef _MAP_
|
|
#define _MAP_
|
|
#include <yvals_core.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
|
|
#include <tuple>
|
|
#include <xtree>
|
|
|
|
#if _HAS_CXX17
|
|
#include <xpolymorphic_allocator.h>
|
|
#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
|
|
template <class _Kty, // key type
|
|
class _Ty, // mapped type
|
|
class _Pr, // comparator predicate type
|
|
class _Alloc, // actual allocator type (should be value allocator)
|
|
bool _Mfl> // 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<const _Kty, _Ty>;
|
|
using key_compare = _Pr;
|
|
using allocator_type = _Alloc;
|
|
#if _HAS_CXX17
|
|
using node_type = _Node_handle<_Tree_node<value_type, typename allocator_traits<_Alloc>::void_pointer>, _Alloc,
|
|
_Node_handle_map_base, _Kty, _Ty>;
|
|
#endif // _HAS_CXX17
|
|
|
|
static constexpr bool _Multi = _Mfl;
|
|
|
|
template <class... _Args>
|
|
using _In_place_key_extractor = _In_place_key_extract_map<_Kty, _Args...>;
|
|
|
|
class value_compare {
|
|
public:
|
|
using _FIRST_ARGUMENT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = value_type;
|
|
using _SECOND_ARGUMENT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = value_type;
|
|
using _RESULT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = bool;
|
|
|
|
_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 <class _Ty1, class _Ty2>
|
|
static const _Kty& _Kfn(const pair<_Ty1, _Ty2>& _Val) { // extract key from element value
|
|
return _Val.first;
|
|
}
|
|
};
|
|
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr = less<_Kty>, class _Alloc = allocator<pair<const _Kty, _Ty>>>
|
|
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<pair<const _Kty, _Ty>, typename _Alloc::value_type>,
|
|
_MISMATCHED_ALLOCATOR_MESSAGE("map<Key, Value, Compare, Allocator>", "pair<const Key, Value>"));
|
|
static_assert(is_object_v<_Kty>, "The C++ Standard forbids containers of non-object types "
|
|
"because of [container.requirements].");
|
|
|
|
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<const _Kty, _Ty>;
|
|
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<iterator, typename _Mybase::node_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 <class _Iter>
|
|
map(_Iter _First, _Iter _Last) : _Mybase(key_compare()) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
map(_Iter _First, _Iter _Last, const key_compare& _Pred) : _Mybase(_Pred) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
map(_Iter _First, _Iter _Last, const allocator_type& _Al) : _Mybase(key_compare(), _Al) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
map(_Iter _First, _Iter _Last, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
#if _HAS_CXX23
|
|
template <_Container_compatible_range<value_type> _Rng>
|
|
map(from_range_t, _Rng&& _Range) : _Mybase(key_compare()) {
|
|
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
|
|
}
|
|
|
|
template <_Container_compatible_range<value_type> _Rng>
|
|
map(from_range_t, _Rng&& _Range, const key_compare& _Pred) : _Mybase(_Pred) {
|
|
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
|
|
}
|
|
|
|
template <_Container_compatible_range<value_type> _Rng>
|
|
map(from_range_t, _Rng&& _Range, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) {
|
|
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
|
|
}
|
|
|
|
template <_Container_compatible_range<value_type> _Rng>
|
|
map(from_range_t, _Rng&& _Range, const allocator_type& _Al) : _Mybase(key_compare(), _Al) {
|
|
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
|
|
}
|
|
#endif // _HAS_CXX23
|
|
|
|
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 <class _Valty, enable_if_t<is_constructible_v<value_type, _Valty>, int> = 0>
|
|
pair<iterator, bool> insert(_Valty&& _Val) {
|
|
return this->emplace(_STD forward<_Valty>(_Val));
|
|
}
|
|
|
|
template <class _Valty, enable_if_t<is_constructible_v<value_type, _Valty>, int> = 0>
|
|
iterator insert(const_iterator _Where, _Valty&& _Val) {
|
|
return this->emplace_hint(_Where, _STD forward<_Valty>(_Val));
|
|
}
|
|
|
|
private:
|
|
template <class _Keyty, class... _Mappedty>
|
|
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 <class _Keyty, class... _Mappedty>
|
|
_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 <class... _Mappedty>
|
|
pair<iterator, bool> 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 <class... _Mappedty>
|
|
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 <class... _Mappedty>
|
|
pair<iterator, bool> 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 <class... _Mappedty>
|
|
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 <class _Keyty, class _Mappedty>
|
|
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 <class _Keyty, class _Mappedty>
|
|
_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 <class _Mappedty>
|
|
pair<iterator, bool> 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 <class _Mappedty>
|
|
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 <class _Mappedty>
|
|
pair<iterator, bool> 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 <class _Mappedty>
|
|
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<value_type> _Ilist) : _Mybase(key_compare()) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
map(initializer_list<value_type> _Ilist, const key_compare& _Pred) : _Mybase(_Pred) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
map(initializer_list<value_type> _Ilist, const allocator_type& _Al) : _Mybase(key_compare(), _Al) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
map(initializer_list<value_type> _Ilist, const key_compare& _Pred, const allocator_type& _Al)
|
|
: _Mybase(_Pred, _Al) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
map& operator=(initializer_list<value_type> _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<K, T> 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<K, T> key");
|
|
}
|
|
|
|
return _Loc._Bound->_Myval.second;
|
|
}
|
|
|
|
using _Mybase::_Unchecked_begin;
|
|
using _Mybase::_Unchecked_end;
|
|
};
|
|
|
|
#if _HAS_CXX17
|
|
template <class _Iter, class _Pr = less<_Guide_key_t<_Iter>>, class _Alloc = allocator<_Guide_pair_t<_Iter>>,
|
|
enable_if_t<conjunction_v<_Is_iterator<_Iter>, 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 _Kty, class _Ty, class _Pr = less<_Kty>, class _Alloc = allocator<pair<const _Kty, _Ty>>,
|
|
enable_if_t<conjunction_v<negation<_Is_allocator<_Pr>>, _Is_allocator<_Alloc>>, int> = 0>
|
|
map(initializer_list<pair<_Kty, _Ty>>, _Pr = _Pr(), _Alloc = _Alloc()) -> map<_Kty, _Ty, _Pr, _Alloc>;
|
|
|
|
template <class _Iter, class _Alloc, enable_if_t<conjunction_v<_Is_iterator<_Iter>, _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 <class _Kty, class _Ty, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0>
|
|
map(initializer_list<pair<_Kty, _Ty>>, _Alloc) -> map<_Kty, _Ty, less<_Kty>, _Alloc>;
|
|
|
|
#if _HAS_CXX23
|
|
template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>,
|
|
_Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>>
|
|
requires (!_Allocator_for_container<_Pr>)
|
|
map(from_range_t, _Rng&&, _Pr = _Pr(),
|
|
_Alloc = _Alloc()) -> map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>;
|
|
|
|
template <_RANGES input_range _Rng, _Allocator_for_container _Alloc>
|
|
map(from_range_t, _Rng&&,
|
|
_Alloc) -> map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, less<_Range_key_type<_Rng>>, _Alloc>;
|
|
#endif // _HAS_CXX23
|
|
#endif // _HAS_CXX17
|
|
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator==(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return _Left.size() == _Right.size()
|
|
&& _STD equal(_Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin());
|
|
}
|
|
|
|
#if _HAS_CXX20
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD _Synth_three_way_result<pair<const _Kty, _Ty>> operator<=>(
|
|
const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return _STD lexicographical_compare_three_way(_Left._Unchecked_begin(), _Left._Unchecked_end_iter(),
|
|
_Right._Unchecked_begin(), _Right._Unchecked_end_iter(), _Synth_three_way{});
|
|
}
|
|
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator!=(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return !(_Left == _Right);
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator<(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return _STD lexicographical_compare(
|
|
_Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin(), _Right._Unchecked_end_iter());
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator>(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return _Right < _Left;
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator<=(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return !(_Right < _Left);
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator>=(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return !(_Left < _Right);
|
|
}
|
|
#endif // ^^^ !_HAS_CXX20 ^^^
|
|
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
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
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Keylt, class _Alloc, class _Pr>
|
|
map<_Kty, _Ty, _Keylt, _Alloc>::size_type erase_if(map<_Kty, _Ty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
|
|
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
|
|
}
|
|
#endif // _HAS_CXX20
|
|
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr = less<_Kty>, class _Alloc = allocator<pair<const _Kty, _Ty>>>
|
|
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<pair<const _Kty, _Ty>, typename _Alloc::value_type>,
|
|
_MISMATCHED_ALLOCATOR_MESSAGE("multimap<Key, Value, Compare, Allocator>", "pair<const Key, Value>"));
|
|
static_assert(is_object_v<_Kty>, "The C++ Standard forbids containers of non-object types "
|
|
"because of [container.requirements].");
|
|
|
|
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<const _Kty, _Ty>;
|
|
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 <class _Iter>
|
|
multimap(_Iter _First, _Iter _Last) : _Mybase(key_compare()) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
multimap(_Iter _First, _Iter _Last, const key_compare& _Pred) : _Mybase(_Pred) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
multimap(_Iter _First, _Iter _Last, const allocator_type& _Al) : _Mybase(key_compare(), _Al) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
multimap(_Iter _First, _Iter _Last, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
#if _HAS_CXX23
|
|
template <_Container_compatible_range<value_type> _Rng>
|
|
multimap(from_range_t, _Rng&& _Range) : _Mybase(key_compare()) {
|
|
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
|
|
}
|
|
|
|
template <_Container_compatible_range<value_type> _Rng>
|
|
multimap(from_range_t, _Rng&& _Range, const key_compare& _Pred) : _Mybase(_Pred) {
|
|
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
|
|
}
|
|
|
|
template <_Container_compatible_range<value_type> _Rng>
|
|
multimap(from_range_t, _Rng&& _Range, const key_compare& _Pred, const allocator_type& _Al) : _Mybase(_Pred, _Al) {
|
|
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
|
|
}
|
|
|
|
template <_Container_compatible_range<value_type> _Rng>
|
|
multimap(from_range_t, _Rng&& _Range, const allocator_type& _Al) : _Mybase(key_compare(), _Al) {
|
|
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
|
|
}
|
|
#endif // _HAS_CXX23
|
|
|
|
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 <class... _Valty>
|
|
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 <class _Valty, enable_if_t<is_constructible_v<value_type, _Valty>, int> = 0>
|
|
iterator insert(_Valty&& _Val) {
|
|
return this->emplace(_STD forward<_Valty>(_Val));
|
|
}
|
|
|
|
template <class _Valty, enable_if_t<is_constructible_v<value_type, _Valty>, int> = 0>
|
|
iterator insert(const_iterator _Where, _Valty&& _Val) {
|
|
return this->emplace_hint(_Where, _STD forward<_Valty>(_Val));
|
|
}
|
|
|
|
multimap(initializer_list<value_type> _Ilist) : _Mybase(key_compare()) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
multimap(initializer_list<value_type> _Ilist, const key_compare& _Pred) : _Mybase(_Pred) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
multimap(initializer_list<value_type> _Ilist, const allocator_type& _Al) : _Mybase(key_compare(), _Al) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
multimap(initializer_list<value_type> _Ilist, const key_compare& _Pred, const allocator_type& _Al)
|
|
: _Mybase(_Pred, _Al) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
multimap& operator=(initializer_list<value_type> _Ilist) {
|
|
_Mybase::clear();
|
|
insert(_Ilist);
|
|
return *this;
|
|
}
|
|
|
|
using _Mybase::_Unchecked_begin;
|
|
using _Mybase::_Unchecked_end;
|
|
};
|
|
|
|
#if _HAS_CXX17
|
|
template <class _Iter, class _Pr = less<_Guide_key_t<_Iter>>, class _Alloc = allocator<_Guide_pair_t<_Iter>>,
|
|
enable_if_t<conjunction_v<_Is_iterator<_Iter>, 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 _Kty, class _Ty, class _Pr = less<_Kty>, class _Alloc = allocator<pair<const _Kty, _Ty>>,
|
|
enable_if_t<conjunction_v<negation<_Is_allocator<_Pr>>, _Is_allocator<_Alloc>>, int> = 0>
|
|
multimap(initializer_list<pair<_Kty, _Ty>>, _Pr = _Pr(), _Alloc = _Alloc()) -> multimap<_Kty, _Ty, _Pr, _Alloc>;
|
|
|
|
template <class _Iter, class _Alloc, enable_if_t<conjunction_v<_Is_iterator<_Iter>, _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 <class _Kty, class _Ty, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0>
|
|
multimap(initializer_list<pair<_Kty, _Ty>>, _Alloc) -> multimap<_Kty, _Ty, less<_Kty>, _Alloc>;
|
|
|
|
#if _HAS_CXX23
|
|
template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>,
|
|
_Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>>
|
|
requires (!_Allocator_for_container<_Pr>)
|
|
multimap(from_range_t, _Rng&&, _Pr = _Pr(),
|
|
_Alloc = _Alloc()) -> multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>;
|
|
|
|
template <_RANGES input_range _Rng, _Allocator_for_container _Alloc>
|
|
multimap(from_range_t, _Rng&&,
|
|
_Alloc) -> multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, less<_Range_key_type<_Rng>>, _Alloc>;
|
|
#endif // _HAS_CXX23
|
|
#endif // _HAS_CXX17
|
|
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator==(
|
|
const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return _Left.size() == _Right.size()
|
|
&& _STD equal(_Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin());
|
|
}
|
|
|
|
#if _HAS_CXX20
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD _Synth_three_way_result<pair<const _Kty, _Ty>> operator<=>(
|
|
const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return _STD lexicographical_compare_three_way(_Left._Unchecked_begin(), _Left._Unchecked_end_iter(),
|
|
_Right._Unchecked_begin(), _Right._Unchecked_end_iter(), _Synth_three_way{});
|
|
}
|
|
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator!=(
|
|
const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return !(_Left == _Right);
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator<(
|
|
const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return _STD lexicographical_compare(
|
|
_Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin(), _Right._Unchecked_end_iter());
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator>(
|
|
const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return _Right < _Left;
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator<=(
|
|
const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return !(_Right < _Left);
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
_NODISCARD bool operator>=(
|
|
const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) {
|
|
return !(_Left < _Right);
|
|
}
|
|
#endif // ^^^ !_HAS_CXX20 ^^^
|
|
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
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
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Keylt, class _Alloc, class _Pr>
|
|
multimap<_Kty, _Ty, _Keylt, _Alloc>::size_type erase_if(multimap<_Kty, _Ty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
|
|
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
|
|
}
|
|
#endif // _HAS_CXX20
|
|
|
|
#if _HAS_CXX17
|
|
namespace pmr {
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr = less<_Kty>>
|
|
using map = _STD map<_Kty, _Ty, _Pr, polymorphic_allocator<pair<const _Kty, _Ty>>>;
|
|
|
|
_EXPORT_STD template <class _Kty, class _Ty, class _Pr = less<_Kty>>
|
|
using multimap = _STD multimap<_Kty, _Ty, _Pr, polymorphic_allocator<pair<const _Kty, _Ty>>>;
|
|
} // 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_
|