70#include "../include/cmp.h"
71#include "../include/lock.h"
72#include "../include/map.h"
73#include "../include/platform.h"
78#define DEFAULT_MAX_LOAD_FACTOR 0.75f
79#define TOMBSTONE_RATIO_THRESHOLD 0.5f
81#define MAX(a, b) ((a) > (b) ? (a) : (b))
84#define _RH_DIB(m, i) ((size_t)(m->deleted[i]))
85#define _RH_SET_DIB(m, i, d) ((m)->deleted[i] = (bool)(d))
87#define _RH_EMPTY(m, i) ((m)->keys_values[(i) * 2] == NULL)
90static inline size_t _rh_slot(
size_t hash,
size_t offset,
size_t cap_mask) {
return (hash + offset) & cap_mask; }
93typedef struct hash_map {
98 float max_load_factor;
100 KeyCmpFunction key_compare;
101 KeyFreeFunction key_free;
102 ValueFreeFunction value_free;
107static inline uint64_t fast_small_hash(
const void* key,
size_t size) {
117 const uint8_t* src = (
const uint8_t*)key;
118 for (
size_t i = 0; i < size && i <
sizeof(value); i++) {
119 value.u8[i] = src[i];
125static inline unsigned long xxhash(
const void* key,
size_t size) {
126 if (size <=
sizeof(uint64_t)) {
127 return fast_small_hash(key, size);
129 return XXH3_64bits(key, size);
133static inline size_t next_power_of_two(
size_t n) {
134 if (n == 0)
return 1;
141#if SIZE_MAX > UINT32_MAX
148static inline size_t calculate_new_capacity(
size_t current) {
149 if (current > SIZE_MAX / 2) {
152 size_t new_cap = current * 2;
153 return (new_cap < current) ? SIZE_MAX : new_cap;
157static inline size_t xxhash_wrapper(
const void* key,
size_t len) {
return (
size_t)xxhash(key, (
size_t)len); }
160HashMap* map_create(
const MapConfig* config) {
161 if (!config || !config->key_compare) {
165 size_t capacity = MAX(
166 MIN_CAPACITY, config->initial_capacity > 0 ? next_power_of_two(config->initial_capacity) : INITIAL_MAP_SIZE);
168 if (capacity > SIZE_MAX / 2) {
172 float max_load_factor = config->max_load_factor > 0.1f && config->max_load_factor <= 0.95f
173 ? config->max_load_factor
174 : DEFAULT_MAX_LOAD_FACTOR;
176 HashMap* m = (HashMap*)malloc(
sizeof(HashMap));
182 m->keys_values = (
void**)calloc(capacity * 2,
sizeof(
void*));
183 m->deleted = (
bool*)calloc(capacity,
sizeof(
bool));
185 if (!m->keys_values || !m->deleted) {
186 free(m->keys_values);
193 m->capacity = capacity;
194 m->max_load_factor = max_load_factor;
195 m->hash = config->hash_func ? config->hash_func : xxhash_wrapper;
196 m->key_compare = config->key_compare;
197 m->key_free = config->key_free;
198 m->value_free = config->value_free;
205static inline void** get_key_ptr(HashMap* m,
size_t index) {
return &m->keys_values[index * 2]; }
208static inline void** get_value_ptr(HashMap* m,
size_t index) {
return &m->keys_values[index * 2 + 1]; }
211static bool map_resize(HashMap* m,
size_t new_capacity,
size_t key_len) {
212 if (new_capacity <= m->capacity || new_capacity > SIZE_MAX / 2) {
216 void** new_keys_values = (
void**)calloc(new_capacity * 2,
sizeof(
void*));
217 bool* new_deleted = (
bool*)calloc(new_capacity,
sizeof(
bool));
219 if (!new_keys_values || !new_deleted) {
220 free(new_keys_values);
226 void** old_keys_values = m->keys_values;
227 bool* old_deleted = m->deleted;
228 size_t old_capacity = m->capacity;
231 m->keys_values = new_keys_values;
232 m->deleted = new_deleted;
233 m->capacity = new_capacity;
234 size_t old_size = m->size;
239 for (
size_t i = 0; i < old_capacity; i++) {
240 if (old_keys_values[i * 2] && !old_deleted[i]) {
241 void* key = old_keys_values[i * 2];
242 void* value = old_keys_values[i * 2 + 1];
245 size_t hash = m->hash(key, key_len);
246 size_t index = hash & (new_capacity - 1);
247 size_t hash2 = (hash >> 5) | 1;
248 size_t probe_count = 0;
250 while (*get_key_ptr(m, index) != NULL) {
251 index = (index + hash2) & (new_capacity - 1);
252 if (++probe_count >= new_capacity) {
259 *get_key_ptr(m, index) = key;
260 *get_value_ptr(m, index) = value;
270 free(old_keys_values);
274 m->keys_values = old_keys_values;
275 m->deleted = old_deleted;
276 m->capacity = old_capacity;
278 free(new_keys_values);
286size_t map_length(HashMap* m) {
return m->size; }
289bool map_set(HashMap* m,
void* key,
size_t key_len,
void* value) {
290 if (!m || !key)
return false;
293 size_t total_used = m->size;
294 if ((
float)total_used / (
float)m->capacity >= m->max_load_factor) {
295 size_t new_cap = calculate_new_capacity(m->capacity);
296 if (new_cap <= m->capacity || !map_resize(m, new_cap, key_len))
return false;
299 const size_t mask = m->capacity - 1;
300 size_t hash = m->hash(key, key_len);
301 size_t idx = hash & mask;
305 void* ins_value = value;
308 for (
size_t i = 0; i < m->capacity; i++) {
309 if (_RH_EMPTY(m, idx)) {
311 *get_key_ptr(m, idx) = ins_key;
312 *get_value_ptr(m, idx) = ins_value;
313 _RH_SET_DIB(m, idx, ins_dist);
314 m->deleted[idx] =
false;
320 void** cur_kp = get_key_ptr(m, idx);
321 if (m->key_compare(*cur_kp, ins_key)) {
323 if (m->value_free) m->value_free(*get_value_ptr(m, idx));
324 *get_value_ptr(m, idx) = ins_value;
329 size_t cur_dist = _RH_DIB(m, idx);
330 if (cur_dist < ins_dist) {
332 void* tmp_k = *cur_kp;
333 void* tmp_v = *get_value_ptr(m, idx);
335 *get_key_ptr(m, idx) = ins_key;
336 *get_value_ptr(m, idx) = ins_value;
337 _RH_SET_DIB(m, idx, ins_dist);
344 idx = (idx + 1) & mask;
352void* map_get(HashMap* m,
void* key,
size_t key_len) {
353 if (!m || !key)
return NULL;
355 const size_t hash = m->hash(key, key_len);
356 const size_t mask = m->capacity - 1;
357 size_t idx = hash & mask;
359 for (
size_t dist = 0; dist < m->capacity; dist++) {
360 if (_RH_EMPTY(m, idx))
return NULL;
363 if (_RH_DIB(m, idx) < dist)
return NULL;
365 void** kp = get_key_ptr(m, idx);
366 if (m->key_compare(*kp, key))
return *get_value_ptr(m, idx);
368 idx = (idx + 1) & mask;
374bool map_remove(HashMap* m,
void* key,
size_t key_len) {
375 if (!m || !key)
return false;
377 const size_t mask = m->capacity - 1;
378 size_t hash = m->hash(key, key_len);
379 size_t idx = hash & mask;
382 size_t pos = SIZE_MAX;
383 for (
size_t dist = 0; dist < m->capacity; dist++) {
384 if (_RH_EMPTY(m, idx))
return false;
385 if (_RH_DIB(m, idx) < dist)
return false;
387 if (m->key_compare(*get_key_ptr(m, idx), key)) {
391 idx = (idx + 1) & mask;
393 if (pos == SIZE_MAX)
return false;
396 if (m->key_free) m->key_free(*get_key_ptr(m, pos));
397 if (m->value_free) m->value_free(*get_value_ptr(m, pos));
402 size_t next = (hole + 1) & mask;
403 if (_RH_EMPTY(m, next) || _RH_DIB(m, next) == 0)
break;
406 *get_key_ptr(m, hole) = *get_key_ptr(m, next);
407 *get_value_ptr(m, hole) = *get_value_ptr(m, next);
408 _RH_SET_DIB(m, hole, _RH_DIB(m, next) - 1);
409 m->deleted[hole] =
false;
415 *get_key_ptr(m, hole) = NULL;
416 *get_value_ptr(m, hole) = NULL;
417 m->deleted[hole] =
false;
422void map_destroy(HashMap* m) {
426 if (!m->key_free && !m->value_free) {
430 void** keys_values = m->keys_values;
431 bool* deleted = m->deleted;
432 size_t capacity = m->capacity;
433 KeyFreeFunction key_free = m->key_free;
434 ValueFreeFunction value_free = m->value_free;
436 for (
size_t i = 0; i < capacity; i++) {
437 void* key = keys_values[i * 2];
438 if (key && !deleted[i]) {
439 if (key_free) key_free(key);
440 if (value_free) value_free(keys_values[i * 2 + 1]);
445 free(m->keys_values);
451map_iterator map_iter(HashMap* map) {
452 map_iterator it = {.map = map, .index = 0};
456bool map_next(map_iterator* it,
void** key,
void** value) {
457 HashMap* map = it->map;
458 size_t capacity = map->capacity;
459 bool* deleted = map->deleted;
460 void** keys_values = map->keys_values;
461 size_t index = it->index;
463 while (index < capacity) {
464 void* current_key = keys_values[index * 2];
465 if (current_key && !deleted[index]) {
466 if (key) *key = current_key;
467 if (value) *value = keys_values[index * 2 + 1];
468 it->index = index + 1;
473 it->index = capacity;
478bool map_set_safe(HashMap* m,
void* key,
size_t key_len,
void* value) {
480 bool result = map_set(m, key, key_len, value);
485void* map_get_safe(HashMap* m,
void* key,
size_t key_len) {
487 void* value = map_get(m, key, key_len);
492bool map_remove_safe(HashMap* m,
void* key,
size_t key_len) {
494 bool result = map_remove(m, key, key_len);
int lock_init(Lock *lock)
int lock_acquire(Lock *lock)
int lock_release(Lock *lock)
int lock_free(Lock *lock)