static void gu_map_enum_next(GuEnum* self, void* to, GuPool* pool) { *((GuMapKeyValue**) to) = NULL; size_t i; GuMapEnum* en = (GuMapEnum*) self; for (i = en->i; i < en->ht->data.n_entries; i++) { if (gu_map_entry_is_free(en->ht, &en->ht->data, i)) { continue; } en->x.key = &en->ht->data.keys[i * en->ht->key_size]; en->x.value = &en->ht->data.values[i * en->ht->value_size]; if (en->ht->kind == GU_MAP_ADDR) { en->x.key = *(const void* const*) en->x.key; } else if (en->ht->kind == GU_MAP_STRING) { en->x.key = *(GuString*) en->x.key; } *((GuMapKeyValue**) to) = &en->x; break; } en->i = i+1; }
void* gu_map_insert(GuMap* map, const void* key) { size_t idx; bool found = gu_map_lookup(map, key, &idx); if (!found) { if (gu_map_maybe_resize(map)) { found = gu_map_lookup(map, key, &idx); gu_assert(!found); } if (map->kind == GU_MAP_ADDR) { ((const void**)map->data.keys)[idx] = key; } else if (map->kind == GU_MAP_STRING) { ((GuString*)map->data.keys)[idx] = key; } else { memcpy(&map->data.keys[idx * map->key_size], key, map->key_size); } if (map->default_value) { memcpy(&map->data.values[idx * map->value_size], map->default_value, map->value_size); } if (gu_map_entry_is_free(map, &map->data, idx)) { gu_assert(map->data.zero_idx == SIZE_MAX); map->data.zero_idx = idx; } map->data.n_occupied++; } return &map->data.values[idx * map->value_size]; }
size_t gu_map_count(GuMap* map) { size_t count = 0; for (size_t i = 0; i < map->data.n_entries; i++) { if (gu_map_entry_is_free(map, &map->data, i)) { continue; } count++; } return count; }
void gu_map_iter(GuMap* map, GuMapItor* itor, GuExn* err) { for (size_t i = 0; i < map->data.n_entries && gu_ok(err); i++) { if (gu_map_entry_is_free(map, &map->data, i)) { continue; } const void* key = &map->data.keys[i * map->key_size]; void* value = &map->data.values[i * map->value_size]; if (map->kind == GU_MAP_ADDR) { key = *(const void* const*) key; } itor->fn(itor, key, value, err); } }
static void gu_map_resize(GuMap* map) { GuMapData* data = &map->data; GuMapData old_data = *data; size_t req_entries = gu_twin_prime_sup(GU_MAX(11, map->data.n_occupied * 4 / 3 + 1)); size_t key_size = map->key_size; size_t key_alloc = 0; data->keys = gu_mem_buf_alloc(req_entries * key_size, &key_alloc); size_t value_size = map->value_size; size_t value_alloc = 0; if (value_size) { data->values = gu_mem_buf_alloc(req_entries * value_size, &value_alloc); memset(data->values, 0, value_alloc); } data->n_entries = gu_twin_prime_inf(value_size ? GU_MIN(key_alloc / key_size, value_alloc / value_size) : key_alloc / key_size); switch (map->kind) { case GU_MAP_GENERIC: case GU_MAP_WORD: memset(data->keys, 0, key_alloc); break; case GU_MAP_ADDR: for (size_t i = 0; i < data->n_entries; i++) { ((const void**)data->keys)[i] = NULL; } break; case GU_MAP_STRING: for (size_t i = 0; i < data->n_entries; i++) { ((GuString*)data->keys)[i] = NULL; } break; default: gu_impossible(); } gu_assert(data->n_entries > data->n_occupied); data->n_occupied = 0; data->zero_idx = SIZE_MAX; for (size_t i = 0; i < old_data.n_entries; i++) { if (gu_map_entry_is_free(map, &old_data, i)) { continue; } void* old_key = &old_data.keys[i * key_size]; if (map->kind == GU_MAP_ADDR) { old_key = *(void**)old_key; } else if (map->kind == GU_MAP_STRING) { old_key = (void*) *(GuString*)old_key; } void* old_value = &old_data.values[i * value_size]; memcpy(gu_map_insert(map, old_key), old_value, map->value_size); } gu_mem_buf_free(old_data.keys); if (value_size) { gu_mem_buf_free(old_data.values); } }