#ifndef _UTIL_HASH_MAP_H #define _UTIL_HASH_MAP_H #include #include #include #include #include #include "utils_static.h" template struct hash_map_entry { K key; V value; }; size_t hash_map_get_next_cap(size_t cap); std::function hash_map_linear_probing(size_t interval); size_t hash_map_quadratic_probing(size_t i); size_t hash_map_quadratic_probing_alter(size_t i); class HashMapRandomProbingGeneator: public std::function { std::mt19937_64 gen; std::vector cache; public: HashMapRandomProbingGeneator(uint64_t seed): std::function([&](size_t i) { while (cache.size() < i) { cache.push_back(gen()); } return cache[i - 1]; }) { gen = std::mt19937_64(seed); } }; std::function hash_map_random_probing(uint64_t seed); template struct hash_map { std::function malloc; std::function realloc; std::function free; size_t cap; size_t count; size_t growat; uint8_t loadfactor; struct hash_map_entry** map; std::function probing; std::hash hash; std::function free_key; std::function free_value; }; template > struct hash_map* hash_map_new( size_t cap = hashmap_primes[0], uint8_t loadfactor = 60, H hash = H(), std::function probing = std::function(hash_map_quadratic_probing_alter), std::function malloc = std::function(::malloc), std::function realloc = std::function(::realloc), std::function free = std::function(::free), std::function free_key = std::function(), std::function free_value = std::function() ) { if (!cap) cap = hash_map_get_next_cap(cap); struct hash_map* map = new (struct hash_map)(); if (!map) return nullptr; map->malloc = malloc; map->realloc = realloc; map->free = free; map->cap = cap; map->count = 0; hash_map_set_loadfactor(map, loadfactor); map->probing = probing; map->hash = hash; map->free_key = free_key; map->free_value = free_value; size_t mapsize = sizeof(void*) * map->cap; map->map = (struct hash_map_entry**)map->malloc(mapsize); if (!map->map) { delete map; return nullptr; } memset(map->map, 0, mapsize); return map; } template void free_hash_map(struct hash_map*& map) { hash_map_clear(map, false); map->free(map->map); delete map; map = nullptr; } template void hash_map_clear(struct hash_map* map, bool shrink = true) { if (!map) return; for (size_t i = 0; i < map->cap; i++) { auto m = map->map[i]; if (m) { if (map->free_key) map->free_key(m->key); if (map->free_value) map->free_value(m->value); delete map->map[i]; map->map[i] = nullptr; } } map->count = 0; if (shrink && map->cap > hashmap_primes[0]) { hash_map_set_cap(map, hashmap_primes[0]); } } template bool hash_map_delete(struct hash_map* map, K key, V* deleted_value = nullptr) { if (!map) return false; size_t h = map->hash(key); size_t loc = h % map->cap; size_t i = 1; while (map->map[loc] && map->map[loc]->key != key) { loc = (h + map->probing(i++)) % map->cap; } if (!map->map[loc]) return false; if (deleted_value) *deleted_value = map->map[loc]->value; if (map->free_key) map->free_key(map->map[loc]->key); if (!deleted_value && map->free_value) map->free_value(map->map[loc]->value); delete map->map[loc]; map->map[loc] = nullptr; return true; } template inline bool hash_map_delete(struct hash_map* map, X key, V* deleted_value = nullptr) { return hash_map_delete(map, K(key), deleted_value); } template struct hash_map_entry* hash_map_get_entry(struct hash_map* map, K key) { if (!map) return nullptr; size_t h = map->hash(key); size_t loc = h % map->cap; size_t i = 1; while (map->map[loc] && map->map[loc]->key != key) { loc = (h + map->probing(i++)) % map->cap; } return map->map[loc]; } template inline struct hash_map_entry* hash_map_get_entry(struct hash_map* map, X key) { return hash_map_get_entry(map, K(key)); } template bool hash_map_get(struct hash_map* map, K key, V& value) { if (!map) return false; size_t h = map->hash(key); size_t loc = h % map->cap; size_t i = 1; while (map->map[loc] && map->map[loc]->key != key) { loc = (h + map->probing(i++)) % map->cap; } if (!map->map[loc]) return false; value = map->map[loc]->value; return true; } template inline bool hash_map_get(struct hash_map* map, X key, V& value) { return hash_map_get(map, K(key), value); } template struct hash_map_entry* hash_map_insert_entry(struct hash_map* map, struct hash_map_entry* entry) { if (!map || !entry) return nullptr; size_t h = map->hash(entry->key); size_t loc = h % map->cap; size_t i = 1; while (map->map[loc] && map->map[loc]->key != entry->key) { loc = (h + map->probing(i++)) % map->cap; } auto t = map->map[loc]; map->map[loc] = entry; map->count += t ? 0 : 1; return t; } template struct hash_map_entry* hash_map_insert(struct hash_map* map, K key, V value) { if (!map) return nullptr; if (map->count >= map->growat) { if (!hash_map_resize(map, hash_map_get_next_cap(map->cap))) { return nullptr; } } size_t h = map->hash(key); size_t loc = h % map->cap; size_t i = 1; while (map->map[loc] && map->map[loc]->key != key) { loc = (h + map->probing(i++)) % map->cap; } if (map->map[loc]) { if (map->free_value) map->free_value(map->map[loc]->value); if (map->free_key) map->free_key(key); map->map[loc]->value = value; return map->map[loc]; } struct hash_map_entry* ent = new (struct hash_map_entry)({key, value}); if (!ent) return nullptr; map->map[loc] = ent; map->count += 1; return map->map[loc]; } template inline struct hash_map_entry* hash_map_insert(struct hash_map* map, X key, Y value) { return hash_map_insert(map, K(key), V(value)); } template bool hash_map_resize(struct hash_map* map, size_t newcap) { if (!map && !newcap) return false; if (map->count > newcap) return false; if (map->cap == newcap) return true; size_t mapsize = sizeof(void *) * newcap; auto t = (struct hash_map_entry**)map->malloc(mapsize); if (!t) return false; memset(t, 0, mapsize); auto ori = map->map; auto oricap = map->cap; map->cap = newcap; map->growat = map->cap * map->loadfactor / 100; map->map = t; map->count = 0; for (size_t i = 0; i < oricap; i++) { if (ori[i]) { hash_map_insert_entry(map, ori[i]); } } map->free(ori); return true; } template bool hash_map_set_cap(struct hash_map* map, size_t newcap) { if (!map || !newcap) return false; auto t = (struct hash_map_entry**)map->realloc(map->map, sizeof(void *) * newcap); if (t) { map->map = t; map->cap = newcap; map->growat = map->cap * map->loadfactor / 100; return true; } return false; } template void hash_map_set_loadfactor(struct hash_map* map, uint8_t loadfactor) { if (!map) return; if (loadfactor > 100) loadfactor = 100; map->loadfactor = loadfactor; map->growat = map->cap * loadfactor / 100; } #endif