42 template <
typename KeyT,
typename HashT = agx::HashFn<KeyT>>
47 enum class State : uint8_t
80 this->goto_next_element();
87 this->goto_next_element();
114 void goto_next_element()
119 }
while (_bucket < _set->_num_buckets &&
_set->_states[
_bucket] != State::FILLED);
151 this->goto_next_element();
158 this->goto_next_element();
185 void goto_next_element()
190 }
while (_bucket < _set->_num_buckets &&
_set->_states[
_bucket] != State::FILLED);
212 *
this = std::move(other);
217 if (
this == &other ) {
235 for (
size_t bucket=0; bucket<_num_buckets; ++bucket) {
236 if (_states[bucket] == State::FILLED) {
237 _keys[bucket].~KeyT();
249 std::swap(_num_buckets, other._num_buckets);
250 std::swap(_num_filled, other._num_filled);
251 std::swap(_max_probe_length, other._max_probe_length);
260 while (bucket<_num_buckets && _states[bucket] != State::FILLED) {
269 while (bucket<_num_buckets && _states[bucket] != State::FILLED) {
276 {
return iterator(
this, _num_buckets); }
288 return _num_filled==0;
296 if (bucket == (
size_t)-1) {
305 if (bucket == (
size_t)-1) {
331 auto bucket = find_or_allocate(key);
333 if (_states[bucket] == State::FILLED) {
337 _states[bucket] = State::FILLED;
338 new(_keys + bucket) KeyT(key);
352 auto bucket = find_or_allocate(key);
354 if (_states[bucket] == State::FILLED) {
355 _keys[bucket] = std::move(key);
358 _states[bucket] = State::FILLED;
359 new(_keys + bucket) KeyT(std::move(key));
365 template<
class... Args>
368 return insert(KeyT(std::forward<Args>(args)...));
383 auto bucket = find_empty_bucket(key);
384 _states[bucket] = State::FILLED;
385 new(_keys + bucket) KeyT(std::move(key));
396 if (bucket != (
size_t)-1) {
420 for (
size_t bucket=0; bucket<_num_buckets; ++bucket) {
421 if (_states[bucket] == State::FILLED) {
422 _states[bucket] = State::INACTIVE;
423 _keys[bucket].~KeyT();
427 _max_probe_length = -1;
433 size_t required_buckets = num_elems + num_elems/2 + 1;
434 if (required_buckets <= _num_buckets) {
437 size_t num_buckets = 4;
438 while (num_buckets < required_buckets) { num_buckets *= 2; }
440 auto new_states = (State*)malloc(num_buckets *
sizeof(State));
441 auto new_keys = (KeyT*)malloc(num_buckets *
sizeof(KeyT));
443 if (!new_states || !new_keys) {
446 throw std::bad_alloc();
450 auto old_num_buckets = _num_buckets;
451 auto old_states = _states;
452 auto old_keys = _keys;
455 _num_buckets = num_buckets;
456 _mask = _num_buckets - 1;
457 _states = new_states;
460 std::fill_n(_states, num_buckets, State::INACTIVE);
462 _max_probe_length = -1;
464 for (
size_t src_bucket=0; src_bucket<old_num_buckets; src_bucket++) {
465 if (old_states[src_bucket] == State::FILLED) {
466 auto& src = old_keys[src_bucket];
468 auto dst_bucket = find_empty_bucket(src);
470 agxAssert(_states[dst_bucket] != State::FILLED);
471 _states[dst_bucket] = State::FILLED;
472 new(_keys + dst_bucket) KeyT(std::move(src));
487 template<
typename T2>
490 if (
empty()) {
return (
size_t)-1; }
492 auto hash_value = _hasher(key);
493 for (
int offset=0; offset<=_max_probe_length; ++offset) {
494 auto bucket = (hash_value + offset) & _mask;
498 if (_states[bucket] == State::INACTIVE) {
506 _states[bucket] = State::ACTIVE;
507 _keys[bucket].~KeyT();
513 void check_expand_need()
520 size_t find_or_allocate(
const KeyT& key)
522 auto hash_value = _hasher(key);
523 size_t hole = (size_t)-1;
525 for (; offset<=_max_probe_length; ++offset) {
526 auto bucket = (hash_value + offset) & _mask;
528 if (_states[bucket] == State::FILLED) {
532 }
else if (_states[bucket] == State::INACTIVE) {
536 if (hole == (
size_t)-1) {
544 agxAssert(offset == _max_probe_length+1);
546 if (hole != (
size_t)-1) {
552 auto bucket = (hash_value + offset) & _mask;
554 if (_states[bucket] != State::FILLED) {
555 _max_probe_length = offset;
562 size_t find_empty_bucket(
const KeyT& key)
564 auto hash_value = _hasher(key);
565 for (
int offset=0; ; ++offset) {
566 auto bucket = (hash_value + offset) & _mask;
567 if (_states[bucket] != State::FILLED) {
568 if (offset > _max_probe_length) {
569 _max_probe_length = offset;
578 State* _states =
nullptr;
579 KeyT* _keys =
nullptr;
580 size_t _num_buckets = 0;
581 size_t _num_filled = 0;
582 int _max_probe_length = -1;
586 template <
typename KeyT,
typename HashT>
592 template <
typename KeyT,
typename HashT>
599 template <
typename KeyT,
typename HashT>
605 template <
typename KeyT,
typename HashT>
619 template <
typename KeyT,
typename HashT = agx::HashFn<KeyT>>
632 template <
typename KeyT,
typename HashT>
637 typedef typename Implementation::iterator
iterator;
653 if (bucket == (
size_t)-1) {
656 return iterator(
this, bucket);
662 if (bucket == (
size_t)-1) {
665 return const_iterator(
this, bucket);
672 if (bucket != (
size_t)-1) {
const_iterator operator++(int)
pointer operator->() const
const_iterator(iterator proto)
bool operator!=(const const_iterator &rhs)
bool operator==(const const_iterator &rhs)
std::forward_iterator_tag iterator_category
const_iterator & operator++()
reference operator*() const
const_iterator(const MyType *hash_set, size_t bucket)
bool operator==(const iterator &rhs)
bool operator!=(const iterator &rhs)
pointer operator->() const
std::forward_iterator_tag iterator_category
iterator(MyType *hash_set, size_t bucket)
reference operator*() const
A cache-friendly hash set with open addressing, linear probing and power-of-two capacity.
size_t count(const KeyT &k) const
size_t find_filled_bucket(const T2 &key) const
void erase_bucket(size_t bucket)
const_iterator end() const
~LinearProbingHashSetImplementation()
LinearProbingHashSetImplementation & operator=(const LinearProbingHashSetImplementation &other)
void swap(LinearProbingHashSetImplementation &other)
LinearProbingHashSetImplementation & operator=(LinearProbingHashSetImplementation &&other)
iterator erase(iterator it)
LinearProbingHashSetImplementation(LinearProbingHashSetImplementation &&other)
LinearProbingHashSetImplementation()=default
bool erase(const KeyT &key)
const_iterator find(const KeyT &key) const
const_iterator begin() const
void insert_unique(KeyT &&key)
void insert(const_iterator begin, const_iterator end)
LinearProbingHashSetImplementation(const LinearProbingHashSetImplementation &other)
iterator find(const KeyT &key)
void reserve(size_t num_elems)
bool contains(const KeyT &k) const
iterator insert(KeyT &&key)
iterator insert(const KeyT &key)
const KeyT & const_reference
iterator emplace(Args &&... args)
Implementation::const_iterator const_iterator
Implementation::iterator iterator
const_iterator find(const KeyT *key) const
iterator find(const KeyT *key)
bool contains(const KeyT *key) const
LinearProbingHashSetImplementation< agx::ref_ptr< KeyT >, HashT > Implementation
bool erase(const KeyT *key)
Inheritance with partial specialization due to bug with ref_ptr containers.
LinearProbingHashSetImplementation< KeyT, HashT > Implementation
Smart pointer for handling referenced counted objects.
The agx namespace contains the dynamics/math part of the AGX Dynamics API.
LinearProbingHashSetImplementation< KeyT, HashT >::const_iterator cend(const LinearProbingHashSetImplementation< KeyT, HashT > &set)
LinearProbingHashSetImplementation< KeyT, HashT >::const_iterator cbegin(const LinearProbingHashSetImplementation< KeyT, HashT > &set)
LinearProbingHashSetImplementation< KeyT, HashT >::iterator end(LinearProbingHashSetImplementation< KeyT, HashT > &set)
LinearProbingHashSetImplementation< KeyT, HashT >::iterator begin(LinearProbingHashSetImplementation< KeyT, HashT > &set)
bool hashKeyEqual(const T1 &key1, const T2 &key2)
void swap(agx::Name &lhs, agx::Name &rhs)