зеркало из https://github.com/microsoft/STL.git
465 строки
18 KiB
C++
465 строки
18 KiB
C++
// hash_map extension header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef _HASH_MAP_
|
|
#define _HASH_MAP_
|
|
#include <yvals_core.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
#include <xhash>
|
|
|
|
#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
|
|
|
|
#ifndef _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
|
|
#error <hash_map> is deprecated and will be REMOVED. Please use <unordered_map>. You can define \
|
|
_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS to suppress this error.
|
|
#endif // _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
|
|
|
|
namespace stdext {
|
|
using _STD allocator;
|
|
using _STD enable_if_t;
|
|
using _STD is_constructible_v;
|
|
using _STD pair;
|
|
using _STD swap;
|
|
using _STD _Hash;
|
|
using _STD _Is_nothrow_swappable;
|
|
using _STD _Xout_of_range;
|
|
|
|
template <class _Kty, // key type
|
|
class _Ty, // mapped type
|
|
class _Tr, // comparator predicate type
|
|
class _Alloc, // actual allocator type (should be value allocator)
|
|
bool _Mfl> // true if multiple equivalent keys are permitted
|
|
class _Hmap_traits : public _Tr { // traits required to make _Hash behave like a map
|
|
public:
|
|
using key_type = _Kty;
|
|
using value_type = pair<const _Kty, _Ty>;
|
|
using _Mutable_value_type = pair<_Kty, _Ty>;
|
|
using key_compare = _Tr;
|
|
using allocator_type = _Alloc;
|
|
#if _HAS_CXX17
|
|
using node_type =
|
|
_STD _Node_handle<_STD _List_node<value_type, typename _STD allocator_traits<_Alloc>::void_pointer>, _Alloc,
|
|
_STD _Node_handle_map_base, _Kty, _Ty>;
|
|
#endif // _HAS_CXX17
|
|
|
|
static constexpr bool _Multi = _Mfl;
|
|
static constexpr bool _Standard = false;
|
|
|
|
template <class... _Args>
|
|
using _In_place_key_extractor = _STD _In_place_key_extract_map<_Kty, _Args...>;
|
|
template <class>
|
|
using _Deduce_key = const _Kty&;
|
|
using key_equal = _Tr;
|
|
|
|
_Hmap_traits() = default;
|
|
|
|
_Hmap_traits(const _Tr& _Traits) noexcept(_STD is_nothrow_copy_constructible_v<_Tr>) : _Tr(_Traits) {}
|
|
|
|
class value_compare {
|
|
public:
|
|
using first_argument_type = value_type;
|
|
using second_argument_type = value_type;
|
|
using result_type = bool;
|
|
|
|
_NODISCARD bool operator()(const value_type& _Left, const value_type& _Right) const
|
|
noexcept(noexcept(_Keycompobj(_Left.first, _Right.first))) {
|
|
// test if _Left precedes _Right by comparing just keys
|
|
return _Keycompobj(_Left.first, _Right.first);
|
|
}
|
|
|
|
value_compare(const key_compare& _Keycomparg) noexcept(_STD is_nothrow_copy_constructible_v<key_compare>)
|
|
: _Keycompobj(_Keycomparg) {}
|
|
|
|
key_compare _Keycompobj;
|
|
};
|
|
|
|
template <class _Ty1, class _Ty2>
|
|
_NODISCARD static const _Kty& _Kfn(const pair<_Ty1, _Ty2>& _Val) noexcept { // extract key from element value
|
|
return _Val.first;
|
|
}
|
|
|
|
_NODISCARD float& _Get_max_bucket_size() noexcept {
|
|
return _Max_buckets;
|
|
}
|
|
|
|
_NODISCARD const float& _Get_max_bucket_size() const noexcept {
|
|
return _Max_buckets;
|
|
}
|
|
|
|
void swap(_Hmap_traits& _Rhs) noexcept(_Is_nothrow_swappable<_Tr>::value) {
|
|
using _STD swap;
|
|
swap(static_cast<_Tr&>(*this), static_cast<_Tr&>(_Rhs)); // intentional ADL
|
|
_STD swap(_Max_buckets, _Rhs._Max_buckets);
|
|
}
|
|
|
|
float _Max_buckets = 0.0F; // current maximum bucket size
|
|
};
|
|
|
|
template <class _Kty, class _Ty, class _Tr = hash_compare<_Kty, _STD less<_Kty>>,
|
|
class _Alloc = allocator<pair<const _Kty, _Ty>>>
|
|
class hash_map : public _Hash<_Hmap_traits<_Kty, _Ty, _Tr, _Alloc, false>> {
|
|
// hash table of {key, mapped} values, unique keys
|
|
public:
|
|
using _Mybase = _Hash<_Hmap_traits<_Kty, _Ty, _Tr, _Alloc, false>>;
|
|
using key_type = _Kty;
|
|
using mapped_type = _Ty;
|
|
using referent_type = _Ty;
|
|
using key_compare = _Tr;
|
|
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 _Alnode = typename _Mybase::_Alnode;
|
|
using _Alnode_traits = typename _Mybase::_Alnode_traits;
|
|
#if _HAS_CXX17
|
|
using insert_return_type = _STD _Insert_return_type<iterator, typename _Mybase::node_type>;
|
|
#endif // _HAS_CXX17
|
|
|
|
hash_map() : _Mybase(key_compare(), allocator_type()) {}
|
|
|
|
explicit hash_map(const allocator_type& _Al) : _Mybase(key_compare(), _Al) {}
|
|
|
|
hash_map(const hash_map& _Right)
|
|
: _Mybase(_Right, _Alnode_traits::select_on_container_copy_construction(_Right._Getal())) {}
|
|
|
|
hash_map(const hash_map& _Right, const allocator_type& _Al) : _Mybase(_Right, _Al) {}
|
|
|
|
explicit hash_map(const key_compare& _Traits) : _Mybase(_Traits, allocator_type()) {}
|
|
|
|
hash_map(const key_compare& _Traits, const allocator_type& _Al) : _Mybase(_Traits, _Al) {}
|
|
|
|
template <class _Iter>
|
|
hash_map(_Iter _First, _Iter _Last) : _Mybase(key_compare(), allocator_type()) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
hash_map(_Iter _First, _Iter _Last, const key_compare& _Traits) : _Mybase(_Traits, allocator_type()) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
hash_map(_Iter _First, _Iter _Last, const key_compare& _Traits, const allocator_type& _Al)
|
|
: _Mybase(_Traits, _Al) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
hash_map& operator=(const hash_map& _Right) {
|
|
_Mybase::operator=(_Right);
|
|
return *this;
|
|
}
|
|
|
|
hash_map(hash_map&& _Right) : _Mybase(_STD move(_Right)) {}
|
|
|
|
hash_map(hash_map&& _Right, const allocator_type& _Al) : _Mybase(_STD move(_Right), _Al) {}
|
|
|
|
hash_map& operator=(hash_map&& _Right) noexcept(noexcept(_Mybase::operator=(_STD move(_Right)))) {
|
|
_Mybase::operator=(_STD move(_Right));
|
|
return *this;
|
|
}
|
|
|
|
mapped_type& operator[](key_type&& _Keyval) {
|
|
return this->_Try_emplace(_STD move(_Keyval)).first->_Myval.second;
|
|
}
|
|
|
|
void swap(hash_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));
|
|
}
|
|
|
|
hash_map(_STD initializer_list<value_type> _Ilist) : _Mybase(key_compare(), allocator_type()) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
hash_map(_STD initializer_list<value_type> _Ilist, const key_compare& _Pred)
|
|
: _Mybase(_Pred, allocator_type()) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
hash_map(_STD initializer_list<value_type> _Ilist, const key_compare& _Pred, const allocator_type& _Al)
|
|
: _Mybase(_Pred, _Al) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
hash_map& operator=(_STD initializer_list<value_type> _Ilist) {
|
|
this->clear();
|
|
insert(_Ilist);
|
|
return *this;
|
|
}
|
|
|
|
mapped_type& operator[](const key_type& _Keyval) {
|
|
return this->_Try_emplace(_Keyval).first->_Myval.second;
|
|
}
|
|
|
|
_NODISCARD mapped_type& at(const key_type& _Keyval) {
|
|
const auto _Target = this->_Find_last(_Keyval, this->_Traitsobj(_Keyval));
|
|
if (_Target._Duplicate) {
|
|
return _Target._Duplicate->_Myval.second;
|
|
}
|
|
|
|
_Xout_of_range("invalid hash_map<K, T> key");
|
|
}
|
|
|
|
_NODISCARD const mapped_type& at(const key_type& _Keyval) const {
|
|
const auto _Target = this->_Find_last(_Keyval, this->_Traitsobj(_Keyval));
|
|
if (_Target._Duplicate) {
|
|
return _Target._Duplicate->_Myval.second;
|
|
}
|
|
|
|
_Xout_of_range("invalid hash_map<K, T> key");
|
|
}
|
|
|
|
using reverse_iterator = _STD reverse_iterator<iterator>;
|
|
using const_reverse_iterator = _STD reverse_iterator<const_iterator>;
|
|
|
|
_NODISCARD reverse_iterator rbegin() noexcept {
|
|
return reverse_iterator(this->end());
|
|
}
|
|
|
|
_NODISCARD const_reverse_iterator rbegin() const noexcept {
|
|
return const_reverse_iterator(this->end());
|
|
}
|
|
|
|
_NODISCARD reverse_iterator rend() noexcept {
|
|
return reverse_iterator(this->begin());
|
|
}
|
|
|
|
_NODISCARD const_reverse_iterator rend() const noexcept {
|
|
return const_reverse_iterator(this->begin());
|
|
}
|
|
|
|
_NODISCARD const_reverse_iterator crbegin() const noexcept {
|
|
return rbegin();
|
|
}
|
|
|
|
_NODISCARD const_reverse_iterator crend() const noexcept {
|
|
return rend();
|
|
}
|
|
|
|
_NODISCARD key_compare key_comp() const {
|
|
return this->_Traitsobj;
|
|
}
|
|
|
|
_NODISCARD value_compare value_comp() const {
|
|
return value_compare(key_comp());
|
|
}
|
|
|
|
using _Mybase::_Unchecked_begin;
|
|
using _Mybase::_Unchecked_end;
|
|
};
|
|
|
|
template <class _Kty, class _Ty, class _Tr, class _Alloc>
|
|
void swap(hash_map<_Kty, _Ty, _Tr, _Alloc>& _Left, hash_map<_Kty, _Ty, _Tr, _Alloc>& _Right) noexcept(
|
|
noexcept(_Left.swap(_Right))) {
|
|
_Left.swap(_Right);
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Tr, class _Alloc>
|
|
_NODISCARD bool operator==(
|
|
const hash_map<_Kty, _Ty, _Tr, _Alloc>& _Left, const hash_map<_Kty, _Ty, _Tr, _Alloc>& _Right) {
|
|
return _STD _Hash_equal(_Left, _Right);
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Tr, class _Alloc>
|
|
_NODISCARD bool operator!=(
|
|
const hash_map<_Kty, _Ty, _Tr, _Alloc>& _Left, const hash_map<_Kty, _Ty, _Tr, _Alloc>& _Right) {
|
|
return !(_Left == _Right);
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Tr = hash_compare<_Kty, _STD less<_Kty>>,
|
|
class _Alloc = allocator<pair<const _Kty, _Ty>>>
|
|
class hash_multimap : public _Hash<_Hmap_traits<_Kty, _Ty, _Tr, _Alloc, true>> {
|
|
// hash table of {key, mapped} values, non-unique keys
|
|
public:
|
|
using _Mybase = _Hash<_Hmap_traits<_Kty, _Ty, _Tr, _Alloc, true>>;
|
|
using key_type = _Kty;
|
|
using mapped_type = _Ty;
|
|
using referent_type = _Ty; // old name, magically gone
|
|
using key_compare = _Tr;
|
|
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 _Alnode = typename _Mybase::_Alnode;
|
|
using _Alnode_traits = typename _Mybase::_Alnode_traits;
|
|
|
|
hash_multimap() : _Mybase(key_compare(), allocator_type()) {}
|
|
|
|
explicit hash_multimap(const allocator_type& _Al) : _Mybase(key_compare(), _Al) {}
|
|
|
|
hash_multimap(const hash_multimap& _Right)
|
|
: _Mybase(_Right, _Alnode_traits::select_on_container_copy_construction(_Right._Getal())) {}
|
|
|
|
hash_multimap(const hash_multimap& _Right, const allocator_type& _Al) : _Mybase(_Right, _Al) {}
|
|
|
|
explicit hash_multimap(const key_compare& _Traits) : _Mybase(_Traits, allocator_type()) {}
|
|
|
|
hash_multimap(const key_compare& _Traits, const allocator_type& _Al) : _Mybase(_Traits, _Al) {}
|
|
|
|
template <class _Iter>
|
|
hash_multimap(_Iter _First, _Iter _Last) : _Mybase(key_compare(), allocator_type()) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
hash_multimap(_Iter _First, _Iter _Last, const key_compare& _Traits) : _Mybase(_Traits, allocator_type()) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
template <class _Iter>
|
|
hash_multimap(_Iter _First, _Iter _Last, const key_compare& _Traits, const allocator_type& _Al)
|
|
: _Mybase(_Traits, _Al) {
|
|
insert(_First, _Last);
|
|
}
|
|
|
|
hash_multimap& operator=(const hash_multimap& _Right) {
|
|
_Mybase::operator=(_Right);
|
|
return *this;
|
|
}
|
|
|
|
hash_multimap(hash_multimap&& _Right) : _Mybase(_STD move(_Right)) {}
|
|
|
|
hash_multimap(hash_multimap&& _Right, const allocator_type& _Al) : _Mybase(_STD move(_Right), _Al) {}
|
|
|
|
hash_multimap& operator=(hash_multimap&& _Right) noexcept(noexcept(_Mybase::operator=(_STD move(_Right)))) {
|
|
_Mybase::operator=(_STD move(_Right));
|
|
return *this;
|
|
}
|
|
|
|
void swap(hash_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));
|
|
}
|
|
|
|
hash_multimap(_STD initializer_list<value_type> _Ilist) : _Mybase(key_compare(), allocator_type()) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
hash_multimap(_STD initializer_list<value_type> _Ilist, const key_compare& _Pred)
|
|
: _Mybase(_Pred, allocator_type()) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
hash_multimap(_STD initializer_list<value_type> _Ilist, const key_compare& _Pred, const allocator_type& _Al)
|
|
: _Mybase(_Pred, _Al) {
|
|
insert(_Ilist);
|
|
}
|
|
|
|
hash_multimap& operator=(_STD initializer_list<value_type> _Ilist) {
|
|
this->clear();
|
|
insert(_Ilist);
|
|
return *this;
|
|
}
|
|
|
|
using reverse_iterator = _STD reverse_iterator<iterator>;
|
|
using const_reverse_iterator = _STD reverse_iterator<const_iterator>;
|
|
|
|
_NODISCARD reverse_iterator rbegin() noexcept {
|
|
return reverse_iterator(this->end());
|
|
}
|
|
|
|
_NODISCARD const_reverse_iterator rbegin() const noexcept {
|
|
return const_reverse_iterator(this->end());
|
|
}
|
|
|
|
_NODISCARD reverse_iterator rend() noexcept {
|
|
return reverse_iterator(this->begin());
|
|
}
|
|
|
|
_NODISCARD const_reverse_iterator rend() const noexcept {
|
|
return const_reverse_iterator(this->begin());
|
|
}
|
|
|
|
_NODISCARD const_reverse_iterator crbegin() const noexcept {
|
|
return rbegin();
|
|
}
|
|
|
|
_NODISCARD const_reverse_iterator crend() const noexcept {
|
|
return rend();
|
|
}
|
|
|
|
_NODISCARD key_compare key_comp() const {
|
|
return this->_Traitsobj;
|
|
}
|
|
|
|
_NODISCARD value_compare value_comp() const {
|
|
return value_compare(key_comp());
|
|
}
|
|
|
|
using _Mybase::_Unchecked_begin;
|
|
using _Mybase::_Unchecked_end;
|
|
};
|
|
|
|
template <class _Kty, class _Ty, class _Tr, class _Alloc>
|
|
void swap(hash_multimap<_Kty, _Ty, _Tr, _Alloc>& _Left, hash_multimap<_Kty, _Ty, _Tr, _Alloc>& _Right) noexcept(
|
|
noexcept(_Left.swap(_Right))) {
|
|
_Left.swap(_Right);
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Tr, class _Alloc>
|
|
_NODISCARD bool operator==(
|
|
const hash_multimap<_Kty, _Ty, _Tr, _Alloc>& _Left, const hash_multimap<_Kty, _Ty, _Tr, _Alloc>& _Right) {
|
|
return _STD _Hash_equal(_Left, _Right);
|
|
}
|
|
|
|
template <class _Kty, class _Ty, class _Tr, class _Alloc>
|
|
_NODISCARD bool operator!=(
|
|
const hash_multimap<_Kty, _Ty, _Tr, _Alloc>& _Left, const hash_multimap<_Kty, _Ty, _Tr, _Alloc>& _Right) {
|
|
return !(_Left == _Right);
|
|
}
|
|
} // namespace stdext
|
|
_STD_BEGIN
|
|
using _STDEXT hash_map;
|
|
using _STDEXT hash_multimap;
|
|
_STD_END
|
|
|
|
#pragma pop_macro("new")
|
|
_STL_RESTORE_CLANG_WARNINGS
|
|
#pragma warning(pop)
|
|
#pragma pack(pop)
|
|
#endif // _STL_COMPILER_PREPROCESSOR
|
|
#endif // _HASH_MAP_
|