35#include <memory_resource>
36#include <shared_mutex>
45 template<
typename key_type,
typename value_type>
class unordered_map;
47 template<
typename map_iterator,
typename key_type,
typename value_type>
48 concept map_container_iterator_t = std::same_as<typename unordered_map<key_type, value_type>::iterator, std::decay_t<map_iterator>>;
50 template<
typename key_type_new,
typename value_type_new>
class unordered_map :
protected hash_policy<unordered_map<key_type_new, value_type_new>>,
51 protected jsonifier_internal::alloc_wrapper<std::pair<key_type_new, value_type_new>>,
52 protected object_compare {
54 using key_type = key_type_new;
55 using value_type = std::pair<key_type_new, value_type_new>;
56 using allocator_type = jsonifier_internal::alloc_wrapper<value_type>;
57 using allocator_traits = std::allocator_traits<allocator_type>;
58 using size_type = uint64_t;
59 using difference_type = int64_t;
60 using pointer =
typename allocator_traits::pointer;
61 using const_pointer =
typename allocator_traits::const_pointer;
62 using mapped_type = value_type_new;
63 using reference = value_type&;
64 using const_reference =
const value_type&;
65 using iterator = hash_iterator<unordered_map<key_type, mapped_type>>;
66 using const_iterator = hash_iterator<const unordered_map<key_type, mapped_type>>;
67 using object_compare = object_compare;
68 using hash_policy_new = hash_policy<unordered_map<key_type, mapped_type>>;
70 friend hash_policy_new;
72 friend const_iterator;
74 DCA_INLINE unordered_map(){};
76 DCA_INLINE unordered_map& operator=(unordered_map&& other)
noexcept {
84 DCA_INLINE unordered_map(unordered_map&& other)
noexcept {
85 *
this = std::move(other);
88 DCA_INLINE unordered_map& operator=(
const unordered_map& other) {
92 reserve(other.capacity());
93 for (
const auto& [key, value]: other) {
100 DCA_INLINE unordered_map(
const unordered_map& other) {
104 DCA_INLINE unordered_map(std::initializer_list<value_type> list) {
105 reserve(list.size());
106 for (
auto& value: list) {
107 emplace(std::move(value.first), std::move(value.second));
111 template<
typename... Args> iterator emplace(Args&&... value) {
112 return emplaceInternal(std::forward<Args>(value)...);
115 template<
typename key_type_newer> DCA_INLINE const_iterator find(key_type_newer&& key)
const {
117 auto currentIndex = hash_policy_new::indexForHash(key);
118 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
119 if (sentinelVector[currentIndex] > 0 && object_compare()(data[currentIndex].first, key)) {
120 return {
this, currentIndex };
127 template<
typename key_type_newer> DCA_INLINE iterator find(key_type_newer&& key) {
129 auto currentIndex = hash_policy_new::indexForHash(key);
130 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
131 if (sentinelVector[currentIndex] > 0 && object_compare()(data[currentIndex].first, key)) {
132 return {
this, currentIndex };
139 template<
typename key_type_newer> DCA_INLINE
const mapped_type& operator[](key_type_newer&& key)
const {
140 return emplaceInternal(key)->second;
143 template<
typename key_type_newer> DCA_INLINE mapped_type& operator[](key_type_newer&& key) {
144 return emplaceInternal(key)->second;
147 template<
typename key_type_newer> DCA_INLINE
const mapped_type& at(key_type_newer&& key)
const {
148 auto iter = find(std::forward<key_type_newer>(key));
150 throw std::runtime_error{
"Sorry, but an object by that key doesn't exist in this map." };
155 template<
typename key_type_newer> DCA_INLINE mapped_type& at(key_type_newer&& key) {
156 auto iter = find(std::forward<key_type_newer>(key));
158 throw std::runtime_error{
"Sorry, but an object by that key doesn't exist in this map." };
163 template<
typename key_type_newer> DCA_INLINE
bool contains(key_type_newer&& key)
const {
165 auto currentIndex = hash_policy_new::indexForHash(key);
166 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
167 if (sentinelVector[currentIndex] > 0 && object_compare()(data[currentIndex].first, key)) {
175 template<map_container_iterator_t<key_type, mapped_type> map_iterator> DCA_INLINE iterator erase(map_iterator&& iter) {
177 auto currentIndex =
static_cast<size_type
>(iter.getRawPtr() - data);
178 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
179 if (sentinelVector[currentIndex] > 0 && object_compare()(data[currentIndex], iter.operator*())) {
180 allocator_traits::destroy(*
this, data + currentIndex);
181 sentinelVector[currentIndex] = 0;
183 return {
this, ++currentIndex };
190 template<
typename key_type_newer> DCA_INLINE iterator erase(key_type_newer&& key) {
192 auto currentIndex = hash_policy_new::indexForHash(key);
193 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
194 if (sentinelVector[currentIndex] > 0 && object_compare()(data[currentIndex].first, key)) {
195 allocator_traits::destroy(*
this, data + currentIndex);
196 sentinelVector[currentIndex] = 0;
198 return {
this, ++currentIndex };
205 DCA_INLINE const_iterator begin()
const {
206 for (size_type x{ 0 }; x < capacityVal; ++x) {
207 if (sentinelVector.at(x) > 0) {
214 DCA_INLINE const_iterator end()
const {
218 DCA_INLINE iterator begin() {
219 for (size_type x{ 0 }; x < capacityVal; ++x) {
220 if (sentinelVector.at(x) > 0) {
227 DCA_INLINE iterator end() {
231 DCA_INLINE
bool full()
const {
232 return static_cast<float>(sizeVal) >=
static_cast<float>(capacityVal) * 0.90f;
235 DCA_INLINE size_type size()
const {
239 DCA_INLINE
bool empty()
const {
243 DCA_INLINE
void reserve(size_type sizeNew) {
247 DCA_INLINE
void swap(unordered_map& other) {
248 std::swap(maxLookAheadDistance, other.maxLookAheadDistance);
249 std::swap(sentinelVector, other.sentinelVector);
250 std::swap(capacityVal, other.capacityVal);
251 std::swap(sizeVal, other.sizeVal);
252 std::swap(data, other.data);
255 DCA_INLINE size_type capacity()
const {
259 DCA_INLINE
bool operator==(
const unordered_map& other)
const {
260 if (capacityVal != other.capacityVal || sizeVal != other.sizeVal || data != other.data) {
263 for (
auto iter01{ begin() }, iter02{ other.begin() }; iter01 != end(); ++iter01, ++iter02) {
264 if (!object_compare()(iter01.operator*().second, iter02.operator*().second)) {
271 DCA_INLINE
void clear() {
272 for (size_type x = 0; x < sentinelVector.size(); ++x) {
273 if (sentinelVector.at(x) > 0) {
274 allocator_traits::destroy(*
this, data + x);
275 sentinelVector.at(x) = 0;
281 DCA_INLINE ~unordered_map() {
286 jsonifier::vector<int8_t> sentinelVector{};
287 int8_t maxLookAheadDistance{ 0 };
288 size_type capacityVal{};
292 template<
typename key_type_newer,
typename... mapped_type_new> DCA_INLINE iterator emplaceInternal(key_type_newer&& key, mapped_type_new&&... value) {
293 if (full() || capacityVal == 0) {
294 resize(capacityVal + 1);
296 auto currentIndex = hash_policy_new::indexForHash(key);
297 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
298 if (sentinelVector[currentIndex] == 0) {
299 if constexpr ((( !std::is_void_v<mapped_type_new> ) || ...)) {
300 new (std::addressof(data[currentIndex])) value_type{ std::make_pair(std::forward<key_type_newer>(key), std::forward<mapped_type_new>(value)...) };
302 new (std::addressof(data[currentIndex])) value_type{ std::make_pair(std::forward<key_type_newer>(key), mapped_type{}) };
304 sentinelVector[currentIndex] = 1;
306 return {
this, currentIndex };
307 }
else if (sentinelVector[currentIndex] > 0 && object_compare()(data[currentIndex].first, key)) {
308 if constexpr ((( !std::is_void_v<mapped_type_new> ) || ...)) {
309 data[currentIndex].second = mapped_type{ std::forward<mapped_type_new>(value)... };
311 return {
this, currentIndex };
314 resize(capacityVal + 1);
315 return emplaceInternal(std::forward<key_type_newer>(key), std::forward<mapped_type_new>(value)...);
318 DCA_INLINE
void resize(size_type capacityNew) {
319 auto newSize = hash_policy_new::nextPowerOfTwo(capacityNew);
320 if (newSize > capacityVal) {
321 jsonifier::vector<int8_t> oldSentinelVector = std::move(sentinelVector);
322 auto oldMaxLookAheadDistance = maxLookAheadDistance;
323 auto oldCapacity = capacityVal;
324 auto oldSize = sizeVal;
326 maxLookAheadDistance = hash_policy_new::computeMaxLookAheadDistance(newSize);
328 data = allocator_traits::allocate(*
this, newSize + 1 + maxLookAheadDistance);
329 sentinelVector.resize(newSize + 1 + maxLookAheadDistance);
330 sentinelVector[newSize + maxLookAheadDistance] = -1;
331 capacityVal = newSize;
332 for (size_type x = 0, y = 0; y < oldSize; ++x) {
333 if (oldSentinelVector.at(x) > 0) {
335 emplaceInternal(std::move(oldPtr[x].first), std::move(oldPtr[x].second));
338 if (oldPtr && oldCapacity) {
339 allocator_traits::deallocate(*
this, oldPtr, oldCapacity + 1 + oldMaxLookAheadDistance);
344 DCA_INLINE
void reset() {
345 if (data && sizeVal > 0) {
346 for (uint64_t x = 0; x < sentinelVector.size(); ++x) {
347 if (sentinelVector.at(x) > 0) {
348 allocator_traits::destroy(*
this, data + x);
349 sentinelVector.at(x) = 0;
352 allocator_traits::deallocate(*
this, data, capacityVal + 1 + maxLookAheadDistance);
353 sentinelVector.clear();
The main namespace for the forward-facing interfaces.