122c22d61SSchrodinger ZHU Yifan //===-- Resizable Monotonic HashTable ---------------------------*- C++ -*-===// 281e3e7e5SSchrodinger ZHU Yifan // 381e3e7e5SSchrodinger ZHU Yifan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481e3e7e5SSchrodinger ZHU Yifan // See https://llvm.org/LICENSE.txt for license information. 581e3e7e5SSchrodinger ZHU Yifan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681e3e7e5SSchrodinger ZHU Yifan // 781e3e7e5SSchrodinger ZHU Yifan //===----------------------------------------------------------------------===// 881e3e7e5SSchrodinger ZHU Yifan 9330793c9SNick Desaulniers #ifndef LLVM_LIBC_SRC___SUPPORT_HASHTABLE_TABLE_H 10330793c9SNick Desaulniers #define LLVM_LIBC_SRC___SUPPORT_HASHTABLE_TABLE_H 1181e3e7e5SSchrodinger ZHU Yifan 1273aab2f6Slntue #include "include/llvm-libc-types/ENTRY.h" 131d894788SGuillaume Chatelet #include "src/__support/CPP/bit.h" // bit_ceil 1481e3e7e5SSchrodinger ZHU Yifan #include "src/__support/CPP/new.h" 1581e3e7e5SSchrodinger ZHU Yifan #include "src/__support/HashTable/bitmask.h" 1681e3e7e5SSchrodinger ZHU Yifan #include "src/__support/hash.h" 1781e3e7e5SSchrodinger ZHU Yifan #include "src/__support/macros/attributes.h" 18*5ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 1981e3e7e5SSchrodinger ZHU Yifan #include "src/__support/macros/optimization.h" 2081e3e7e5SSchrodinger ZHU Yifan #include "src/__support/memory_size.h" 2181e3e7e5SSchrodinger ZHU Yifan #include "src/string/memset.h" 2281e3e7e5SSchrodinger ZHU Yifan #include "src/string/strcmp.h" 2381e3e7e5SSchrodinger ZHU Yifan #include "src/string/strlen.h" 2481e3e7e5SSchrodinger ZHU Yifan #include <stddef.h> 2581e3e7e5SSchrodinger ZHU Yifan #include <stdint.h> 2681e3e7e5SSchrodinger ZHU Yifan 27*5ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 2881e3e7e5SSchrodinger ZHU Yifan namespace internal { 2981e3e7e5SSchrodinger ZHU Yifan 3081e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE uint8_t secondary_hash(uint64_t hash) { 3181e3e7e5SSchrodinger ZHU Yifan // top 7 bits of the hash. 3281e3e7e5SSchrodinger ZHU Yifan return static_cast<uint8_t>(hash >> 57); 3381e3e7e5SSchrodinger ZHU Yifan } 3481e3e7e5SSchrodinger ZHU Yifan 3581e3e7e5SSchrodinger ZHU Yifan // Probe sequence based on triangular numbers, which is guaranteed (since our 3681e3e7e5SSchrodinger ZHU Yifan // table size is a power of two) to visit every group of elements exactly once. 3781e3e7e5SSchrodinger ZHU Yifan // 3881e3e7e5SSchrodinger ZHU Yifan // A triangular probe has us jump by 1 more group every time. So first we 3981e3e7e5SSchrodinger ZHU Yifan // jump by 1 group (meaning we just continue our linear scan), then 2 groups 4081e3e7e5SSchrodinger ZHU Yifan // (skipping over 1 group), then 3 groups (skipping over 2 groups), and so on. 4181e3e7e5SSchrodinger ZHU Yifan // 4281e3e7e5SSchrodinger ZHU Yifan // If we set sizeof(Group) to be one unit: 4381e3e7e5SSchrodinger ZHU Yifan // T[k] = sum {1 + 2 + ... + k} = k * (k + 1) / 2 4481e3e7e5SSchrodinger ZHU Yifan // It is provable that T[k] mod 2^m generates a permutation of 4581e3e7e5SSchrodinger ZHU Yifan // 0, 1, 2, 3, ..., 2^m - 2, 2^m - 1 4681e3e7e5SSchrodinger ZHU Yifan // Detailed proof is available at: 4781e3e7e5SSchrodinger ZHU Yifan // https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/ 4881e3e7e5SSchrodinger ZHU Yifan struct ProbeSequence { 4981e3e7e5SSchrodinger ZHU Yifan size_t position; 5081e3e7e5SSchrodinger ZHU Yifan size_t stride; 5181e3e7e5SSchrodinger ZHU Yifan size_t entries_mask; 5281e3e7e5SSchrodinger ZHU Yifan 5381e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE size_t next() { 5481e3e7e5SSchrodinger ZHU Yifan position += stride; 5581e3e7e5SSchrodinger ZHU Yifan position &= entries_mask; 5681e3e7e5SSchrodinger ZHU Yifan stride += sizeof(Group); 5781e3e7e5SSchrodinger ZHU Yifan return position; 5881e3e7e5SSchrodinger ZHU Yifan } 5981e3e7e5SSchrodinger ZHU Yifan }; 6081e3e7e5SSchrodinger ZHU Yifan 6181e3e7e5SSchrodinger ZHU Yifan // The number of entries is at least group width: we do not 6281e3e7e5SSchrodinger ZHU Yifan // need to do the fixup when we set the control bytes. 6381e3e7e5SSchrodinger ZHU Yifan // The number of entries is at least 8: we don't have to worry 6481e3e7e5SSchrodinger ZHU Yifan // about special sizes when check the fullness of the table. 6581e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE size_t capacity_to_entries(size_t cap) { 6681e3e7e5SSchrodinger ZHU Yifan if (8 >= sizeof(Group) && cap < 8) 6781e3e7e5SSchrodinger ZHU Yifan return 8; 6881e3e7e5SSchrodinger ZHU Yifan if (16 >= sizeof(Group) && cap < 15) 6981e3e7e5SSchrodinger ZHU Yifan return 16; 7081e3e7e5SSchrodinger ZHU Yifan if (cap < sizeof(Group)) 7181e3e7e5SSchrodinger ZHU Yifan cap = sizeof(Group); 7281e3e7e5SSchrodinger ZHU Yifan // overflow is always checked in allocate() 731d894788SGuillaume Chatelet return cpp::bit_ceil(cap * 8 / 7); 7481e3e7e5SSchrodinger ZHU Yifan } 7581e3e7e5SSchrodinger ZHU Yifan 7681e3e7e5SSchrodinger ZHU Yifan // The heap memory layout for N buckets HashTable is as follows: 7781e3e7e5SSchrodinger ZHU Yifan // 7881e3e7e5SSchrodinger ZHU Yifan // ======================= 7981e3e7e5SSchrodinger ZHU Yifan // | N * Entry | 8081e3e7e5SSchrodinger ZHU Yifan // ======================= <- align boundary 8181e3e7e5SSchrodinger ZHU Yifan // | Header | 8286e99e11SSchrodinger ZHU Yifan // ======================= <- align boundary (for fast resize) 8381e3e7e5SSchrodinger ZHU Yifan // | (N + 1) * Byte | 8481e3e7e5SSchrodinger ZHU Yifan // ======================= 8581e3e7e5SSchrodinger ZHU Yifan // 8681e3e7e5SSchrodinger ZHU Yifan // The trailing group part is to make sure we can always load 8781e3e7e5SSchrodinger ZHU Yifan // a whole group of control bytes. 8881e3e7e5SSchrodinger ZHU Yifan 8981e3e7e5SSchrodinger ZHU Yifan struct HashTable { 9081e3e7e5SSchrodinger ZHU Yifan HashState state; 9181e3e7e5SSchrodinger ZHU Yifan size_t entries_mask; // number of buckets - 1 9281e3e7e5SSchrodinger ZHU Yifan size_t available_slots; // less than capacity 9381e3e7e5SSchrodinger ZHU Yifan private: 9481e3e7e5SSchrodinger ZHU Yifan // How many entries are there in the table. 9581e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE size_t num_of_entries() const { return entries_mask + 1; } 9681e3e7e5SSchrodinger ZHU Yifan 9786e99e11SSchrodinger ZHU Yifan // How many entries can we store in the table before resizing. 9886e99e11SSchrodinger ZHU Yifan LIBC_INLINE size_t full_capacity() const { return num_of_entries() / 8 * 7; } 9986e99e11SSchrodinger ZHU Yifan 10086e99e11SSchrodinger ZHU Yifan // The alignment of the whole memory area is the maximum of the alignment 10186e99e11SSchrodinger ZHU Yifan // among the following types: 10286e99e11SSchrodinger ZHU Yifan // - HashTable 10386e99e11SSchrodinger ZHU Yifan // - ENTRY 10486e99e11SSchrodinger ZHU Yifan // - Group 10586e99e11SSchrodinger ZHU Yifan LIBC_INLINE constexpr static size_t table_alignment() { 10686e99e11SSchrodinger ZHU Yifan size_t left_align = alignof(HashTable) > alignof(ENTRY) ? alignof(HashTable) 10786e99e11SSchrodinger ZHU Yifan : alignof(ENTRY); 10886e99e11SSchrodinger ZHU Yifan return left_align > alignof(Group) ? left_align : alignof(Group); 10986e99e11SSchrodinger ZHU Yifan } 11086e99e11SSchrodinger ZHU Yifan 11181e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE bool is_full() const { return available_slots == 0; } 11281e3e7e5SSchrodinger ZHU Yifan 11381e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE size_t offset_from_entries() const { 11481e3e7e5SSchrodinger ZHU Yifan size_t entries_size = num_of_entries() * sizeof(ENTRY); 1151d894788SGuillaume Chatelet return entries_size + 1161d894788SGuillaume Chatelet SafeMemSize::offset_to(entries_size, table_alignment()); 11781e3e7e5SSchrodinger ZHU Yifan } 11881e3e7e5SSchrodinger ZHU Yifan 11981e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE constexpr static size_t offset_to_groups() { 12086e99e11SSchrodinger ZHU Yifan size_t header_size = sizeof(HashTable); 12186e99e11SSchrodinger ZHU Yifan return header_size + SafeMemSize::offset_to(header_size, table_alignment()); 12281e3e7e5SSchrodinger ZHU Yifan } 12381e3e7e5SSchrodinger ZHU Yifan 12481e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE ENTRY &entry(size_t i) { 12581e3e7e5SSchrodinger ZHU Yifan return reinterpret_cast<ENTRY *>(this)[-i - 1]; 12681e3e7e5SSchrodinger ZHU Yifan } 12781e3e7e5SSchrodinger ZHU Yifan 12886e99e11SSchrodinger ZHU Yifan LIBC_INLINE const ENTRY &entry(size_t i) const { 12986e99e11SSchrodinger ZHU Yifan return reinterpret_cast<const ENTRY *>(this)[-i - 1]; 13086e99e11SSchrodinger ZHU Yifan } 13186e99e11SSchrodinger ZHU Yifan 13281e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE uint8_t &control(size_t i) { 13381e3e7e5SSchrodinger ZHU Yifan uint8_t *ptr = reinterpret_cast<uint8_t *>(this) + offset_to_groups(); 13481e3e7e5SSchrodinger ZHU Yifan return ptr[i]; 13581e3e7e5SSchrodinger ZHU Yifan } 13681e3e7e5SSchrodinger ZHU Yifan 13786e99e11SSchrodinger ZHU Yifan LIBC_INLINE const uint8_t &control(size_t i) const { 13886e99e11SSchrodinger ZHU Yifan const uint8_t *ptr = 13986e99e11SSchrodinger ZHU Yifan reinterpret_cast<const uint8_t *>(this) + offset_to_groups(); 14086e99e11SSchrodinger ZHU Yifan return ptr[i]; 14186e99e11SSchrodinger ZHU Yifan } 14286e99e11SSchrodinger ZHU Yifan 14381e3e7e5SSchrodinger ZHU Yifan // We duplicate a group of control bytes to the end. Thus, it is possible that 14481e3e7e5SSchrodinger ZHU Yifan // we need to set two control bytes at the same time. 14581e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE void set_ctrl(size_t index, uint8_t value) { 14681e3e7e5SSchrodinger ZHU Yifan size_t index2 = ((index - sizeof(Group)) & entries_mask) + sizeof(Group); 14781e3e7e5SSchrodinger ZHU Yifan control(index) = value; 14881e3e7e5SSchrodinger ZHU Yifan control(index2) = value; 14981e3e7e5SSchrodinger ZHU Yifan } 15081e3e7e5SSchrodinger ZHU Yifan 15186e99e11SSchrodinger ZHU Yifan LIBC_INLINE size_t find(const char *key, uint64_t primary) { 15286e99e11SSchrodinger ZHU Yifan uint8_t secondary = secondary_hash(primary); 15386e99e11SSchrodinger ZHU Yifan ProbeSequence sequence{static_cast<size_t>(primary), 0, entries_mask}; 15486e99e11SSchrodinger ZHU Yifan while (true) { 15586e99e11SSchrodinger ZHU Yifan size_t pos = sequence.next(); 15686e99e11SSchrodinger ZHU Yifan Group ctrls = Group::load(&control(pos)); 15786e99e11SSchrodinger ZHU Yifan IteratableBitMask masks = ctrls.match_byte(secondary); 15886e99e11SSchrodinger ZHU Yifan for (size_t i : masks) { 15986e99e11SSchrodinger ZHU Yifan size_t index = (pos + i) & entries_mask; 16086e99e11SSchrodinger ZHU Yifan ENTRY &entry = this->entry(index); 16186e99e11SSchrodinger ZHU Yifan if (LIBC_LIKELY(entry.key != nullptr && strcmp(entry.key, key) == 0)) 16286e99e11SSchrodinger ZHU Yifan return index; 16386e99e11SSchrodinger ZHU Yifan } 16486e99e11SSchrodinger ZHU Yifan BitMask available = ctrls.mask_available(); 16586e99e11SSchrodinger ZHU Yifan // Since there is no deletion, the first time we find an available slot 16686e99e11SSchrodinger ZHU Yifan // it is also ready to be used as an insertion point. Therefore, we also 16786e99e11SSchrodinger ZHU Yifan // return the first available slot we find. If such entry is empty, the 16886e99e11SSchrodinger ZHU Yifan // key will be nullptr. 16986e99e11SSchrodinger ZHU Yifan if (LIBC_LIKELY(available.any_bit_set())) { 17086e99e11SSchrodinger ZHU Yifan size_t index = 17186e99e11SSchrodinger ZHU Yifan (pos + available.lowest_set_bit_nonzero()) & entries_mask; 17286e99e11SSchrodinger ZHU Yifan return index; 17386e99e11SSchrodinger ZHU Yifan } 17486e99e11SSchrodinger ZHU Yifan } 17586e99e11SSchrodinger ZHU Yifan } 17686e99e11SSchrodinger ZHU Yifan 17786e99e11SSchrodinger ZHU Yifan LIBC_INLINE uint64_t oneshot_hash(const char *key) const { 17886e99e11SSchrodinger ZHU Yifan LIBC_NAMESPACE::internal::HashState hasher = state; 17986e99e11SSchrodinger ZHU Yifan hasher.update(key, strlen(key)); 18086e99e11SSchrodinger ZHU Yifan return hasher.finish(); 18186e99e11SSchrodinger ZHU Yifan } 18286e99e11SSchrodinger ZHU Yifan 18386e99e11SSchrodinger ZHU Yifan // A fast insertion routine without checking if a key already exists. 18486e99e11SSchrodinger ZHU Yifan // Nor does the routine check if the table is full. 18586e99e11SSchrodinger ZHU Yifan // This is only to be used in grow() where we insert all existing entries 18686e99e11SSchrodinger ZHU Yifan // into a new table. Hence, the requirements are naturally satisfied. 18786e99e11SSchrodinger ZHU Yifan LIBC_INLINE ENTRY *unsafe_insert(ENTRY item) { 18886e99e11SSchrodinger ZHU Yifan uint64_t primary = oneshot_hash(item.key); 18986e99e11SSchrodinger ZHU Yifan uint8_t secondary = secondary_hash(primary); 19086e99e11SSchrodinger ZHU Yifan ProbeSequence sequence{static_cast<size_t>(primary), 0, entries_mask}; 19186e99e11SSchrodinger ZHU Yifan while (true) { 19286e99e11SSchrodinger ZHU Yifan size_t pos = sequence.next(); 19386e99e11SSchrodinger ZHU Yifan Group ctrls = Group::load(&control(pos)); 19486e99e11SSchrodinger ZHU Yifan BitMask available = ctrls.mask_available(); 19586e99e11SSchrodinger ZHU Yifan if (available.any_bit_set()) { 19686e99e11SSchrodinger ZHU Yifan size_t index = 19786e99e11SSchrodinger ZHU Yifan (pos + available.lowest_set_bit_nonzero()) & entries_mask; 19886e99e11SSchrodinger ZHU Yifan set_ctrl(index, secondary); 19986e99e11SSchrodinger ZHU Yifan entry(index).key = item.key; 20086e99e11SSchrodinger ZHU Yifan entry(index).data = item.data; 20186e99e11SSchrodinger ZHU Yifan available_slots--; 20286e99e11SSchrodinger ZHU Yifan return &entry(index); 20386e99e11SSchrodinger ZHU Yifan } 20486e99e11SSchrodinger ZHU Yifan } 20586e99e11SSchrodinger ZHU Yifan } 20686e99e11SSchrodinger ZHU Yifan 20786e99e11SSchrodinger ZHU Yifan LIBC_INLINE HashTable *grow() const { 20886e99e11SSchrodinger ZHU Yifan size_t hint = full_capacity() + 1; 20986e99e11SSchrodinger ZHU Yifan HashState state = this->state; 21086e99e11SSchrodinger ZHU Yifan // migrate to a new random state 21186e99e11SSchrodinger ZHU Yifan state.update(&hint, sizeof(hint)); 21286e99e11SSchrodinger ZHU Yifan HashTable *new_table = allocate(hint, state.finish()); 21386e99e11SSchrodinger ZHU Yifan // It is safe to call unsafe_insert() because we know that: 21486e99e11SSchrodinger ZHU Yifan // - the new table has enough capacity to hold all the entries 21586e99e11SSchrodinger ZHU Yifan // - there is no duplicate key in the old table 21686e99e11SSchrodinger ZHU Yifan if (new_table != nullptr) 21786e99e11SSchrodinger ZHU Yifan for (ENTRY e : *this) 21886e99e11SSchrodinger ZHU Yifan new_table->unsafe_insert(e); 21986e99e11SSchrodinger ZHU Yifan return new_table; 22086e99e11SSchrodinger ZHU Yifan } 22186e99e11SSchrodinger ZHU Yifan 22286e99e11SSchrodinger ZHU Yifan LIBC_INLINE static ENTRY *insert(HashTable *&table, ENTRY item, 22386e99e11SSchrodinger ZHU Yifan uint64_t primary) { 22486e99e11SSchrodinger ZHU Yifan auto index = table->find(item.key, primary); 22586e99e11SSchrodinger ZHU Yifan auto slot = &table->entry(index); 22686e99e11SSchrodinger ZHU Yifan // SVr4 and POSIX.1-2001 specify that action is significant only for 22786e99e11SSchrodinger ZHU Yifan // unsuccessful searches, so that an ENTER should not do anything 22886e99e11SSchrodinger ZHU Yifan // for a successful search. 22986e99e11SSchrodinger ZHU Yifan if (slot->key != nullptr) 23086e99e11SSchrodinger ZHU Yifan return slot; 23186e99e11SSchrodinger ZHU Yifan 23286e99e11SSchrodinger ZHU Yifan // if table of full, we try to grow the table 23386e99e11SSchrodinger ZHU Yifan if (table->is_full()) { 23486e99e11SSchrodinger ZHU Yifan HashTable *new_table = table->grow(); 23586e99e11SSchrodinger ZHU Yifan // allocation failed, return nullptr to indicate failure 23686e99e11SSchrodinger ZHU Yifan if (new_table == nullptr) 23786e99e11SSchrodinger ZHU Yifan return nullptr; 23886e99e11SSchrodinger ZHU Yifan // resized sccuessfully: clean up the old table and use the new one 23986e99e11SSchrodinger ZHU Yifan deallocate(table); 24086e99e11SSchrodinger ZHU Yifan table = new_table; 24186e99e11SSchrodinger ZHU Yifan // it is still valid to use the fastpath insertion. 24286e99e11SSchrodinger ZHU Yifan return table->unsafe_insert(item); 24386e99e11SSchrodinger ZHU Yifan } 24486e99e11SSchrodinger ZHU Yifan 24586e99e11SSchrodinger ZHU Yifan table->set_ctrl(index, secondary_hash(primary)); 24686e99e11SSchrodinger ZHU Yifan slot->key = item.key; 24786e99e11SSchrodinger ZHU Yifan slot->data = item.data; 24886e99e11SSchrodinger ZHU Yifan table->available_slots--; 24986e99e11SSchrodinger ZHU Yifan return slot; 25086e99e11SSchrodinger ZHU Yifan } 25186e99e11SSchrodinger ZHU Yifan 25281e3e7e5SSchrodinger ZHU Yifan public: 25381e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE static void deallocate(HashTable *table) { 25481e3e7e5SSchrodinger ZHU Yifan if (table) { 25581e3e7e5SSchrodinger ZHU Yifan void *ptr = 25681e3e7e5SSchrodinger ZHU Yifan reinterpret_cast<uint8_t *>(table) - table->offset_from_entries(); 25781e3e7e5SSchrodinger ZHU Yifan operator delete(ptr, std::align_val_t{table_alignment()}); 25881e3e7e5SSchrodinger ZHU Yifan } 25981e3e7e5SSchrodinger ZHU Yifan } 26086e99e11SSchrodinger ZHU Yifan 26181e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE static HashTable *allocate(size_t capacity, uint64_t randomness) { 26281e3e7e5SSchrodinger ZHU Yifan // check if capacity_to_entries overflows MAX_MEM_SIZE 26381e3e7e5SSchrodinger ZHU Yifan if (capacity > size_t{1} << (8 * sizeof(size_t) - 1 - 3)) 26481e3e7e5SSchrodinger ZHU Yifan return nullptr; 26581e3e7e5SSchrodinger ZHU Yifan SafeMemSize entries{capacity_to_entries(capacity)}; 26681e3e7e5SSchrodinger ZHU Yifan SafeMemSize entries_size = entries * SafeMemSize{sizeof(ENTRY)}; 26781e3e7e5SSchrodinger ZHU Yifan SafeMemSize align_boundary = entries_size.align_up(table_alignment()); 26881e3e7e5SSchrodinger ZHU Yifan SafeMemSize ctrl_sizes = entries + SafeMemSize{sizeof(Group)}; 26981e3e7e5SSchrodinger ZHU Yifan SafeMemSize header_size{offset_to_groups()}; 27081e3e7e5SSchrodinger ZHU Yifan SafeMemSize total_size = 27181e3e7e5SSchrodinger ZHU Yifan (align_boundary + header_size + ctrl_sizes).align_up(table_alignment()); 27281e3e7e5SSchrodinger ZHU Yifan if (!total_size.valid()) 27381e3e7e5SSchrodinger ZHU Yifan return nullptr; 27481e3e7e5SSchrodinger ZHU Yifan AllocChecker ac; 27581e3e7e5SSchrodinger ZHU Yifan 27681e3e7e5SSchrodinger ZHU Yifan void *mem = operator new(total_size, std::align_val_t{table_alignment()}, 27781e3e7e5SSchrodinger ZHU Yifan ac); 27881e3e7e5SSchrodinger ZHU Yifan 27981e3e7e5SSchrodinger ZHU Yifan HashTable *table = reinterpret_cast<HashTable *>( 28081e3e7e5SSchrodinger ZHU Yifan static_cast<uint8_t *>(mem) + align_boundary); 28181e3e7e5SSchrodinger ZHU Yifan if (ac) { 28281e3e7e5SSchrodinger ZHU Yifan table->entries_mask = entries - 1u; 28381e3e7e5SSchrodinger ZHU Yifan table->available_slots = entries / 8 * 7; 28481e3e7e5SSchrodinger ZHU Yifan table->state = HashState{randomness}; 28581e3e7e5SSchrodinger ZHU Yifan memset(&table->control(0), 0x80, ctrl_sizes); 28681e3e7e5SSchrodinger ZHU Yifan memset(mem, 0, table->offset_from_entries()); 28781e3e7e5SSchrodinger ZHU Yifan } 28881e3e7e5SSchrodinger ZHU Yifan return table; 28981e3e7e5SSchrodinger ZHU Yifan } 29081e3e7e5SSchrodinger ZHU Yifan 29186e99e11SSchrodinger ZHU Yifan struct FullTableIterator { 29286e99e11SSchrodinger ZHU Yifan size_t current_offset; 29386e99e11SSchrodinger ZHU Yifan size_t remaining; 29486e99e11SSchrodinger ZHU Yifan IteratableBitMask current_mask; 29586e99e11SSchrodinger ZHU Yifan const HashTable &table; 29686e99e11SSchrodinger ZHU Yifan 29786e99e11SSchrodinger ZHU Yifan // It is fine to use remaining to represent the iterator: 29886e99e11SSchrodinger ZHU Yifan // - this comparison only happens with the same table 29986e99e11SSchrodinger ZHU Yifan // - hashtable will not be mutated during the iteration 30086e99e11SSchrodinger ZHU Yifan LIBC_INLINE bool operator==(const FullTableIterator &other) const { 30186e99e11SSchrodinger ZHU Yifan return remaining == other.remaining; 30281e3e7e5SSchrodinger ZHU Yifan } 30386e99e11SSchrodinger ZHU Yifan LIBC_INLINE bool operator!=(const FullTableIterator &other) const { 30486e99e11SSchrodinger ZHU Yifan return remaining != other.remaining; 30581e3e7e5SSchrodinger ZHU Yifan } 30686e99e11SSchrodinger ZHU Yifan 30786e99e11SSchrodinger ZHU Yifan LIBC_INLINE FullTableIterator &operator++() { 30886e99e11SSchrodinger ZHU Yifan this->ensure_valid_group(); 30986e99e11SSchrodinger ZHU Yifan current_mask.remove_lowest_bit(); 31086e99e11SSchrodinger ZHU Yifan remaining--; 31186e99e11SSchrodinger ZHU Yifan return *this; 31281e3e7e5SSchrodinger ZHU Yifan } 31386e99e11SSchrodinger ZHU Yifan LIBC_INLINE const ENTRY &operator*() { 31486e99e11SSchrodinger ZHU Yifan this->ensure_valid_group(); 31586e99e11SSchrodinger ZHU Yifan return table.entry( 31686e99e11SSchrodinger ZHU Yifan (current_offset + current_mask.lowest_set_bit_nonzero()) & 31786e99e11SSchrodinger ZHU Yifan table.entries_mask); 31881e3e7e5SSchrodinger ZHU Yifan } 31981e3e7e5SSchrodinger ZHU Yifan 32081e3e7e5SSchrodinger ZHU Yifan private: 32186e99e11SSchrodinger ZHU Yifan LIBC_INLINE void ensure_valid_group() { 32286e99e11SSchrodinger ZHU Yifan while (!current_mask.any_bit_set()) { 32386e99e11SSchrodinger ZHU Yifan current_offset += sizeof(Group); 32486e99e11SSchrodinger ZHU Yifan // It is ensured that the load will only happen at aligned boundaries. 32586e99e11SSchrodinger ZHU Yifan current_mask = 32686e99e11SSchrodinger ZHU Yifan Group::load_aligned(&table.control(current_offset)).occupied(); 32781e3e7e5SSchrodinger ZHU Yifan } 32881e3e7e5SSchrodinger ZHU Yifan } 32986e99e11SSchrodinger ZHU Yifan }; 33081e3e7e5SSchrodinger ZHU Yifan 33186e99e11SSchrodinger ZHU Yifan using value_type = ENTRY; 33286e99e11SSchrodinger ZHU Yifan using iterator = FullTableIterator; 33386e99e11SSchrodinger ZHU Yifan iterator begin() const { 33486e99e11SSchrodinger ZHU Yifan return {0, full_capacity() - available_slots, 33586e99e11SSchrodinger ZHU Yifan Group::load_aligned(&control(0)).occupied(), *this}; 33686e99e11SSchrodinger ZHU Yifan } 337c1023c58SNick Desaulniers iterator end() const { return {0, 0, {BitMask{0}}, *this}; } 33886e99e11SSchrodinger ZHU Yifan 33981e3e7e5SSchrodinger ZHU Yifan LIBC_INLINE ENTRY *find(const char *key) { 34086e99e11SSchrodinger ZHU Yifan uint64_t primary = oneshot_hash(key); 34181e3e7e5SSchrodinger ZHU Yifan ENTRY &entry = this->entry(find(key, primary)); 34281e3e7e5SSchrodinger ZHU Yifan if (entry.key == nullptr) 34381e3e7e5SSchrodinger ZHU Yifan return nullptr; 34481e3e7e5SSchrodinger ZHU Yifan return &entry; 34581e3e7e5SSchrodinger ZHU Yifan } 34686e99e11SSchrodinger ZHU Yifan 34786e99e11SSchrodinger ZHU Yifan LIBC_INLINE static ENTRY *insert(HashTable *&table, ENTRY item) { 34886e99e11SSchrodinger ZHU Yifan uint64_t primary = table->oneshot_hash(item.key); 34986e99e11SSchrodinger ZHU Yifan return insert(table, item, primary); 35081e3e7e5SSchrodinger ZHU Yifan } 35181e3e7e5SSchrodinger ZHU Yifan }; 35281e3e7e5SSchrodinger ZHU Yifan } // namespace internal 353*5ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 35481e3e7e5SSchrodinger ZHU Yifan 355330793c9SNick Desaulniers #endif // LLVM_LIBC_SRC___SUPPORT_HASHTABLE_TABLE_H 356