21 constexpr
bool operator()(
const T &lhs,
const T &rhs)
const 28 template <
typename KeyT,
typename HashT = std::hash<KeyT>,
typename EqT = HashSetEqualTo<KeyT>>
35 using size_type = size_t;
36 using value_type = KeyT;
37 using reference = KeyT&;
38 using const_reference =
const KeyT&;
43 using iterator_category = std::forward_iterator_tag;
44 using difference_type = size_t;
45 using distance_type = size_t;
46 using value_type = KeyT;
47 using pointer = value_type*;
48 using reference = value_type&;
52 iterator(
MyType* hash_set,
size_t bucket) : _set(hash_set), _bucket(bucket)
58 this->goto_next_element();
64 size_t old_index = _bucket;
65 this->goto_next_element();
69 reference operator*()
const 71 return _set->_keys[_bucket];
74 pointer operator->()
const 76 return _set->_keys + _bucket;
79 bool operator==(
const iterator& rhs)
const 81 DCHECK_EQ_F(_set, rhs._set);
82 return this->_bucket == rhs._bucket;
85 bool operator!=(
const iterator& rhs)
const 87 DCHECK_EQ_F(_set, rhs._set);
88 return this->_bucket != rhs._bucket;
92 void goto_next_element()
94 DCHECK_LT_F(_bucket, _set->_num_buckets);
97 }
while (_bucket < _set->_num_buckets && _set->_states[_bucket] != State::FILLED);
110 using iterator_category = std::forward_iterator_tag;
111 using difference_type = size_t;
112 using distance_type = size_t;
113 using value_type =
const KeyT;
114 using pointer = value_type*;
115 using reference = value_type&;
129 this->goto_next_element();
135 size_t old_index = _bucket;
136 this->goto_next_element();
140 reference operator*()
const 142 return _set->_keys[_bucket];
145 pointer operator->()
const 147 return _set->_keys + _bucket;
152 DCHECK_EQ_F(_set, rhs._set);
153 return this->_bucket == rhs._bucket;
158 DCHECK_EQ_F(_set, rhs._set);
159 return this->_bucket != rhs._bucket;
163 void goto_next_element()
165 DCHECK_LT_F(_bucket, _set->_num_buckets);
168 }
while (_bucket < _set->_num_buckets && _set->_states[_bucket] != State::FILLED);
184 reserve(other.size());
185 insert(cbegin(other), cend(other));
190 *
this = std::move(other);
196 reserve(other.size());
197 insert(cbegin(other), cend(other));
201 void operator=(
HashSet&& other)
208 for (
size_t bucket=0; bucket<_num_buckets; ++bucket) {
209 if (_states[bucket] == State::FILLED) {
210 _keys[bucket].~KeyT();
219 std::swap(_hasher, other._hasher);
220 std::swap(_eq, other._eq);
221 std::swap(_states, other._states);
222 std::swap(_keys, other._keys);
223 std::swap(_num_buckets, other._num_buckets);
224 std::swap(_num_filled, other._num_filled);
225 std::swap(_max_probe_length, other._max_probe_length);
226 std::swap(_mask, other._mask);
234 while (bucket<_num_buckets && _states[bucket] != State::FILLED) {
243 while (bucket<_num_buckets && _states[bucket] != State::FILLED) {
250 {
return iterator(
this, _num_buckets); }
262 return _num_filled==0;
265 size_t bucket_count()
const 274 auto bucket = this->find_filled_bucket(key);
275 if (bucket == (
size_t)-1) {
283 auto bucket = this->find_filled_bucket(key);
284 if (bucket == (
size_t)-1) {
290 bool contains(
const KeyT& k)
const 292 return find_filled_bucket(k) != (size_t)-1;
295 size_t count(
const KeyT& k)
const 297 return find_filled_bucket(k) != (size_t)-1 ? 1 : 0;
306 std::pair<iterator, bool>
insert(
const KeyT& key)
310 auto bucket = find_or_allocate(key);
312 if (_states[bucket] == State::FILLED) {
313 return {
iterator(
this, bucket),
false };
315 _states[bucket] = State::FILLED;
316 new(_keys + bucket) KeyT(key);
318 return {
iterator(
this, bucket),
true };
326 std::pair<iterator, bool>
insert(KeyT&& key)
330 auto bucket = find_or_allocate(key);
332 if (_states[bucket] == State::FILLED) {
333 return {
iterator(
this, bucket),
false };
335 _states[bucket] = State::FILLED;
336 new(_keys + bucket) KeyT(std::move(key));
338 return {
iterator(
this, bucket),
true };
342 template<
class... Args>
343 std::pair<iterator, bool> emplace(Args&&... args)
345 return insert(KeyT(std::forward<Args>(args)...));
350 for (; begin != end; ++begin) {
358 DCHECK_F(!contains(key));
360 auto bucket = find_empty_bucket(key);
361 _states[bucket] = State::FILLED;
362 new(_keys + bucket) KeyT(std::move(key));
372 auto bucket = find_filled_bucket(key);
373 if (bucket != (
size_t)-1) {
374 _states[bucket] = State::ACTIVE;
375 _keys[bucket].~KeyT();
387 DCHECK_EQ_F(it._set,
this);
388 DCHECK_LT_F(it._bucket, _num_buckets);
389 _states[it._bucket] = State::ACTIVE;
390 _keys[it._bucket].~KeyT();
398 for (
size_t bucket=0; bucket<_num_buckets; ++bucket) {
399 if (_states[bucket] == State::FILLED) {
400 _states[bucket] = State::INACTIVE;
401 _keys[bucket].~KeyT();
405 _max_probe_length = -1;
411 size_t required_buckets = num_elems + num_elems/2 + 1;
412 if (required_buckets <= _num_buckets) {
415 size_t num_buckets = 4;
416 while (num_buckets < required_buckets) { num_buckets *= 2; }
418 auto new_states = (State*)malloc(num_buckets *
sizeof(State));
419 auto new_keys = (KeyT*)malloc(num_buckets *
sizeof(KeyT));
421 if (!new_states || !new_keys) {
424 throw std::bad_alloc();
428 auto old_num_buckets = _num_buckets;
429 auto old_states = _states;
430 auto old_keys = _keys;
433 _num_buckets = num_buckets;
434 _mask = _num_buckets - 1;
435 _states = new_states;
438 std::fill_n(_states, num_buckets, State::INACTIVE);
440 _max_probe_length = -1;
442 for (
size_t src_bucket=0; src_bucket<old_num_buckets; src_bucket++) {
443 if (old_states[src_bucket] == State::FILLED) {
444 auto& src = old_keys[src_bucket];
446 auto dst_bucket = find_empty_bucket(src);
447 DCHECK_NE_F(dst_bucket, (
size_t)-1);
448 DCHECK_NE_F(_states[dst_bucket], State::FILLED);
449 _states[dst_bucket] = State::FILLED;
450 new(_keys + dst_bucket) KeyT(std::move(src));
465 void check_expand_need()
467 reserve(_num_filled + 1);
471 size_t find_filled_bucket(
const KeyT& key)
const 473 if (empty()) {
return (
size_t)-1; }
475 auto hash_value = _hasher(key);
476 for (
int offset=0; offset<=_max_probe_length; ++offset) {
477 auto bucket = (hash_value + offset) & _mask;
478 if (_states[bucket] == State::FILLED) {
479 if (_eq(_keys[bucket], key)) {
482 }
else if (_states[bucket] == State::INACTIVE) {
491 size_t find_or_allocate(
const KeyT& key)
493 auto hash_value = _hasher(key);
494 size_t hole = (size_t)-1;
496 for (; offset<=_max_probe_length; ++offset) {
497 auto bucket = (hash_value + offset) & _mask;
499 if (_states[bucket] == State::FILLED) {
500 if (_eq(_keys[bucket], key)) {
503 }
else if (_states[bucket] == State::INACTIVE) {
507 if (hole == (
size_t)-1) {
514 DCHECK_EQ_F(offset, _max_probe_length+1);
516 if (hole != (
size_t)-1) {
522 auto bucket = (hash_value + offset) & _mask;
524 if (_states[bucket] != State::FILLED) {
525 _max_probe_length = offset;
532 size_t find_empty_bucket(
const KeyT& key)
534 auto hash_value = _hasher(key);
535 for (
int offset=0; ; ++offset) {
536 auto bucket = (hash_value + offset) & _mask;
537 if (_states[bucket] != State::FILLED) {
538 if (offset > _max_probe_length) {
539 _max_probe_length = offset;
547 enum class State : uint8_t
556 State* _states =
nullptr;
557 KeyT* _keys =
nullptr;
558 size_t _num_buckets = 0;
559 size_t _num_filled = 0;
560 int _max_probe_length = -1;
Definition: hash_set.hpp:40
void insert_unique(KeyT key)
Same as above, but contains(key) MUST be false.
Definition: hash_set.hpp:356
iterator erase(iterator it)
Definition: hash_set.hpp:385
std::pair< iterator, bool > insert(KeyT &&key)
Definition: hash_set.hpp:326
A cache-friendly hash set with open addressing, linear probing and power-of-two capacity.
Definition: hash_set.hpp:29
void reserve(size_t num_elems)
Make room for this many elements.
Definition: hash_set.hpp:409
Definition: hash_set.hpp:107
std::pair< iterator, bool > insert(const KeyT &key)
Definition: hash_set.hpp:306
bool erase(const KeyT &key)
Definition: hash_set.hpp:370
like std::equal_to but no need to #include <functional>
Definition: hash_set.hpp:19
Definition: coroutine.hpp:18
void clear()
Remove all elements, keeping full capacity.
Definition: hash_set.hpp:396