// IWYU pragma: private, include "WAVM/Inline/HashSet.h" // You should only include this file indirectly by including HashMap.h. template bool HashSetIterator::operator!=(const HashSetIterator& other) { return bucket != other.bucket; } template bool HashSetIterator::operator==(const HashSetIterator& other) { return bucket == other.bucket; } template HashSetIterator::operator bool() const { return bucket < endBucket && bucket->hashAndOccupancy; } template void HashSetIterator::operator++() { do { ++bucket; } while(bucket < endBucket && !bucket->hashAndOccupancy); } template const Element& HashSetIterator::operator*() const { WAVM_ASSERT(bucket->hashAndOccupancy); return bucket->storage.get(); } template const Element* HashSetIterator::operator->() const { WAVM_ASSERT(bucket->hashAndOccupancy); return &bucket->storage.get(); } template HashSetIterator::HashSetIterator(const HashTableBucket* inBucket, const HashTableBucket* inEndBucket) : bucket(inBucket), endBucket(inEndBucket) { } template HashSet::HashSet(Uptr reserveNumElements) : table(reserveNumElements) { } template HashSet::HashSet(const std::initializer_list& initializerList) : table(initializerList.size()) { for(const Element& element : initializerList) { const bool result = add(element); WAVM_ASSERT(result); } } template bool HashSet::add(const Element& element) { const Uptr hash = ElementHashPolicy::getKeyHash(element); HashTableBucket& bucket = table.getBucketForAdd(hash, element); if(bucket.hashAndOccupancy != 0) { return false; } else { bucket.hashAndOccupancy = hash | HashTableBucket::isOccupiedMask; bucket.storage.construct(element); return true; } } template void HashSet::addOrFail(const Element& element) { const Uptr hash = ElementHashPolicy::getKeyHash(element); HashTableBucket& bucket = table.getBucketForAdd(hash, element); WAVM_ASSERT(!bucket.hashAndOccupancy); bucket.hashAndOccupancy = hash | HashTableBucket::isOccupiedMask; bucket.storage.construct(element); } template bool HashSet::remove(const Element& element) { return table.remove(ElementHashPolicy::getKeyHash(element), element); } template void HashSet::removeOrFail(const Element& element) { const bool removed = table.remove(ElementHashPolicy::getKeyHash(element), element); WAVM_ASSERT(removed); } template const Element& HashSet::operator[](const Element& element) const { const Uptr hash = ElementHashPolicy::getKeyHash(element); const HashTableBucket* bucket = table.getBucketForRead(hash, element); WAVM_ASSERT(bucket); if(!bucket) { // In addition to the assert, use WAVM_UNREACHABLE to ensure that GCC's -Wnull-dereference // warning isn't triggered because it thinks this function might return nullptr. WAVM_UNREACHABLE(); } WAVM_ASSERT(bucket->hashAndOccupancy == (hash | HashTableBucket::isOccupiedMask)); return bucket->storage.get(); } template bool HashSet::contains(const Element& element) const { const Uptr hash = ElementHashPolicy::getKeyHash(element); const HashTableBucket* bucket = table.getBucketForRead(hash, element); WAVM_ASSERT(!bucket || bucket->hashAndOccupancy == (hash | HashTableBucket::isOccupiedMask)); return bucket != nullptr; } template const Element* HashSet::get(const Element& element) const { const Uptr hash = ElementHashPolicy::getKeyHash(element); const HashTableBucket* bucket = table.getBucketForRead(hash, element); if(!bucket) { return nullptr; } else { WAVM_ASSERT(bucket->hashAndOccupancy == (hash | HashTableBucket::isOccupiedMask)); return &bucket->storage.get(); } } template void HashSet::clear() { table.clear(); } template HashSetIterator HashSet::begin() const { // Find the first occupied bucket. HashTableBucket* beginBucket = table.getBuckets(); HashTableBucket* endBucket = table.getBuckets() + table.numBuckets(); while(beginBucket < endBucket && !beginBucket->hashAndOccupancy) { ++beginBucket; }; return HashSetIterator(beginBucket, endBucket); } template HashSetIterator HashSet::end() const { return HashSetIterator(table.getBuckets() + table.numBuckets(), table.getBuckets() + table.numBuckets()); } template Uptr HashSet::size() const { return table.size(); } template void HashSet::analyzeSpaceUsage(Uptr& outTotalMemoryBytes, Uptr& outMaxProbeCount, F32& outOccupancy, F32& outAverageProbeCount) const { return table.analyzeSpaceUsage( outTotalMemoryBytes, outMaxProbeCount, outOccupancy, outAverageProbeCount); }