#define PTR_MAP_ENABLE_MULTI_MAP 1 typedef u32 MapIndex; enum { MAP_CACHE_LINE_SIZE_POW = 6, MAP_CACHE_LINE_SIZE = 1< struct PtrMapEntry { static_assert(sizeof(K) == sizeof(void *), "Key size must be pointer size"); K key; V value; }; template struct PtrMap { PtrMapEntry *entries; u32 count; u32 capacity; }; gb_internal gb_inline u32 ptr_map_hash_key(uintptr key) { u32 res; #if defined(GB_ARCH_64_BIT) key = (~key) + (key << 21); key = key ^ (key >> 24); key = (key + (key << 3)) + (key << 8); key = key ^ (key >> 14); key = (key + (key << 2)) + (key << 4); key = key ^ (key << 28); res = cast(u32)key; #elif defined(GB_ARCH_32_BIT) u32 state = (cast(u32)key) * 747796405u + 2891336453u; u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; res = (word >> 22u) ^ word; #endif return res; } gb_internal gb_inline u32 ptr_map_hash_key(void const *key) { return ptr_map_hash_key((uintptr)key); } template gb_internal void map_init (PtrMap *h, isize capacity = 16); template gb_internal void map_destroy (PtrMap *h); template gb_internal V * map_get (PtrMap *h, K key); template gb_internal void map_set (PtrMap *h, K key, V const &value); template gb_internal bool map_set_if_not_previously_exists(PtrMap *h, K key, V const &value); // returns true if it previously existed template gb_internal void map_remove (PtrMap *h, K key); template gb_internal void map_clear (PtrMap *h); template gb_internal void map_grow (PtrMap *h); template gb_internal void map_rehash (PtrMap *h, isize new_count); template gb_internal void map_reserve (PtrMap *h, isize cap); // Mutlivalued map procedure template gb_internal PtrMapEntry * multi_map_find_first(PtrMap *h, K key); template gb_internal PtrMapEntry * multi_map_find_next (PtrMap *h, PtrMapEntry *e); template gb_internal isize multi_map_count (PtrMap *h, K key); template gb_internal void multi_map_get_all (PtrMap *h, K key, V *items); template gb_internal void multi_map_insert (PtrMap *h, K key, V const &value); template gb_internal void multi_map_remove (PtrMap *h, K key, PtrMapEntry *e); template gb_internal void multi_map_remove_all(PtrMap *h, K key); gb_internal gbAllocator map_allocator(void) { return heap_allocator(); } template gb_internal gb_inline void map_init(PtrMap *h, isize capacity) { capacity = next_pow2_isize(capacity); map_reserve(h, capacity); } template gb_internal gb_inline void map_destroy(PtrMap *h) { gbAllocator a = map_allocator(); gb_free(a, h->entries); } template gb_internal void map__insert(PtrMap *h, K key, V const &value) { if (h->count+1 >= h->capacity) { map_grow(h); } u32 hash = ptr_map_hash_key(key); u32 mask = h->capacity-1; MapIndex index = hash & mask; MapIndex original_index = index; do { auto *entry = h->entries+index; if (!entry->key || entry->key == cast(K)MAP_TOMBSTONE) { entry->key = key; entry->value = value; h->count += 1; return; } index = (index+1)&mask; } while (index != original_index); GB_PANIC("FAILED TO INSERT"); } template gb_internal b32 map__full(PtrMap *h) { return 0.75f * h->capacity <= h->count; } template gb_internal gb_inline void map_grow(PtrMap *h) { isize new_capacity = gb_max(h->capacity<<1, 16); map_reserve(h, new_capacity); } template gb_internal void try_map_grow(PtrMap *h) { if (h->capacity == 0 || map__full(h)) { map_grow(h); } } template gb_internal void map_reserve(PtrMap *h, isize cap) { if (cap < h->capacity) { return; } cap = next_pow2_isize(cap); typedef PtrMapEntry EntryType; PtrMap new_h = {}; new_h.count = 0; new_h.capacity = cast(u32)cap; new_h.entries = gb_alloc_array(map_allocator(), EntryType, new_h.capacity); if (h->count) { for (u32 i = 0; i < h->capacity; i++) { auto *entry = h->entries+i; if (entry->key && entry->key != cast(K)MAP_TOMBSTONE) { map__insert(&new_h, entry->key, entry->value); } } } map_destroy(h); *h = new_h; } template gb_internal V *map_get(PtrMap *h, K key) { if (h->count == 0) { return nullptr; } if (key == 0) { GB_PANIC("0 key"); } u32 hash = ptr_map_hash_key(key); u32 mask = (h->capacity-1); u32 index = hash & mask; u32 original_index = index; do { auto *entry = h->entries+index; if (!entry->key) { // NOTE(bill): no found, but there isn't any key removal for this hash map return nullptr; } else if (entry->key == key) { return &entry->value; } index = (index+1) & mask; } while (original_index != index); return nullptr; } template gb_internal V *map_try_get(PtrMap *h, K key, MapIndex *found_index_) { if (found_index_) *found_index_ = ~(MapIndex)0; if (h->count == 0) { return nullptr; } if (key == 0) { GB_PANIC("0 key"); } u32 hash = ptr_map_hash_key(key); u32 mask = (h->capacity-1); u32 index = hash & mask; u32 original_index = index; do { auto *entry = h->entries+index; if (!entry->key) { // NOTE(bill): no found, but there isn't any key removal for this hash map return nullptr; } else if (entry->key == key) { if (found_index_) *found_index_ = index; return &entry->value; } index = (index+1) & mask; } while (original_index != index); return nullptr; } template gb_internal void map_set_internal_from_try_get(PtrMap *h, K key, V const &value, MapIndex found_index) { if (found_index != MAP_SENTINEL) { GB_ASSERT(h->entries[found_index].key == key); h->entries[found_index].value = value; } else { map_set(h, key, value); } } template gb_internal V &map_must_get(PtrMap *h, K key) { V *ptr = map_get(h, key); GB_ASSERT(ptr != nullptr); return *ptr; } template gb_internal void map_set(PtrMap *h, K key, V const &value) { GB_ASSERT(key != 0); try_map_grow(h); auto *found = map_get(h, key); if (found) { *found = value; return; } map__insert(h, key, value); } // returns true if it previously existed template gb_internal bool map_set_if_not_previously_exists(PtrMap *h, K key, V const &value) { try_map_grow(h); auto *found = map_get(h, key); if (found) { return true; } map__insert(h, key, value); return false; } template gb_internal void map_remove(PtrMap *h, K key) { MapIndex found_index = 0; if (map_try_get(h, key, &found_index)) { h->entries[found_index].key = cast(K)MAP_TOMBSTONE; h->count -= 1; } } template gb_internal gb_inline void map_clear(PtrMap *h) { h->count = 0; gb_zero_array(h->entries, h->capacity); } #if PTR_MAP_ENABLE_MULTI_MAP template gb_internal PtrMapEntry *multi_map_find_first(PtrMap *h, K key) { if (h->count == 0) { return nullptr; } u32 hash = ptr_map_hash_key(key); u32 mask = (h->capacity-1); u32 index = hash & mask; u32 original_index = index; do { auto *entry = h->entries+index; if (!entry->key) { // NOTE(bill): no found, but there isn't any key removal for this hash map return nullptr; } else if (entry->key == key) { return entry; } index = (index+1) & mask; } while (original_index != index); return nullptr; } template gb_internal PtrMapEntry *multi_map_find_next(PtrMap *h, PtrMapEntry *e) { u32 mask = h->capacity-1; MapIndex index = cast(MapIndex)(e - h->entries); MapIndex original_index = index; do { index = (index+1)&mask; auto *entry = h->entries+index; if (!entry->key) { return nullptr; } if (entry->key == e->key) { return entry; } } while (original_index != index); return nullptr; } template gb_internal isize multi_map_count(PtrMap *h, K key) { isize count = 0; PtrMapEntry *e = multi_map_find_first(h, key); while (e != nullptr) { count++; e = multi_map_find_next(h, e); } return count; } template gb_internal void multi_map_get_all(PtrMap *h, K key, V *items) { usize i = 0; PtrMapEntry *e = multi_map_find_first(h, key); while (e != nullptr) { items[i++] = e->value; e = multi_map_find_next(h, e); } } template gb_internal void multi_map_insert(PtrMap *h, K key, V const &value) { try_map_grow(h); map__insert(h, key, value); } // template // gb_internal void multi_map_remove(PtrMap *h, K key, PtrMapEntry *e) { // if (fr.entry_index != MAP_SENTINEL) { // map__erase(h, fr); // } // } template gb_internal void multi_map_remove_all(PtrMap *h, K key) { while (map_get(h, key) != nullptr) { map_remove(h, key); } } #endif template struct PtrMapIterator { PtrMap *map; MapIndex index; PtrMapIterator &operator++() noexcept { for (;;) { ++index; if (map->capacity == index) { return *this; } PtrMapEntry *entry = map->entries+index; if (entry->key && entry->key != cast(K)MAP_TOMBSTONE) { return *this; } } } bool operator==(PtrMapIterator const &other) const noexcept { return this->map == other->map && this->index == other->index; } operator PtrMapEntry *() const { return map->entries+index; } }; template gb_internal PtrMapIterator end(PtrMap &m) noexcept { return PtrMapIterator{&m, m.capacity}; } template gb_internal PtrMapIterator const end(PtrMap const &m) noexcept { return PtrMapIterator{&m, m.capacity}; } template gb_internal PtrMapIterator begin(PtrMap &m) noexcept { if (m.count == 0) { return end(m); } MapIndex index = 0; while (index < m.capacity) { auto key = m.entries[index].key; if (key && key != cast(K)MAP_TOMBSTONE) { break; } index++; } return PtrMapIterator{&m, index}; } template gb_internal PtrMapIterator const begin(PtrMap const &m) noexcept { if (m.count == 0) { return end(m); } MapIndex index = 0; while (index < m.capacity) { auto key = m.entries[index].key; if (key && key != cast(K)MAP_TOMBSTONE) { break; } index++; } return PtrMapIterator{&m, index}; }