diff options
| author | Fabrice <fabrice@schaub-dev.xyz> | 2026-03-22 13:49:46 +0100 |
|---|---|---|
| committer | Fabrice <fabrice@schaub-dev.xyz> | 2026-03-22 13:49:46 +0100 |
| commit | 5f955749eb99e53304338453e351c9f8e5f5a2f7 (patch) | |
| tree | 88563277f9569ee078974a57f19a02c555b3757c | |
| parent | e4cd519363547444be338ff087a559bb0490c5f1 (diff) | |
finishing wrapper
| -rw-r--r-- | cheesemap.c | 71 | ||||
| -rw-r--r-- | cheesemap.h | 13 | ||||
| -rw-r--r-- | cm-demo.c | 102 |
3 files changed, 177 insertions, 9 deletions
diff --git a/cheesemap.c b/cheesemap.c index bdaee94..f5ea7f4 100644 --- a/cheesemap.c +++ b/cheesemap.c @@ -209,7 +209,7 @@ static bool cm_raw_find_in_group(const struct cheesemap_raw* map, const struct cheesemap_fns* fns, group_t group, const struct sequence* seq, uint8_t h2, uintptr_t key_size, const uint8_t* key, - uintptr_t* out_index) { + uintptr_t value_size, uintptr_t* out_index) { assert(map != NULL && fns != NULL); assert(seq != NULL); assert(key != NULL && out_index != NULL); @@ -219,7 +219,7 @@ static bool cm_raw_find_in_group(const struct cheesemap_raw* map, uintptr_t bucket_offset = cm_bitmask_lowest_set_bit(mask); uintptr_t index = (seq->pos + bucket_offset) & map->bucket_mask; - uint8_t* elem = cm_raw_elem_at(map, index, key_size); + uint8_t* elem = cm_raw_elem_at(map, index, key_size + value_size); if (fns->compare(key, elem, fns->map_usr)) { *out_index = index; return true; @@ -234,7 +234,7 @@ static bool cm_raw_find_in_group(const struct cheesemap_raw* map, static bool cm_raw_find(const struct cheesemap_raw* map, const struct cheesemap_fns* fns, cm_hash_t hash, uintptr_t key_size, const uint8_t* key, - uintptr_t* out_index) { + uintptr_t value_size, uintptr_t* out_index) { assert(map != NULL && fns != NULL); assert(key != NULL && out_index != NULL); @@ -246,7 +246,7 @@ static bool cm_raw_find(const struct cheesemap_raw* map, group_t group = cm_group_load(ctrl); if (cm_raw_find_in_group(map, fns, group, &seq, h2, key_size, key, - out_index)) + value_size, out_index)) return true; if (cm_group_match_empty(group) != 0) return false; @@ -367,7 +367,8 @@ bool cm_raw_lookup(struct cheesemap_raw* map, const struct cheesemap_fns* fns, cm_hash_t hash = fns->hash(key, fns->map_usr); uintptr_t index; - if (!cm_raw_find(map, fns, hash, key_size, key, &index)) return false; + if (!cm_raw_find(map, fns, hash, key_size, key, value_size, &index)) + return false; uint8_t* elem = cm_raw_elem_at(map, index, key_size + value_size); *out_value = elem + key_size; @@ -383,7 +384,8 @@ bool cm_raw_remove(struct cheesemap_raw* map, const struct cheesemap_fns* fns, cm_hash_t hash = fns->hash(key, fns->map_usr); uintptr_t index; - if (!cm_raw_find(map, fns, hash, key_size, key, &index)) return false; + if (!cm_raw_find(map, fns, hash, key_size, key, value_size, &index)) + return false; if (out_value != NULL) { uint8_t* elem = cm_raw_elem_at(map, index, key_size + value_size); @@ -465,6 +467,38 @@ void cm_drop(struct cheesemap* map) { memset(map, 0, sizeof(*map)); } +bool cm_insert(struct cheesemap* map, const uint8_t* key, + const uint8_t* value) { + assert(map != NULL); + assert(key != NULL && value != NULL); + + return cm_raw_insert(&map->raw, &map->fns, map->key_size, key, + map->value_size, value); +} + +bool cm_lookup(struct cheesemap* map, const uint8_t* key, uint8_t** out_value) { + assert(map != NULL); + assert(key != NULL && out_value != NULL); + + return cm_raw_lookup(&map->raw, &map->fns, map->key_size, key, + map->value_size, out_value); +} + +bool cm_remove(struct cheesemap* map, const uint8_t* key, uint8_t* out_value) { + assert(map != NULL); + assert(key != NULL); + + return cm_raw_remove(&map->raw, &map->fns, map->key_size, key, + map->value_size, out_value); +} + +bool cm_reserve(struct cheesemap* map, uintptr_t additional) { + assert(map != NULL); + + return cm_raw_reserve(&map->raw, &map->fns, map->key_size, map->value_size, + additional); +} + /* iterator */ static inline uint8_t* cm_raw_iter_next_entry( const struct cheesemap_raw_iter* iter, uint8_t* old_entry, @@ -533,3 +567,28 @@ bool cheesemap_raw_iter_next(struct cheesemap_raw_iter* iter, iter->n_entry = cm_raw_iter_next_entry(iter, iter->n_entry, entry_size); } } + +void cm_iter_init(struct cheesemap_iter* iter, const struct cheesemap* map) { + assert(iter != NULL && map != NULL); + + iter->key_size = map->key_size; + iter->value_size = map->value_size; + cm_raw_iter_init(&iter->raw, &map->raw, map->key_size + map->value_size, 0); +} + +bool cm_iter_next(struct cheesemap_iter* iter, const struct cheesemap* map, + uint8_t** out_key, uint8_t** out_value) { + assert(iter != NULL && map != NULL); + assert(out_key != NULL && out_value != NULL); + + uintptr_t index; + if (!cheesemap_raw_iter_next(&iter->raw, iter->key_size + iter->value_size, + &index)) + return false; + + uint8_t* elem = + cm_raw_elem_at(&map->raw, index, iter->key_size + iter->value_size); + *out_key = elem; + *out_value = elem + iter->key_size; + return true; +} diff --git a/cheesemap.h b/cheesemap.h index 423ec17..d1f72ef 100644 --- a/cheesemap.h +++ b/cheesemap.h @@ -140,6 +140,11 @@ void cm_new(struct cheesemap* map, uintptr_t key_size, uintptr_t value_size, uint8_t* mem_usr, cm_malloc_fn malloc, cm_free_fn free, uint8_t* map_usr, cm_hash_fn hash, cm_compare_fn compare); void cm_drop(struct cheesemap* map); +bool cm_insert(struct cheesemap* map, const uint8_t* key, + const uint8_t* value); +bool cm_lookup(struct cheesemap* map, const uint8_t* key, uint8_t** out_value); +bool cm_remove(struct cheesemap* map, const uint8_t* key, uint8_t* out_value); +bool cm_reserve(struct cheesemap* map, uintptr_t additional); //////////////////////////////// // cheesemap iterators @@ -159,6 +164,14 @@ void cm_raw_iter_init(struct cheesemap_raw_iter* iter, bool cheesemap_raw_iter_next(struct cheesemap_raw_iter* iter, uintptr_t entry_size, uintptr_t* out_index); +struct cheesemap_iter { + uintptr_t key_size, value_size; + struct cheesemap_raw_iter raw; +}; + +void cm_iter_init(struct cheesemap_iter* iter, const struct cheesemap* map); +bool cm_iter_next(struct cheesemap_iter* iter, const struct cheesemap* map, + uint8_t** out_key, uint8_t** out_value); #ifdef __cplusplus } @@ -41,9 +41,7 @@ int main() { for (uint64_t i = 0; i < num_entries; i++) { uint64_t key = i; uint64_t value = i * 2; - bool success = - cm_raw_insert(&map.raw, &map.fns, sizeof(uint64_t), (uint8_t*)&key, - sizeof(uint64_t), (uint8_t*)&value); + bool success = cm_insert(&map, (uint8_t*)&key, (uint8_t*)&value); if (!success) { printf("Insert failed at i=%lu\n", i); cm_drop(&map); @@ -61,6 +59,104 @@ int main() { printf("Map buckets: %lu\n", map.raw.bucket_mask + 1); printf("Growth left: %lu\n", map.raw.growth_left); + // Test lookups + printf("\nTesting lookups...\n"); + for (uint64_t i = 0; i < 10; i++) { + uint64_t key = i * 100000; + uint8_t* value_ptr; + if (cm_lookup(&map, (uint8_t*)&key, &value_ptr)) { + uint64_t value = *(uint64_t*)value_ptr; + printf(" Lookup key=%lu -> value=%lu (expected %lu)\n", key, value, + key * 2); + } else { + printf(" Lookup key=%lu FAILED\n", key); + } + } + + // Test iteration + printf("\nIterating first 10 entries...\n"); + struct cheesemap_iter iter; + cm_iter_init(&iter, &map); + uintptr_t count = 0; + uint8_t *key_ptr, *value_ptr; + while (cm_iter_next(&iter, &map, &key_ptr, &value_ptr)) { + uint64_t key = *(uint64_t*)key_ptr; + uint64_t value = *(uint64_t*)value_ptr; + if (count < 10) { + printf(" [%lu] key=%lu, value=%lu\n", count, key, value); + } + count++; + } + printf(" Total iterated: %lu entries\n", count); + + // Test removes + printf("\nTesting removes...\n"); + for (uint64_t i = 0; i < 5; i++) { + uint64_t key = i * 200000; + uint64_t old_value; + if (cm_remove(&map, (uint8_t*)&key, (uint8_t*)&old_value)) { + printf(" Removed key=%lu, old_value=%lu\n", key, old_value); + } else { + printf(" Remove key=%lu FAILED\n", key); + } + } + printf("Map count after removes: %lu\n", map.raw.count); + + // Verify removes worked + printf("\nVerifying removes...\n"); + for (uint64_t i = 0; i < 5; i++) { + uint64_t key = i * 200000; + uint8_t* value_ptr; + if (cm_lookup(&map, (uint8_t*)&key, &value_ptr)) { + printf(" ERROR: key=%lu still exists!\n", key); + } else { + printf(" Confirmed key=%lu removed\n", key); + } + } + + // Deep check: verify ALL remaining entries + printf("\nDeep check: verifying all %lu remaining entries...\n", + map.raw.count); + uint64_t checked = 0, errors = 0; + for (uint64_t i = 0; i < num_entries; i++) { + uint64_t key = i; + uint8_t* value_ptr; + bool should_exist = (i % 200000 != 0 || i / 200000 >= 5); + + if (cm_lookup(&map, (uint8_t*)&key, &value_ptr)) { + uint64_t value = *(uint64_t*)value_ptr; + if (!should_exist) { + printf(" ERROR: key=%lu exists but should be removed!\n", key); + errors++; + } else if (value != key * 2) { + printf(" ERROR: key=%lu has wrong value %lu (expected %lu)\n", key, + value, key * 2); + errors++; + } + checked++; + } else { + if (should_exist) { + printf(" ERROR: key=%lu missing but should exist!\n", key); + errors++; + } + } + } + printf(" Checked %lu entries, found %lu errors\n", checked, errors); + + // Verify iteration count matches + printf("\nVerifying iteration count...\n"); + cm_iter_init(&iter, &map); + count = 0; + while (cm_iter_next(&iter, &map, &key_ptr, &value_ptr)) { + count++; + } + if (count == map.raw.count) { + printf(" OK: iteration count %lu matches map count\n", count); + } else { + printf(" ERROR: iteration count %lu != map count %lu\n", count, + map.raw.count); + } + // Calculate memory usage uintptr_t entry_size = sizeof(uint64_t) + sizeof(uint64_t); uintptr_t buckets = map.raw.bucket_mask + 1; |
