19#include <initializer_list>
40template<
typename Value>
56 template<
typename T,
typename... Args>
57 requires(!std::same_as<Element, std::remove_cvref_t<T>>)
58 explicit constexpr Element(T&&
t, Args&&... args)
59 :
value(std::forward<T>(
t), std::forward<Args>(args)...)
73template<
typename Value>
82 , freeIdx_ (source.freeIdx_)
83 , capacity_(source.capacity_)
85 source.buf_ =
nullptr;
93 freeIdx_ = source.freeIdx_;
94 capacity_ = source.capacity_;
95 source.buf_ =
nullptr;
111 assert(idx.
idx < capacity_);
112 return buf_[idx.
idx];
116 return const_cast<Pool&
>(*this).
get(idx);
130 auto& elem =
get(idx);
131 freeIdx_ = elem.nextIdx;
132 new (&elem)
Elem(std::forward<V>(value), hash, nextIdx);
141 auto& elem =
get(idx);
143 elem.nextIdx = freeIdx_;
148 template<
typename... Args>
153 auto& elem =
get(idx);
154 freeIdx_ = elem.nextIdx;
155 new (&elem)
Elem(std::forward<Args>(args)...);
167 if (capacity_ >= count)
return;
168 if (capacity_ != 0) {
178 swap(x.buf_, y.buf_);
179 swap(x.freeIdx_, y.freeIdx_);
180 swap(x.capacity_, y.capacity_);
186 if (capacity_ != 0) {
187 growMore(2 * capacity_);
193 void growMore(
unsigned newCapacity)
197 if constexpr (std::is_trivially_move_constructible_v<Elem> &&
198 std::is_trivially_copyable_v<Elem>) {
199 newBuf =
static_cast<Elem*
>(realloc(oldBuf, newCapacity *
sizeof(Elem)));
200 if (!newBuf)
throw std::bad_alloc();
202 newBuf =
static_cast<Elem*
>(malloc(newCapacity *
sizeof(Elem)));
203 if (!newBuf)
throw std::bad_alloc();
205 for (
size_t i :
xrange(capacity_)) {
206 new (&newBuf[i]) Elem(std::move(oldBuf[i]));
212 for (
auto i :
xrange(capacity_, newCapacity - 1)) {
213 newBuf[i].nextIdx = PoolIndex{i + 1};
218 freeIdx_ = PoolIndex{capacity_};
219 capacity_ = newCapacity;
222 void growInitial(
unsigned newCapacity)
224 auto* newBuf =
static_cast<Elem*
>(malloc(newCapacity *
sizeof(Elem)));
225 if (!newBuf)
throw std::bad_alloc();
227 for (
auto i :
xrange(newCapacity - 1)) {
228 newBuf[i].nextIdx = PoolIndex{i + 1};
233 freeIdx_ = PoolIndex{0};
234 capacity_ = newCapacity;
238 Elem* buf_ =
nullptr;
240 unsigned capacity_ = 0;
244template<
typename Value,
typename Extractor>
246 decltype(std::declval<Extractor>()(std::declval<Value>()))>;
265template<
typename Value,
266 typename Extractor = std::identity,
267 typename Hasher = std::hash<hash_set_impl::ExtractedType<Value, Extractor>>,
268 typename Equal = std::equal_to<>>
278 template<
typename HashSet,
typename IValue>
289 template<
typename HashSet2,
typename IValue2>
291 : hashSet(other.hashSet), elemIdx(other.elemIdx) {}
293 template<
typename HashSet2,
typename IValue2>
295 hashSet = rhs.hashSet;
296 elemIdx = rhs.elemIdx;
301 assert((hashSet == rhs.hashSet) || !hashSet || !rhs.hashSet);
302 return elemIdx == rhs.elemIdx;
306 auto& oldElem = hashSet->pool.get(elemIdx);
307 elemIdx = oldElem.nextIdx;
309 unsigned tableIdx = oldElem.hash & hashSet->allocMask;
311 if (tableIdx == hashSet->allocMask)
break;
312 elemIdx = hashSet->table[++tableIdx];
324 return hashSet->pool.get(elemIdx).value;
327 return &hashSet->pool.get(elemIdx).value;
332 : hashSet(m), elemIdx(idx) {}
339 HashSet* hashSet =
nullptr;
348 Extractor extract_ = Extractor(),
349 Hasher hasher_ = Hasher(),
350 Equal equal_ = Equal())
363 for (
unsigned i = 0; i <= source.
allocMask; ++i) {
365 const auto& elem = source.
pool.get(idx);
373 :
table(source.table)
374 ,
pool(std::move(source.pool))
377 ,
extract(std::move(source.extract))
378 ,
hasher (std::move(source.hasher))
379 ,
equal (std::move(source.equal))
381 source.table =
nullptr;
382 source.allocMask = -1;
383 source.elemCount = 0;
386 explicit hash_set(std::initializer_list<Value> args)
388 reserve(narrow<unsigned>(args.size()));
400 if (&source ==
this)
return *
this;
405 for (
unsigned i = 0; i <= source.
allocMask; ++i) {
407 const auto& elem = source.
pool.get(idx);
420 table = source.table;
421 pool = std::move(source.pool);
424 extract = std::move(source.extract);
425 hasher = std::move(source.hasher);
426 equal = std::move(source.equal);
428 source.table =
nullptr;
429 source.allocMask = -1;
430 source.elemCount = 0;
441 std::pair<iterator, bool>
insert(V&& value)
443 return insert_impl<true, true>(std::forward<V>(value));
448 return insert_impl<false, true>(std::forward<V>(value));
453 return insert_impl<true, false>(std::forward<V>(value)).first;
458 return insert_impl<false, false>(std::forward<V>(value)).first;
461 template<
typename... Args>
462 std::pair<iterator, bool>
emplace(Args&&... args)
464 return emplace_impl<true, true>(std::forward<Args>(args)...);
466 template<
typename... Args>
469 return emplace_impl<false, true>(std::forward<Args>(args)...);
471 template<
typename... Args>
474 return emplace_impl<true, false>(std::forward<Args>(args)...).first;
476 template<
typename... Args>
479 return emplace_impl<false, false>(std::forward<Args>(args)...).first;
487 auto hash = unsigned(
hasher(key));
491 auto elemIdx = *prev;
492 auto& elem =
pool.get(elemIdx);
493 if (elem.hash != hash)
continue;
496 *prev = elem.nextIdx;
497 pool.destroy(elemIdx);
508 auto& elem =
pool.get(elemIdx);
510 auto* prev = &
table[tableIdx];
512 while (*prev != elemIdx) {
513 prev = &(
pool.get(*prev).nextIdx);
516 *prev = elem.nextIdx;
517 pool.destroy(elemIdx);
526 [[nodiscard]]
unsigned size()
const
535 for (
unsigned i = 0; i <=
allocMask; ++i) {
537 auto nextIdx =
pool.get(elemIdx).nextIdx;
538 pool.destroy(elemIdx);
562 for (
unsigned idx = 0; idx <=
allocMask; ++idx) {
574 for (
unsigned idx = 0; idx <=
allocMask; ++idx) {
594 unsigned poolCapacity =
pool.capacity();
595 unsigned tableCapacity = (
allocMask + 1) / 4 * 3;
596 return std::min(poolCapacity, tableCapacity);
607 if (oldCount >= newCount)
return;
618 }
while (oldCount < newCount);
625 swap(x.table, y.table);
626 swap(x.pool, y.pool);
627 swap(x.allocMask, y.allocMask);
628 swap(x.elemCount, y.elemCount);
629 swap(x.extract , y.extract);
630 swap(x.hasher , y.hasher);
631 swap(x.equal , y.equal);
644 static_assert(
sizeof(unsigned) ==
sizeof(uint32_t),
"only works for exactly 32 bit");
654 template<
bool CHECK_CAPACITY,
bool CHECK_DUPLICATE,
typename V>
661 if (!CHECK_CAPACITY || (
elemCount > 0)) {
662 primary =
table[tableIdx];
663 if constexpr (CHECK_DUPLICATE) {
664 for (
auto elemIdx = primary; elemIdx !=
invalidIndex; ) {
665 auto& elem =
pool.get(elemIdx);
666 if ((elem.hash == hash) &&
669 return std::pair(
iterator(
this, elemIdx),
false);
671 elemIdx = elem.nextIdx;
679 primary =
table[tableIdx];
683 auto idx =
pool.create(std::forward<V>(value), hash, primary);
684 table[tableIdx] = idx;
685 return std::pair(
iterator(
this, idx),
true);
688 template<
bool CHECK_CAPACITY,
bool CHECK_DUPLICATE,
typename... Args>
691 auto poolIdx =
pool.emplace(std::forward<Args>(args)...);
692 auto& poolElem =
pool.get(poolIdx);
698 if (!CHECK_CAPACITY || (
elemCount > 0)) {
699 primary =
table[tableIdx];
700 if constexpr (CHECK_DUPLICATE) {
701 for (
auto elemIdx = primary; elemIdx !=
invalidIndex; ) {
702 auto& elem =
pool.get(elemIdx);
703 if ((elem.hash == hash) &&
706 pool.destroy(poolIdx);
707 return std::pair(
iterator(
this, elemIdx),
false);
709 elemIdx = elem.nextIdx;
717 primary =
table[tableIdx];
721 poolElem.hash = hash;
722 poolElem.nextIdx = primary;
723 table[tableIdx] = poolIdx;
724 return std::pair(
iterator(
this, poolIdx),
true);
735 unsigned newCount = 2 * oldCount;
744 assert((oldCount & (oldCount - 1)) == 0);
745 for (
auto i :
xrange(oldCount)) {
746 auto* p0 = &
table[i];
747 auto* p1 = &
table[i + oldCount];
749 auto& elem =
pool.get(p);
750 if ((elem.hash & oldCount) == 0) {
768 auto hash = unsigned(
hasher(key));
771 auto& elem =
pool.get(elemIdx);
772 if ((elem.hash == hash) &&
776 elemIdx = elem.nextIdx;
Iter(HashSet *m, PoolIndex idx)
IValue & operator*() const
Iter & operator=(const Iter< HashSet2, IValue2 > &rhs)
Iter(const Iter< HashSet2, IValue2 > &other)
IValue * operator->() const
bool operator==(const Iter &rhs) const
PoolIndex getElementIdx() const
std::forward_iterator_tag iterator_category
PoolIndex emplace(Args &&... args)
unsigned capacity() const
friend void swap(Pool &x, Pool &y) noexcept
const Elem & get(PoolIndex idx) const
Pool(Pool &&source) noexcept
Elem & get(PoolIndex idx)
PoolIndex create(V &&value, unsigned hash, PoolIndex nextIdx)
void destroy(PoolIndex idx)
Pool & operator=(Pool &&source) noexcept
void reserve(unsigned count)
hash_set(unsigned initialSize=0, Extractor extract_=Extractor(), Hasher hasher_=Hasher(), Equal equal_=Equal())
std::pair< iterator, bool > insert_noCapacityCheck(V &&value)
friend auto end(hash_set &s)
void rehash(unsigned oldCount)
std::pair< iterator, bool > emplace_noCapacityCheck(Args &&... args)
friend void swap(hash_set &x, hash_set &y) noexcept
bool contains(const K &key) const
friend auto begin(hash_set &s)
hash_set(std::initializer_list< Value > args)
friend auto begin(const hash_set &s)
static unsigned nextPowerOf2(unsigned x)
const_iterator end() const
hash_set & operator=(const hash_set &source)
std::pair< iterator, bool > emplace(Args &&... args)
iterator insert_noCapacityCheck_noDuplicateCheck(V &&value)
const_iterator begin() const
hash_set(const hash_set &source)
iterator insert_noDuplicateCheck(V &&value)
PoolIndex locateElement(const K &key) const
Iter< const hash_set, const Value > const_iterator
hash_set(hash_set &&source) noexcept
iterator emplace_noDuplicateCheck(Args &&... args)
hash_set & operator=(hash_set &&source) noexcept
std::pair< iterator, bool > emplace_impl(Args &&... args)
iterator find(const K &key)
const_iterator find(const K &key) const
std::pair< iterator, bool > insert(V &&value)
Iter< hash_set, Value > iterator
void reserve(unsigned count)
friend auto end(const hash_set &s)
static constexpr auto invalidIndex
iterator emplace_noCapacityCheck_noDuplicateCheck(Args &&... args)
unsigned capacity() const
hash_set_impl::Pool< Value > pool
std::pair< iterator, bool > insert_impl(V &&value)
constexpr PoolIndex invalidIndex
typename std::remove_cvref_t< decltype(std::declval< Extractor >()(std::declval< Value >()))> ExtractedType
constexpr Element(V &&value_, unsigned hash_, PoolIndex nextIdx_)
constexpr Element(T &&t, Args &&... args)
constexpr Element()=default
constexpr bool operator==(const PoolIndex &) const =default
constexpr auto xrange(T e)