2 * Copyright (c) 2018 Jaroslav Jindrak
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #ifndef LIBCPP_BITS_ADT_HASH_TABLE
30 #define LIBCPP_BITS_ADT_HASH_TABLE
32 #include <__bits/adt/list_node.hpp>
33 #include <__bits/adt/key_extractors.hpp>
34 #include <__bits/adt/hash_table_iterators.hpp>
35 #include <__bits/adt/hash_table_policies.hpp>
46 * To save code, we're going to implement one hash table
47 * for both unordered_map and unordered_set. To do this,
48 * we create one inner hash table that is oblivious to its
49 * held type (and uses a key extractor to get the key from it)
50 * and two proxies that either use plain Key type or a pair
51 * of a key and a value.
52 * Additionally, we will use policies to represent both single
53 * and multi variants of these containers at once.
54 * Note: I am aware the naming is very unimaginative here,
55 * not my strong side :)
59 class Value
, class Key
, class KeyExtractor
,
60 class Hasher
, class KeyEq
,
61 class Alloc
, class Size
,
62 class Iterator
, class ConstIterator
,
63 class LocalIterator
, class ConstLocalIterator
,
69 using value_type
= Value
;
71 using size_type
= Size
;
72 using allocator_type
= Alloc
;
73 using key_equal
= KeyEq
;
74 using hasher
= Hasher
;
75 using key_extract
= KeyExtractor
;
77 using iterator
= Iterator
;
78 using const_iterator
= ConstIterator
;
79 using local_iterator
= LocalIterator
;
80 using const_local_iterator
= ConstLocalIterator
;
82 using node_type
= list_node
<value_type
>;
84 using place_type
= tuple
<
85 hash_table_bucket
<value_type
, size_type
>*,
86 list_node
<value_type
>*, size_type
89 hash_table(size_type buckets
, float max_load_factor
= 1.f
)
90 : table_
{new hash_table_bucket
<value_type
, size_type
>[buckets
]()},
91 bucket_count_
{buckets
}, size_
{}, hasher_
{}, key_eq_
{},
92 key_extractor_
{}, max_load_factor_
{max_load_factor
}
95 hash_table(size_type buckets
, const hasher
& hf
, const key_equal
& eql
,
96 float max_load_factor
= 1.f
)
97 : table_
{new hash_table_bucket
<value_type
, size_type
>[buckets
]()},
98 bucket_count_
{buckets
}, size_
{}, hasher_
{hf
}, key_eq_
{eql
},
99 key_extractor_
{}, max_load_factor_
{max_load_factor
}
102 hash_table(const hash_table
& other
)
103 : hash_table
{other
.bucket_count_
, other
.hasher_
, other
.key_eq_
,
104 other
.max_load_factor_
}
106 for (const auto& x
: other
)
110 hash_table(hash_table
&& other
)
111 : table_
{other
.table_
}, bucket_count_
{other
.bucket_count_
},
112 size_
{other
.size_
}, hasher_
{move(other
.hasher_
)},
113 key_eq_
{move(other
.key_eq_
)}, key_extractor_
{move(other
.key_extractor_
)},
114 max_load_factor_
{other
.max_load_factor_
}
116 other
.table_
= nullptr;
117 other
.bucket_count_
= size_type
{};
118 other
.size_
= size_type
{};
119 other
.max_load_factor_
= 1.f
;
122 hash_table
& operator=(const hash_table
& other
)
124 hash_table tmp
{other
};
130 hash_table
& operator=(hash_table
&& other
)
132 hash_table tmp
{move(other
)};
138 bool empty() const noexcept
143 size_type
size() const noexcept
148 size_type
max_size(allocator_type
& alloc
)
150 return allocator_traits
<allocator_type
>::max_size(alloc
);
153 iterator
begin() noexcept
155 auto idx
= first_filled_bucket_();
157 table_
, idx
, bucket_count_
,
162 const_iterator
begin() const noexcept
167 iterator
end() noexcept
172 const_iterator
end() const noexcept
177 const_iterator
cbegin() const noexcept
179 auto idx
= first_filled_bucket_();
180 return const_iterator
{
181 table_
, idx
, bucket_count_
,
186 const_iterator
cend() const noexcept
188 return const_iterator
{};
191 template<class... Args
>
192 auto emplace(Args
&&... args
)
194 return Policy::emplace(*this, forward
<Args
>(args
)...);
197 auto insert(const value_type
& val
)
199 return Policy::insert(*this, val
);
202 auto insert(value_type
&& val
)
204 return Policy::insert(*this, forward
<value_type
>(val
));
207 size_type
erase(const key_type
& key
)
209 return Policy::erase(*this, key
);
212 iterator
erase(const_iterator it
)
217 auto node
= it
.node();
221 * Note: This way we will continue on the next bucket
222 * if this is the last element in its bucket.
224 iterator res
{table_
, idx
, size_
, node
};
227 if (table_
[idx
].head
== node
)
229 if (node
->next
!= node
)
230 table_
[idx
].head
= node
->next
;
232 table_
[idx
].head
= nullptr;
245 void clear() noexcept
247 for (size_type i
= 0; i
< bucket_count_
; ++i
)
252 void swap(hash_table
& other
)
253 noexcept(allocator_traits
<allocator_type
>::is_always_equal::value
&&
254 noexcept(std::swap(declval
<Hasher
&>(), declval
<Hasher
&>())) &&
255 noexcept(std::swap(declval
<KeyEq
&>(), declval
<KeyEq
&>())))
257 std::swap(table_
, other
.table_
);
258 std::swap(bucket_count_
, other
.bucket_count_
);
259 std::swap(size_
, other
.size_
);
260 std::swap(hasher_
, other
.hasher_
);
261 std::swap(key_eq_
, other
.key_eq_
);
262 std::swap(max_load_factor_
, other
.max_load_factor_
);
265 hasher
hash_function() const
270 key_equal
key_eq() const
275 iterator
find(const key_type
& key
)
277 auto idx
= get_bucket_idx_(key
);
278 auto head
= table_
[idx
].head
;
286 if (key_eq_(key
, key_extractor_(current
->value
)))
287 return iterator
{table_
, idx
, size_
, current
};
288 current
= current
->next
;
290 while (current
&& current
!= head
);
295 const_iterator
find(const key_type
& key
) const
297 auto idx
= get_bucket_idx_(key
);
298 auto head
= table_
[idx
].head
;
306 if (key_eq_(key
, key_extractor_(current
->value
)))
307 return iterator
{table_
, idx
, size_
, current
};
308 current
= current
->next
;
310 while (current
!= head
);
315 size_type
count(const key_type
& key
) const
317 return Policy::count(*this, key
);
320 pair
<iterator
, iterator
> equal_range(const key_type
& key
)
322 return Policy::equal_range(*this, key
);
325 pair
<const_iterator
, const_iterator
> equal_range(const key_type
& key
) const
327 return Policy::equal_range_const(*this, key
);
330 size_type
bucket_count() const noexcept
332 return bucket_count_
;
335 size_type
max_bucket_count() const noexcept
337 return numeric_limits
<size_type
>::max() /
338 sizeof(hash_table_bucket
<value_type
, size_type
>);
341 size_type
bucket_size(size_type n
) const
343 return table_
[n
].size();
346 size_type
bucket(const key_type
& key
) const
348 return get_bucket_idx_(key
);
351 local_iterator
begin(size_type n
)
353 return local_iterator
{table_
[n
].head
, table_
[n
].head
};
356 const_local_iterator
begin(size_type n
) const
361 local_iterator
end(size_type n
)
363 return local_iterator
{};
366 const_local_iterator
end(size_type n
) const
371 const_local_iterator
cbegin(size_type n
) const
373 return const_local_iterator
{table_
[n
].head
, table_
[n
].head
};
376 const_local_iterator
cend(size_type n
) const
378 return const_local_iterator
{};
381 float load_factor() const noexcept
383 return size_
/ static_cast<float>(bucket_count_
);
386 float max_load_factor() const noexcept
388 return max_load_factor_
;
391 void max_load_factor(float factor
)
394 max_load_factor_
= factor
;
399 void rehash(size_type count
)
401 if (count
< size_
/ max_load_factor_
)
402 count
= size_
/ max_load_factor_
;
405 * Note: If an exception is thrown, there
406 * is no effect. Since this is the only
407 * place where an exception (no mem) can
408 * be thrown and no changes to this have been
411 hash_table new_table
{count
, max_load_factor_
};
413 for (std::size_t i
= 0; i
< bucket_count_
; ++i
)
415 auto head
= table_
[i
].head
;
423 auto next
= current
->next
;
425 current
->next
= current
;
426 current
->prev
= current
;
428 auto where
= Policy::find_insertion_spot(
429 new_table
, key_extractor_(current
->value
)
433 * Note: We're rehashing, so we know each
434 * key can be inserted.
436 auto new_bucket
= get
<0>(where
);
437 auto new_successor
= get
<1>(where
);
440 new_successor
->append(current
);
442 new_bucket
->append(current
);
445 } while (current
!= head
);
447 table_
[i
].head
= nullptr;
450 new_table
.size_
= size_
;
453 delete[] new_table
.table_
;
454 new_table
.table_
= nullptr;
457 void reserve(size_type count
)
459 rehash(count
/ max_load_factor_
+ 1);
462 bool is_eq_to(const hash_table
& other
) const
464 if (size() != other
.size())
471 * For each key K we will check how many
472 * instances of K are there in the table.
473 * Then we will check if the count for K
474 * is equal to that amount.
480 while (key_eq_(key_extractor_(*it
), key_extractor_(*tmp
)))
487 auto other_cnt
= other
.count(key_extractor_(*it
));
488 if (cnt
!= other_cnt
)
491 it
= tmp
; // tmp is one past *it's key.
499 // Lists are deleted in ~hash_table_bucket.
504 place_type
find_insertion_spot(const key_type
& key
) const
506 return Policy::find_insertion_spot(*this, key
);
509 place_type
find_insertion_spot(key_type
&& key
) const
511 return Policy::find_insertion_spot(*this, key
);
514 const key_type
& get_key(const value_type
& val
) const
516 return key_extractor_(val
);
519 bool keys_equal(const key_type
& key
, const value_type
& val
)
521 return key_eq_(key
, key_extractor_(val
));
524 bool keys_equal(const key_type
& key
, const value_type
& val
) const
526 return key_eq_(key
, key_extractor_(val
));
529 hash_table_bucket
<value_type
, size_type
>* table()
534 hash_table_bucket
<value_type
, size_type
>* head(size_type idx
)
536 if (idx
< bucket_count_
)
537 return table_
[idx
]->head
;
542 void rehash_if_needed()
544 if (size_
> max_load_factor_
* bucket_count_
)
545 rehash(bucket_count_
* bucket_count_growth_factor_
);
548 void increment_size()
555 void decrement_size()
561 hash_table_bucket
<value_type
, size_type
>* table_
;
562 size_type bucket_count_
;
566 key_extract key_extractor_
;
567 float max_load_factor_
;
569 static constexpr float bucket_count_growth_factor_
{1.25};
571 size_type
get_bucket_idx_(const key_type
& key
) const
573 return hasher_(key
) % bucket_count_
;
576 size_type
first_filled_bucket_() const
579 while (res
< bucket_count_
)
581 if (table_
[res
].head
)
587 * Note: This is used for iterators,
588 * so we need to return a valid index.
589 * But since table_[0].head is nullptr
590 * we know that if we return 0 the
591 * created iterator will test as equal