static bool gu_map_entry_is_free(GuMap* map, GuMapData* data, size_t idx) { if (idx == data->zero_idx) { return false; } else if (map->kind == GU_MAP_ADDR) { const void* key = ((const void**)data->keys)[idx]; return key == NULL; } else if (map->kind == GU_MAP_WORD) { GuWord key = ((GuWord*)data->keys)[idx]; return key == 0; } gu_assert(map->kind == GU_MAP_GENERIC); const void* key = &data->keys[idx * map->key_size]; return gu_map_buf_is_zero(key, map->key_size); }
static bool gu_map_lookup(GuMap* map, const void* key, size_t* idx_out) { size_t n = map->data.n_entries; switch (map->kind) { case GU_MAP_GENERIC: { GuHasher* hasher = map->hasher; GuEquality* eq = (GuEquality*) hasher; GuHash hash = hasher->hash(hasher, key); size_t idx = hash % n; size_t offset = (hash % (n - 2)) + 1; size_t key_size = map->key_size; while (true) { void* entry_key = &map->data.keys[idx * key_size]; if (gu_map_buf_is_zero(entry_key, key_size) && map->data.zero_idx != idx) { *idx_out = idx; return false; } else if (eq->is_equal(eq, key, entry_key)) { *idx_out = idx; return true; } idx = (idx + offset) % n; } gu_impossible(); break; } case GU_MAP_ADDR: { GuHash hash = (GuHash) key; size_t idx = hash % n; size_t offset = (hash % (n - 2)) + 1; while (true) { const void* entry_key = ((const void**)map->data.keys)[idx]; if (entry_key == NULL && map->data.zero_idx != idx) { *idx_out = idx; return false; } else if (entry_key == key) { *idx_out = idx; return true; } idx = (idx + offset) % n; } gu_impossible(); break; } case GU_MAP_WORD: { GuWord w = *(const GuWord*)key; GuHash hash = (GuHash) w; size_t idx = hash % n; size_t offset = (hash % (n - 2)) + 1; while (true) { GuWord entry_key = ((GuWord*)map->data.keys)[idx]; if (entry_key == 0 && map->data.zero_idx != idx) { *idx_out = idx; return false; } else if (entry_key == w) { *idx_out = idx; return true; } idx = (idx + offset) % n; } gu_impossible(); break; } case GU_MAP_STRING: { GuHasher* hasher = map->hasher; GuEquality* eq = (GuEquality*) hasher; GuHash hash = hasher->hash(hasher, key); size_t idx = hash % n; size_t offset = (hash % (n - 2)) + 1; while (true) { GuString entry_key = ((GuString*)map->data.keys)[idx]; if (entry_key == NULL && map->data.zero_idx != idx) { *idx_out = idx; return false; } else if (eq->is_equal(eq, key, entry_key)) { *idx_out = idx; return true; } idx = (idx + offset) % n; } gu_impossible(); break; } default: gu_impossible(); } gu_impossible(); return false; }