aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md13
-rw-r--r--cheesemap.c264
-rw-r--r--cheesemap.h121
-rw-r--r--cm-demo.c13
4 files changed, 210 insertions, 201 deletions
diff --git a/README.md b/README.md
index 759b7d0..a07a78e 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ is not yet production tested but fully working.
#include "cheesemap.h"
-_Noreturn void panic_impl(const char* file, uint32_t line, const char* fmt,
+_Noreturn void panic_impl(const char* file, cm_u32 line, const char* fmt,
...) {
fprintf(stderr, "Panic at %s:%u: ", file, line);
va_list args;
@@ -30,29 +30,29 @@ _Noreturn void panic_impl(const char* file, uint32_t line, const char* fmt,
#define countof(arr) (sizeof(arr) / sizeof(*(arr)))
// Simple hash function for string keys
-uint64_t hash_string(const uint8_t* key, uint8_t* user) {
+cm_u64 hash_string(const cm_u8* key, cm_u8* user) {
(void)user;
const char* str = *(const char**)key;
- uint64_t hash = 5381;
+ cm_u64 hash = 5381;
int c;
while ((c = *str++)) hash = ((hash << 5) + hash) + c; // hash * 33 + c
return hash;
}
// Compare function for string keys
-bool compare_string(const uint8_t* key1, const uint8_t* key2, uint8_t* user) {
+bool compare_string(const cm_u8* key1, const cm_u8* key2, cm_u8* user) {
(void)user;
return strcmp(*(const char**)key1, *(const char**)key2) == 0;
}
// Default allocator (uses malloc)
-void* default_alloc(uintptr_t size, uint8_t* user) {
+void* default_alloc(cm_usize size, cm_u8* user) {
(void)user;
return malloc(size);
}
// Default deallocator (uses free)
-void default_dealloc(void* ptr, uint8_t* user) {
+void default_dealloc(void* ptr, cm_u8* user) {
(void)user;
free(ptr);
}
@@ -108,4 +108,3 @@ int main(void) {
Copyright © 2026 Fabrice
```
-
diff --git a/cheesemap.c b/cheesemap.c
index 36ad496..af57ab0 100644
--- a/cheesemap.c
+++ b/cheesemap.c
@@ -7,29 +7,29 @@
#define CM_ATTR(...) __attribute__((__VA_ARGS__))
-CM_ATTR(hot) static inline uintptr_t cm_ctz(uintptr_t val) {
+CM_ATTR(hot) static inline cm_usize cm_ctz(cm_usize val) {
cm_assert(val != 0);
#if UINTPTR_MAX == UINT64_MAX
- return (uintptr_t)__builtin_ctzll(val);
+ return (cm_usize)__builtin_ctzll(val);
#elif UINTPTR_MAX == UINT32_MAX
- return (uintptr_t)__builtin_ctz(val);
+ return (cm_usize)__builtin_ctz(val);
#else
#error "unknown word width"
#endif
}
-CM_ATTR(hot) static inline uintptr_t cm_clz(uintptr_t val) {
+CM_ATTR(hot) static inline cm_usize cm_clz(cm_usize val) {
cm_assert(val != 0);
#if UINTPTR_MAX == UINT64_MAX
- return (uintptr_t)__builtin_clzll(val);
+ return (cm_usize)__builtin_clzll(val);
#elif UINTPTR_MAX == UINT32_MAX
- return (uintptr_t)__builtin_clz(val);
+ return (cm_usize)__builtin_clz(val);
#else
#error "unknown word width"
#endif
}
-CM_ATTR(hot) static inline uintptr_t cm_bitmask_lowest_set_bit(bitmask_t mask) {
+CM_ATTR(hot) static inline cm_usize cm_bitmask_lowest_set_bit(bitmask_t mask) {
#if CM_GROUP_SIZE == 8
return cm_ctz(mask) / CHAR_BIT;
#elif CM_GROUP_SIZE == 16
@@ -39,7 +39,7 @@ CM_ATTR(hot) static inline uintptr_t cm_bitmask_lowest_set_bit(bitmask_t mask) {
#endif
}
-CM_ATTR(hot) static inline uintptr_t cm_bitmask_ctz(bitmask_t mask) {
+CM_ATTR(hot) static inline cm_usize cm_bitmask_ctz(bitmask_t mask) {
if (mask == 0) return CM_GROUP_SIZE;
#if CM_GROUP_SIZE == 8
return cm_ctz(mask) / CHAR_BIT;
@@ -50,7 +50,7 @@ CM_ATTR(hot) static inline uintptr_t cm_bitmask_ctz(bitmask_t mask) {
#endif
}
-CM_ATTR(hot) static inline uintptr_t cm_bitmask_clz(bitmask_t mask) {
+CM_ATTR(hot) static inline cm_usize cm_bitmask_clz(bitmask_t mask) {
if (mask == 0) return CM_GROUP_SIZE;
#if CM_GROUP_SIZE == 8
return cm_clz(mask) / CHAR_BIT;
@@ -64,25 +64,25 @@ CM_ATTR(hot) static inline uintptr_t cm_bitmask_clz(bitmask_t mask) {
#define cm_max(x, y) ((x) > (y) ? (x) : (y))
#define cm_ispow2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-static inline uintptr_t cm_align_up(uintptr_t value, uintptr_t alignment) {
+static inline cm_usize cm_align_up(cm_usize value, cm_usize alignment) {
cm_assert(cm_ispow2(alignment));
return (value + alignment - 1) & ~(alignment - 1);
}
-static inline uintptr_t cm_npow2(uintptr_t v) {
+static inline cm_usize cm_npow2(cm_usize v) {
if (v <= 1) return 1;
- return (uintptr_t)1 << (CM_WORD_WIDTH - cm_clz(v - 1));
+ return (cm_usize)1 << (CM_WORD_WIDTH - cm_clz(v - 1));
}
struct sequence {
- uintptr_t pos;
- uintptr_t stride;
+ cm_usize pos;
+ cm_usize stride;
};
#define sequence_init(pos, stride) ((struct sequence){pos, stride})
static inline void cm_sequence_next(struct sequence* sequence,
- uintptr_t bucket_mask) {
+ cm_usize bucket_mask) {
cm_assert(sequence != NULL);
cm_assert(sequence->stride <= bucket_mask);
@@ -92,28 +92,28 @@ static inline void cm_sequence_next(struct sequence* sequence,
}
/* ctrl ops */
-static inline bool cm_ctrl_is_special(uint8_t v) { return v & CM_CTRL_DELETED; }
+static inline bool cm_ctrl_is_special(cm_u8 v) { return v & CM_CTRL_DELETED; }
-static inline bool cm_ctrl_is_empty(uint8_t v) {
+static inline bool cm_ctrl_is_empty(cm_u8 v) {
cm_assert(cm_ctrl_is_special(v) == true);
return (v & CM_CTRL_END) != 0;
}
/* group ops */
-static inline group_t cm_group_load(const uint8_t* ctrl);
-static inline bitmask_t cm_group_match_tag(group_t group, uint8_t tag);
+static inline group_t cm_group_load(const cm_u8* ctrl);
+static inline bitmask_t cm_group_match_tag(group_t group, cm_u8 tag);
static inline bitmask_t cm_group_match_empty_or_deleted(group_t group);
static inline bitmask_t cm_group_match_empty(group_t group);
static inline bitmask_t cm_group_match_full(group_t group);
/* sse2 implementation */
#ifdef CM_ENABLE_SSE2
-static inline group_t cm_group_load(const uint8_t* ctrl) {
+static inline group_t cm_group_load(const cm_u8* ctrl) {
cm_assert(ctrl != NULL);
return _mm_loadu_si128((const group_t*)ctrl);
}
-static inline bitmask_t cm_group_match_tag(group_t group, uint8_t tag) {
+static inline bitmask_t cm_group_match_tag(group_t group, cm_u8 tag) {
const __m128i tagvec = _mm_set1_epi8(tag);
__m128i cmp = _mm_cmpeq_epi8(group, tagvec);
return _mm_movemask_epi8(cmp);
@@ -134,11 +134,11 @@ static inline bitmask_t cm_group_match_full(group_t group) {
/* scalar implementation */
#ifndef CM_NO_FALLBACK
-static inline group_t cm_group_repeat(uint8_t v) {
- return (group_t)v * (((group_t)-1) / (uint8_t)~0);
+static inline group_t cm_group_repeat(cm_u8 v) {
+ return (group_t)v * (((group_t)-1) / (cm_u8)~0);
}
-static inline group_t cm_group_load(const uint8_t* ctrl) {
+static inline group_t cm_group_load(const cm_u8* ctrl) {
cm_assert(ctrl != NULL);
group_t v;
@@ -159,7 +159,7 @@ static inline bitmask_t cm_group_match_full(group_t group) {
cm_group_repeat(CM_CTRL_DELETED);
}
-static inline bitmask_t cm_group_match_tag(group_t group, uint8_t tag) {
+static inline bitmask_t cm_group_match_tag(group_t group, cm_u8 tag) {
group_t cmp = group ^ cm_group_repeat(tag);
return (cmp - cm_group_repeat(CM_CTRL_END)) & ~cmp &
cm_group_repeat(CM_CTRL_DELETED);
@@ -168,59 +168,59 @@ static inline bitmask_t cm_group_match_tag(group_t group, uint8_t tag) {
/* ctrl's n stuff */
-static inline uintptr_t cm_h1(cm_hash_t hash) {
- return (uintptr_t)(hash >> CM_FP_SIZE);
+static inline cm_usize cm_h1(cm_hash_t hash) {
+ return (cm_usize)(hash >> CM_FP_SIZE);
}
-static inline uint8_t cm_h2(cm_hash_t hash) {
- uintptr_t top = hash >> (sizeof(cm_hash_t) * CHAR_BIT - CM_FP_SIZE);
- return (uint8_t)(top & CM_H2_MASK);
+static inline cm_u8 cm_h2(cm_hash_t hash) {
+ cm_usize top = hash >> (sizeof(cm_hash_t) * CHAR_BIT - CM_FP_SIZE);
+ return (cm_u8)(top & CM_H2_MASK);
}
-const uint8_t CM_CTRL_STATIC_EMPTY[CM_GROUP_SIZE] = {[0 ... CM_GROUP_SIZE - 1] =
- CM_CTRL_EMPTY};
+const cm_u8 CM_CTRL_STATIC_EMPTY[CM_GROUP_SIZE] = {[0 ... CM_GROUP_SIZE - 1] =
+ CM_CTRL_EMPTY};
/* hashmap implementation */
-static inline uintptr_t cm_buckets_to_capacity(uintptr_t bucket_mask) {
- uintptr_t num_buckets = bucket_mask + 1;
+static inline cm_usize cm_buckets_to_capacity(cm_usize bucket_mask) {
+ cm_usize num_buckets = bucket_mask + 1;
return (num_buckets / CM_LOAD_DENOM) * CM_LOAD_NUM;
}
-static inline uintptr_t cm_capacity_to_buckets(uintptr_t capacity) {
- uintptr_t min_buckets =
+static inline cm_usize cm_capacity_to_buckets(cm_usize capacity) {
+ cm_usize min_buckets =
(capacity * CM_LOAD_DENOM + CM_LOAD_NUM - 1) / CM_LOAD_NUM;
- uintptr_t buckets = cm_npow2(min_buckets);
+ cm_usize buckets = cm_npow2(min_buckets);
return cm_max(buckets, CM_GROUP_SIZE);
}
-static inline uintptr_t cm_ctrl_offset(uintptr_t buckets,
- const struct cm_type* type) {
- uintptr_t offset = type->entry_size * buckets;
+static inline cm_usize cm_ctrl_offset(cm_usize buckets,
+ const struct cm_type* type) {
+ cm_usize offset = type->entry_size * buckets;
return cm_align_up(offset, CM_GROUP_SIZE);
}
-static inline uint8_t* cm_raw_elem_at(const struct cheesemap_raw* map,
- uintptr_t index,
- const struct cm_type* type) {
+static inline cm_u8* cm_raw_elem_at(const struct cheesemap_raw* map,
+ cm_usize index,
+ const struct cm_type* type) {
cm_assert(map != NULL);
cm_assert(map->bucket_mask + 1 > index);
return map->ctrl - type->entry_size * (index + 1);
}
-static inline uint8_t* cm_raw_origin(const struct cheesemap_raw* map,
- const struct cm_type* type) {
+static inline cm_u8* cm_raw_origin(const struct cheesemap_raw* map,
+ const struct cm_type* type) {
cm_assert(map != NULL);
- uintptr_t buckets = map->bucket_mask + 1;
- uintptr_t ctrl_offset = cm_ctrl_offset(buckets, type);
+ cm_usize buckets = map->bucket_mask + 1;
+ cm_usize ctrl_offset = cm_ctrl_offset(buckets, type);
return map->ctrl - ctrl_offset;
}
-static inline void cm_raw_ctrl_set(struct cheesemap_raw* map, uintptr_t index,
- uint8_t ctrl) {
+static inline void cm_raw_ctrl_set(struct cheesemap_raw* map, cm_usize index,
+ cm_u8 ctrl) {
cm_assert(map != NULL);
- uintptr_t index2 =
+ cm_usize index2 =
((index - CM_GROUP_SIZE) & map->bucket_mask) + CM_GROUP_SIZE;
map->ctrl[index] = ctrl;
map->ctrl[index2] = ctrl;
@@ -229,7 +229,7 @@ static inline void cm_raw_ctrl_set(struct cheesemap_raw* map, uintptr_t index,
static bool cm_raw_find_insert_index_in_group(const struct cheesemap_raw* map,
const group_t* group,
const struct sequence* seq,
- uintptr_t* out_index) {
+ cm_usize* out_index) {
cm_assert(map != NULL);
cm_assert(group != NULL && seq != NULL);
cm_assert(out_index != NULL);
@@ -237,21 +237,21 @@ static bool cm_raw_find_insert_index_in_group(const struct cheesemap_raw* map,
bitmask_t mask = cm_group_match_empty_or_deleted(*group);
if (mask == 0) return false;
- uintptr_t bucket_offset = cm_bitmask_lowest_set_bit(mask);
+ cm_usize bucket_offset = cm_bitmask_lowest_set_bit(mask);
*out_index = (seq->pos + bucket_offset) & map->bucket_mask;
return true;
}
-static uintptr_t cm_raw_find_insert_index(const struct cheesemap_raw* map,
- cm_hash_t hash) {
+static cm_usize cm_raw_find_insert_index(const struct cheesemap_raw* map,
+ cm_hash_t hash) {
cm_assert(map != NULL);
struct sequence seq = sequence_init(cm_h1(hash) & map->bucket_mask, 0);
while (true) {
- uint8_t* ctrl = &map->ctrl[seq.pos];
+ cm_u8* ctrl = &map->ctrl[seq.pos];
group_t group = cm_group_load(ctrl);
- uintptr_t index;
+ cm_usize index;
if (cm_raw_find_insert_index_in_group(map, &group, &seq, &index))
return index;
cm_sequence_next(&seq, map->bucket_mask);
@@ -259,20 +259,20 @@ static uintptr_t cm_raw_find_insert_index(const struct cheesemap_raw* map,
}
static bool cm_raw_find_in_group(const struct cheesemap_raw* map,
- cm_compare_fn compare, uint8_t* user,
+ cm_compare_fn compare, cm_u8* user,
group_t group, const struct sequence* seq,
- uint8_t h2, const struct cm_type* type,
- const uint8_t* key, uintptr_t* out_index) {
+ cm_u8 h2, const struct cm_type* type,
+ const cm_u8* key, cm_usize* out_index) {
cm_assert(map != NULL && compare != NULL);
cm_assert(seq != NULL);
cm_assert(key != NULL && out_index != NULL);
bitmask_t mask = cm_group_match_tag(group, h2);
while (mask != 0) {
- uintptr_t bucket_offset = cm_bitmask_lowest_set_bit(mask);
- uintptr_t index = (seq->pos + bucket_offset) & map->bucket_mask;
+ cm_usize bucket_offset = cm_bitmask_lowest_set_bit(mask);
+ cm_usize index = (seq->pos + bucket_offset) & map->bucket_mask;
- uint8_t* elem = cm_raw_elem_at(map, index, type);
+ cm_u8* elem = cm_raw_elem_at(map, index, type);
if (compare(key, elem, user)) {
*out_index = index;
return true;
@@ -285,17 +285,16 @@ static bool cm_raw_find_in_group(const struct cheesemap_raw* map,
}
static bool cm_raw_find(const struct cheesemap_raw* map, cm_compare_fn compare,
- uint8_t* user, cm_hash_t hash,
- const struct cm_type* type, const uint8_t* key,
- uintptr_t* out_index) {
+ cm_u8* user, cm_hash_t hash, const struct cm_type* type,
+ const cm_u8* key, cm_usize* out_index) {
cm_assert(map != NULL && compare != NULL);
cm_assert(key != NULL && out_index != NULL);
- uint8_t h2 = cm_h2(hash);
+ cm_u8 h2 = cm_h2(hash);
struct sequence seq = sequence_init(cm_h1(hash) & map->bucket_mask, 0);
while (true) {
- uint8_t* ctrl = &map->ctrl[seq.pos];
+ cm_u8* ctrl = &map->ctrl[seq.pos];
group_t group = cm_group_load(ctrl);
if (cm_raw_find_in_group(map, compare, user, group, &seq, h2, type, key,
@@ -309,16 +308,16 @@ static bool cm_raw_find(const struct cheesemap_raw* map, cm_compare_fn compare,
}
static void cm_raw_insert_at(struct cheesemap_raw* map, cm_hash_t hash,
- uintptr_t index, const struct cm_type* type,
- const uint8_t* key, const uint8_t* value) {
+ cm_usize index, const struct cm_type* type,
+ const cm_u8* key, const cm_u8* value) {
cm_assert(map != NULL);
cm_assert(value != NULL);
- uint8_t old_ctrl = map->ctrl[index];
+ cm_u8 old_ctrl = map->ctrl[index];
map->growth_left -= cm_ctrl_is_empty(old_ctrl);
cm_raw_ctrl_set(map, index, cm_h2(hash));
- uint8_t* elem = cm_raw_elem_at(map, index, type);
+ cm_u8* elem = cm_raw_elem_at(map, index, type);
memcpy(elem, key, type->key_size);
memcpy(elem + type->value_offset, value, type->value_size);
@@ -327,22 +326,22 @@ static void cm_raw_insert_at(struct cheesemap_raw* map, cm_hash_t hash,
static void cm_raw_rehash(struct cheesemap_raw* old_map,
struct cheesemap_raw* new_map, cm_hash_fn hash,
- uint8_t* user, const struct cm_type* type) {
+ cm_u8* user, const struct cm_type* type) {
cm_assert(old_map != NULL);
cm_assert(new_map != NULL && hash != NULL);
struct cheesemap_raw_iter iter;
cm_raw_iter_init(&iter, old_map, type, 0);
- uintptr_t index;
+ cm_usize index;
while (cm_raw_iter_next(&iter, type, &index)) {
- uint8_t* elem = cm_raw_elem_at(old_map, index, type);
+ cm_u8* elem = cm_raw_elem_at(old_map, index, type);
cm_hash_t h = hash(elem, user);
- uintptr_t new_index = cm_raw_find_insert_index(new_map, h);
+ cm_usize new_index = cm_raw_find_insert_index(new_map, h);
cm_raw_ctrl_set(new_map, new_index, cm_h2(h));
- uint8_t* new_elem = cm_raw_elem_at(new_map, new_index, type);
+ cm_u8* new_elem = cm_raw_elem_at(new_map, new_index, type);
memcpy(new_elem, elem, type->entry_size);
}
@@ -353,8 +352,8 @@ static void cm_raw_rehash(struct cheesemap_raw* old_map,
static bool cm_raw_resize(struct cheesemap_raw* map, cm_hash_fn hash,
cm_alloc_fn alloc, cm_dealloc_fn dealloc,
- uint8_t* user, const struct cm_type* type,
- uintptr_t new_capacity) {
+ cm_u8* user, const struct cm_type* type,
+ cm_usize new_capacity) {
cm_assert(map != NULL && hash != NULL);
cm_assert(alloc != NULL && dealloc != NULL);
@@ -370,20 +369,20 @@ static bool cm_raw_resize(struct cheesemap_raw* map, cm_hash_fn hash,
}
bool cm_raw_new_with(struct cheesemap_raw* map, cm_alloc_fn alloc,
- uint8_t* user, const struct cm_type* type,
- uintptr_t initial_capacity) {
+ cm_u8* user, const struct cm_type* type,
+ cm_usize initial_capacity) {
cm_assert(map != NULL);
cm_assert(alloc != NULL);
memset(map, 0, sizeof(*map));
- uintptr_t buckets = cm_capacity_to_buckets(initial_capacity);
- uintptr_t ctrl_offset = cm_ctrl_offset(buckets, type);
- uintptr_t size = ctrl_offset + buckets + CM_GROUP_SIZE;
+ cm_usize buckets = cm_capacity_to_buckets(initial_capacity);
+ cm_usize ctrl_offset = cm_ctrl_offset(buckets, type);
+ cm_usize size = ctrl_offset + buckets + CM_GROUP_SIZE;
- uint8_t* ptr = alloc(size, user);
+ cm_u8* ptr = alloc(size, user);
if (ptr == NULL) return false;
- uint8_t* ctrl = ptr + ctrl_offset;
+ cm_u8* ctrl = ptr + ctrl_offset;
memset(ctrl, CM_CTRL_EMPTY, buckets);
memcpy(ctrl + buckets, ctrl, CM_GROUP_SIZE);
@@ -395,63 +394,63 @@ bool cm_raw_new_with(struct cheesemap_raw* map, cm_alloc_fn alloc,
}
bool cm_raw_reserve(struct cheesemap_raw* map, cm_hash_fn hash,
- cm_alloc_fn alloc, cm_dealloc_fn dealloc, uint8_t* user,
- const struct cm_type* type, uintptr_t additional) {
+ cm_alloc_fn alloc, cm_dealloc_fn dealloc, cm_u8* user,
+ const struct cm_type* type, cm_usize additional) {
cm_assert(map != NULL && hash != NULL);
cm_assert(alloc != NULL && dealloc != NULL);
if (map->growth_left >= additional) return true;
// TODO: inplace rehash
- uintptr_t needed = map->count + additional;
- uintptr_t capacity = cm_buckets_to_capacity(map->bucket_mask);
- uintptr_t new_capacity = cm_max(needed, capacity + 1);
+ cm_usize needed = map->count + additional;
+ cm_usize capacity = cm_buckets_to_capacity(map->bucket_mask);
+ cm_usize new_capacity = cm_max(needed, capacity + 1);
return cm_raw_resize(map, hash, alloc, dealloc, user, type, new_capacity);
}
bool cm_raw_lookup(const struct cheesemap_raw* map, cm_hash_fn hash,
- cm_compare_fn compare, uint8_t* user,
- const struct cm_type* type, const uint8_t* key,
- uint8_t** out_value) {
+ cm_compare_fn compare, cm_u8* user,
+ const struct cm_type* type, const cm_u8* key,
+ cm_u8** out_value) {
cm_assert(map != NULL && hash != NULL);
cm_assert(key != NULL && out_value != NULL);
cm_hash_t h = hash(key, user);
- uintptr_t index;
+ cm_usize index;
if (!cm_raw_find(map, compare, user, h, type, key, &index)) return false;
- uint8_t* elem = cm_raw_elem_at(map, index, type);
+ cm_u8* elem = cm_raw_elem_at(map, index, type);
*out_value = elem + type->value_offset;
return true;
}
bool cm_raw_remove(struct cheesemap_raw* map, cm_hash_fn hash,
- cm_compare_fn compare, uint8_t* user,
- const struct cm_type* type, const uint8_t* key,
- uint8_t* out_value) {
+ cm_compare_fn compare, cm_u8* user,
+ const struct cm_type* type, const cm_u8* key,
+ cm_u8* out_value) {
cm_assert(map != NULL && hash != NULL);
cm_assert(key != NULL);
cm_hash_t h = hash(key, user);
- uintptr_t index;
+ cm_usize index;
if (!cm_raw_find(map, compare, user, h, type, key, &index)) return false;
if (out_value != NULL) {
- uint8_t* elem = cm_raw_elem_at(map, index, type);
+ cm_u8* elem = cm_raw_elem_at(map, index, type);
memcpy(out_value, elem + type->value_offset, type->value_size);
}
- uintptr_t index_before = (index - CM_GROUP_SIZE) & map->bucket_mask;
+ cm_usize index_before = (index - CM_GROUP_SIZE) & map->bucket_mask;
group_t group_before = cm_group_load(&map->ctrl[index_before]);
group_t group_at = cm_group_load(&map->ctrl[index]);
bitmask_t empty_before = cm_group_match_empty(group_before);
bitmask_t empty_after = cm_group_match_empty(group_at);
- uintptr_t empty_count =
+ cm_usize empty_count =
cm_bitmask_clz(empty_before) + cm_bitmask_ctz(empty_after);
- uint8_t ctrl =
+ cm_u8 ctrl =
(empty_count >= CM_GROUP_SIZE) ? CM_CTRL_DELETED : CM_CTRL_EMPTY;
if (ctrl == CM_CTRL_EMPTY) map->growth_left += 1;
@@ -463,17 +462,17 @@ bool cm_raw_remove(struct cheesemap_raw* map, cm_hash_fn hash,
}
bool cm_raw_insert(struct cheesemap_raw* map, cm_hash_fn hash,
- cm_alloc_fn alloc, cm_dealloc_fn dealloc, uint8_t* user,
- const struct cm_type* type, const uint8_t* key,
- const uint8_t* value) {
+ cm_alloc_fn alloc, cm_dealloc_fn dealloc, cm_u8* user,
+ const struct cm_type* type, const cm_u8* key,
+ const cm_u8* value) {
cm_assert(map != NULL && hash != NULL);
cm_assert(alloc != NULL && dealloc != NULL);
cm_assert(key != NULL && value != NULL);
cm_hash_t h = hash(key, user);
- uintptr_t index = cm_raw_find_insert_index(map, h);
+ cm_usize index = cm_raw_find_insert_index(map, h);
- uint8_t old_ctrl = map->ctrl[index];
+ cm_u8 old_ctrl = map->ctrl[index];
if (map->growth_left == 0 && cm_ctrl_is_empty(old_ctrl)) {
bool success = cm_raw_reserve(map, hash, alloc, dealloc, user, type, 1);
if (!success) return success;
@@ -485,29 +484,29 @@ bool cm_raw_insert(struct cheesemap_raw* map, cm_hash_fn hash,
}
void cm_raw_drop(struct cheesemap_raw* map, cm_dealloc_fn dealloc,
- uint8_t* user, const struct cm_type* type) {
+ cm_u8* user, const struct cm_type* type) {
cm_assert(map != NULL);
cm_assert(dealloc != NULL);
if (map->ctrl == CM_CTRL_STATIC_EMPTY || map->ctrl == NULL) return;
- uint8_t* origin = cm_raw_origin(map, type);
+ cm_u8* origin = cm_raw_origin(map, type);
dealloc(origin, user);
*map = cm_raw_new();
}
-void cm_new(struct cheesemap* map, uintptr_t key_size, uintptr_t key_align,
- uintptr_t value_size, uintptr_t value_align, uint8_t* user,
+void cm_new(struct cheesemap* map, cm_usize key_size, cm_usize key_align,
+ cm_usize value_size, cm_usize value_align, cm_u8* user,
cm_hash_fn hash, cm_compare_fn compare, cm_alloc_fn alloc,
cm_dealloc_fn dealloc) {
cm_assert(map != NULL);
cm_assert(hash != NULL && compare != NULL);
cm_assert(alloc != NULL && dealloc != NULL);
- uintptr_t value_offset = cm_align_up(key_size, value_align);
- uintptr_t max_align = cm_max(key_align, value_align);
- uintptr_t entry_size = cm_align_up(value_offset + value_size, max_align);
+ cm_usize value_offset = cm_align_up(key_size, value_align);
+ cm_usize max_align = cm_max(key_align, value_align);
+ cm_usize entry_size = cm_align_up(value_offset + value_size, max_align);
struct cm_type type =
cm_type_construct(key_size, value_size, value_offset, entry_size);
@@ -521,8 +520,7 @@ 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) {
+bool cm_insert(struct cheesemap* map, const cm_u8* key, const cm_u8* value) {
cm_assert(map != NULL);
cm_assert(key != NULL && value != NULL);
@@ -530,8 +528,8 @@ bool cm_insert(struct cheesemap* map, const uint8_t* key,
map->user, &map->type, key, value);
}
-bool cm_lookup(const struct cheesemap* map, const uint8_t* key,
- uint8_t** out_value) {
+bool cm_lookup(const struct cheesemap* map, const cm_u8* key,
+ cm_u8** out_value) {
cm_assert(map != NULL);
cm_assert(key != NULL && out_value != NULL);
@@ -539,7 +537,7 @@ bool cm_lookup(const struct cheesemap* map, const uint8_t* key,
&map->type, key, out_value);
}
-bool cm_remove(struct cheesemap* map, const uint8_t* key, uint8_t* out_value) {
+bool cm_remove(struct cheesemap* map, const cm_u8* key, cm_u8* out_value) {
cm_assert(map != NULL);
cm_assert(key != NULL);
@@ -547,7 +545,7 @@ bool cm_remove(struct cheesemap* map, const uint8_t* key, uint8_t* out_value) {
&map->type, key, out_value);
}
-bool cm_reserve(struct cheesemap* map, uintptr_t additional) {
+bool cm_reserve(struct cheesemap* map, cm_usize additional) {
cm_assert(map != NULL);
return cm_raw_reserve(&map->raw, map->hash, map->alloc, map->dealloc,
@@ -555,23 +553,23 @@ bool cm_reserve(struct cheesemap* map, uintptr_t additional) {
}
/* iterator */
-static inline uint8_t* cm_raw_iter_next_entry(uint8_t* old_entry,
- const struct cm_type* type) {
+static inline cm_u8* cm_raw_iter_next_entry(cm_u8* old_entry,
+ const struct cm_type* type) {
return old_entry - type->entry_size * CM_GROUP_SIZE;
}
void cm_raw_iter_init(struct cheesemap_raw_iter* iter,
const struct cheesemap_raw* map,
- const struct cm_type* type, uintptr_t start_index) {
+ const struct cm_type* type, cm_usize start_index) {
cm_assert(map != NULL);
cm_assert(start_index % CM_GROUP_SIZE == 0);
memset(iter, 0, sizeof(*iter));
- uintptr_t buckets = map->bucket_mask + 1;
+ cm_usize buckets = map->bucket_mask + 1;
cm_assert(buckets > start_index);
- uint8_t* ctrl = &map->ctrl[start_index];
- uint8_t* entry = cm_raw_elem_at(map, start_index, type);
+ cm_u8* ctrl = &map->ctrl[start_index];
+ cm_u8* entry = cm_raw_elem_at(map, start_index, type);
group_t group = cm_group_load(ctrl);
bitmask_t mask = cm_group_match_full(group);
@@ -593,18 +591,18 @@ static inline void cm_raw_iter_next_inner_slow(
iter->curr_index += CM_GROUP_SIZE;
}
-static inline uintptr_t cm_raw_iter_next_inner_fast(
+static inline cm_usize cm_raw_iter_next_inner_fast(
struct cheesemap_raw_iter* iter) {
cm_assert(iter != NULL);
- uintptr_t bucket_offset = cm_bitmask_lowest_set_bit(iter->curr_mask);
+ cm_usize bucket_offset = cm_bitmask_lowest_set_bit(iter->curr_mask);
iter->curr_mask &= iter->curr_mask - 1;
return iter->curr_index + bucket_offset;
}
bool cm_raw_iter_next(struct cheesemap_raw_iter* iter,
- const struct cm_type* type, uintptr_t* out_index) {
+ const struct cm_type* type, cm_usize* out_index) {
cm_assert(iter != NULL);
cm_assert(out_index != NULL);
@@ -630,14 +628,14 @@ 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) {
+ cm_u8** out_key, cm_u8** out_value) {
cm_assert(iter != NULL && map != NULL);
cm_assert(out_key != NULL && out_value != NULL);
- uintptr_t index;
+ cm_usize index;
if (!cm_raw_iter_next(&iter->raw, &map->type, &index)) return false;
- uint8_t* elem = cm_raw_elem_at(&map->raw, index, &map->type);
+ cm_u8* elem = cm_raw_elem_at(&map->raw, index, &map->type);
*out_key = elem;
*out_value = elem + iter->value_offset;
return true;
diff --git a/cheesemap.h b/cheesemap.h
index cb3d0a9..0241fb1 100644
--- a/cheesemap.h
+++ b/cheesemap.h
@@ -13,7 +13,20 @@ extern "C" {
#include <stdbool.h>
#include <stdint.h>
-void CM_PANIC_SYM(const char* file, uint32_t line, const char* fmt, ...);
+typedef uint8_t cm_u8;
+typedef uint16_t cm_u16;
+typedef uint32_t cm_u32;
+typedef uint64_t cm_u64;
+
+#if UINTPTR_MAX == UINT64_MAX
+typedef cm_u64 cm_usize;
+#elif UINTPTR_MAX == UINT32_MAX
+typedef cm_u32 cm_usize;
+#else
+#error "unsupported uintptr_t width"
+#endif
+
+void CM_PANIC_SYM(const char* file, cm_u32 line, const char* fmt, ...);
#ifdef NDEBUG
#define cm_assert(cond)
@@ -29,13 +42,13 @@ void CM_PANIC_SYM(const char* file, uint32_t line, const char* fmt, ...);
#include <emmintrin.h>
typedef __m128i group_t;
-typedef uint16_t bitmask_t;
+typedef cm_u16 bitmask_t;
#define CM_GROUP_SIZE 16
#define CM_NO_FALLBACK
#endif
#ifndef CM_NO_FALLBACK
-typedef uintptr_t group_t;
+typedef cm_usize group_t;
typedef group_t bitmask_t;
#define CM_GROUP_SIZE __SIZEOF_POINTER__
#endif
@@ -44,16 +57,16 @@ typedef group_t bitmask_t;
// cheesemap callback functions
//
-typedef uint64_t cm_hash_t;
+typedef cm_u64 cm_hash_t;
/* hash and compare methods */
-typedef cm_hash_t (*cm_hash_fn)(const uint8_t* key, uint8_t* user);
-typedef bool (*cm_compare_fn)(const uint8_t* key1, const uint8_t* key2,
- uint8_t* user);
+typedef cm_hash_t (*cm_hash_fn)(const cm_u8* key, cm_u8* user);
+typedef bool (*cm_compare_fn)(const cm_u8* key1, const cm_u8* key2,
+ cm_u8* user);
/* allocator methods */
-typedef void* (*cm_alloc_fn)(uintptr_t size, uint8_t* user);
-typedef void (*cm_dealloc_fn)(void* ptr, uint8_t* user);
+typedef cm_u8* (*cm_alloc_fn)(cm_usize size, cm_u8* user);
+typedef void (*cm_dealloc_fn)(cm_u8* ptr, cm_u8* user);
////////////////////////////////
// raw cheesemap implementation
@@ -81,17 +94,17 @@ enum {
//
// aux
// Size of a word in bits
- CM_WORD_WIDTH = sizeof(uintptr_t) * CHAR_BIT,
+ CM_WORD_WIDTH = sizeof(cm_usize) * CHAR_BIT,
};
-extern const uint8_t CM_CTRL_STATIC_EMPTY[CM_GROUP_SIZE];
+extern const cm_u8 CM_CTRL_STATIC_EMPTY[CM_GROUP_SIZE];
struct cm_type {
- uintptr_t key_size;
- uintptr_t value_size;
- uintptr_t value_offset;
- uintptr_t entry_size;
+ cm_usize key_size;
+ cm_usize value_size;
+ cm_usize value_offset;
+ cm_usize entry_size;
};
#define cm_type_construct(key_size, value_size, value_offset, entry_size) \
@@ -99,38 +112,38 @@ struct cm_type {
struct cheesemap_raw {
// number of buckets as mask
- uintptr_t bucket_mask;
+ cm_usize bucket_mask;
// number of entries in the map
- uintptr_t count;
+ cm_usize count;
// number of entry left until resize
- uintptr_t growth_left;
+ cm_usize growth_left;
// pointer to the control bytes
- uint8_t* ctrl;
+ cm_u8* ctrl;
};
#define cm_raw_new() \
- ((struct cheesemap_raw){.ctrl = (uint8_t*)CM_CTRL_STATIC_EMPTY})
+ ((struct cheesemap_raw){.ctrl = (cm_u8*)CM_CTRL_STATIC_EMPTY})
bool cm_raw_new_with(struct cheesemap_raw* map, cm_alloc_fn alloc,
- uint8_t* user, const struct cm_type* type,
- uintptr_t initial_capacity);
+ cm_u8* user, const struct cm_type* type,
+ cm_usize initial_capacity);
void cm_raw_drop(struct cheesemap_raw* map, cm_dealloc_fn dealloc,
- uint8_t* user, const struct cm_type* type);
+ cm_u8* user, const struct cm_type* type);
bool cm_raw_reserve(struct cheesemap_raw* map, cm_hash_fn hash,
- cm_alloc_fn alloc, cm_dealloc_fn dealloc, uint8_t* user,
- const struct cm_type* type, uintptr_t additional);
+ cm_alloc_fn alloc, cm_dealloc_fn dealloc, cm_u8* user,
+ const struct cm_type* type, cm_usize additional);
bool cm_raw_lookup(const struct cheesemap_raw* map, cm_hash_fn hash,
- cm_compare_fn compare, uint8_t* user,
- const struct cm_type* type, const uint8_t* key,
- uint8_t** out_value);
+ cm_compare_fn compare, cm_u8* user,
+ const struct cm_type* type, const cm_u8* key,
+ cm_u8** out_value);
bool cm_raw_remove(struct cheesemap_raw* map, cm_hash_fn hash,
- cm_compare_fn compare, uint8_t* user,
- const struct cm_type* type, const uint8_t* key,
- uint8_t* out_value);
+ cm_compare_fn compare, cm_u8* user,
+ const struct cm_type* type, const cm_u8* key,
+ cm_u8* out_value);
bool cm_raw_insert(struct cheesemap_raw* map, cm_hash_fn hash,
- cm_alloc_fn alloc, cm_dealloc_fn dealloc, uint8_t* user,
- const struct cm_type* type, const uint8_t* key,
- const uint8_t* value);
+ cm_alloc_fn alloc, cm_dealloc_fn dealloc, cm_u8* user,
+ const struct cm_type* type, const cm_u8* key,
+ const cm_u8* value);
////////////////////////////////
// cheesemap implementation
@@ -138,7 +151,7 @@ bool cm_raw_insert(struct cheesemap_raw* map, cm_hash_fn hash,
struct cheesemap {
struct cm_type type;
- uint8_t* user;
+ cm_u8* user;
cm_hash_fn hash;
cm_compare_fn compare;
cm_alloc_fn alloc;
@@ -149,16 +162,16 @@ struct cheesemap {
#define cm_construct(type, user, hash, compare, alloc, dealloc, raw) \
((struct cheesemap){type, user, hash, compare, alloc, dealloc, raw})
-void cm_new(struct cheesemap* map, uintptr_t key_size, uintptr_t key_align,
- uintptr_t value_size, uintptr_t value_align, uint8_t* user,
+void cm_new(struct cheesemap* map, cm_usize key_size, cm_usize key_align,
+ cm_usize value_size, cm_usize value_align, cm_u8* user,
cm_hash_fn hash, cm_compare_fn compare, cm_alloc_fn alloc,
cm_dealloc_fn dealloc);
void cm_drop(struct cheesemap* map);
-bool cm_insert(struct cheesemap* map, const uint8_t* key, const uint8_t* value);
-bool cm_lookup(const 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);
+bool cm_insert(struct cheesemap* map, const cm_u8* key, const cm_u8* value);
+bool cm_lookup(const struct cheesemap* map, const cm_u8* key,
+ cm_u8** out_value);
+bool cm_remove(struct cheesemap* map, const cm_u8* key, cm_u8* out_value);
+bool cm_reserve(struct cheesemap* map, cm_usize additional);
////////////////////////////////
// cheesemap convenience macros
@@ -169,13 +182,13 @@ bool cm_reserve(struct cheesemap* map, uintptr_t additional);
cmp_fn, alloc_fn, dealloc_fn)
#define cm_lookup_(map, key, out_val) \
- cm_lookup(map, (const uint8_t*)&(key), (uint8_t**)(out_val))
+ cm_lookup(map, (const cm_u8*)&(key), (cm_u8**)(out_val))
#define cm_insert_(map, key, val) \
- cm_insert(map, (const uint8_t*)&(key), (const uint8_t*)&(val))
+ cm_insert(map, (const cm_u8*)&(key), (const cm_u8*)&(val))
#define cm_remove_(map, key, out_val) \
- cm_remove(map, (const uint8_t*)&(key), (uint8_t*)(out_val))
+ cm_remove(map, (const cm_u8*)&(key), (cm_u8*)(out_val))
////////////////////////////////
// cheesemap iterators
@@ -183,29 +196,29 @@ bool cm_reserve(struct cheesemap* map, uintptr_t additional);
struct cheesemap_raw_iter {
bitmask_t curr_mask;
- uintptr_t curr_index;
- uint8_t* n_ctrl;
- uint8_t* n_entry;
- uint8_t* end;
+ cm_usize curr_index;
+ cm_u8* n_ctrl;
+ cm_u8* n_entry;
+ cm_u8* end;
};
void cm_raw_iter_init(struct cheesemap_raw_iter* iter,
const struct cheesemap_raw* map,
- const struct cm_type* type, uintptr_t start_index);
+ const struct cm_type* type, cm_usize start_index);
bool cm_raw_iter_next(struct cheesemap_raw_iter* iter,
- const struct cm_type* type, uintptr_t* out_index);
+ const struct cm_type* type, cm_usize* out_index);
struct cheesemap_iter {
- uintptr_t entry_size, value_offset;
+ cm_usize entry_size, value_offset;
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);
+ cm_u8** out_key, cm_u8** out_value);
#define cm_iter_next_(iter, map, out_key, out_val) \
- cm_iter_next(iter, map, (uint8_t**)(out_key), (uint8_t**)(out_val))
+ cm_iter_next(iter, map, (cm_u8**)(out_key), (cm_u8**)(out_val))
#ifdef __cplusplus
}
diff --git a/cm-demo.c b/cm-demo.c
index 62a689a..0e9f82d 100644
--- a/cm-demo.c
+++ b/cm-demo.c
@@ -5,8 +5,7 @@
#include "cheesemap.h"
-_Noreturn void panic_impl(const char* file, uint32_t line, const char* fmt,
- ...) {
+_Noreturn void panic_impl(const char* file, cm_u32 line, const char* fmt, ...) {
fprintf(stderr, "Panic at %s:%u: ", file, line);
va_list args;
va_start(args, fmt);
@@ -20,29 +19,29 @@ _Noreturn void panic_impl(const char* file, uint32_t line, const char* fmt,
#define countof(arr) (sizeof(arr) / sizeof(*(arr)))
// Simple hash function for string keys
-uint64_t hash_string(const uint8_t* key, uint8_t* user) {
+cm_u64 hash_string(const cm_u8* key, cm_u8* user) {
(void)user;
const char* str = *(const char**)key;
- uint64_t hash = 5381;
+ cm_u64 hash = 5381;
int c;
while ((c = *str++)) hash = ((hash << 5) + hash) + c; // hash * 33 + c
return hash;
}
// Compare function for string keys
-bool compare_string(const uint8_t* key1, const uint8_t* key2, uint8_t* user) {
+bool compare_string(const cm_u8* key1, const cm_u8* key2, cm_u8* user) {
(void)user;
return strcmp(*(const char**)key1, *(const char**)key2) == 0;
}
// Default allocator (uses malloc)
-void* default_alloc(uintptr_t size, uint8_t* user) {
+cm_u8* default_alloc(cm_usize size, cm_u8* user) {
(void)user;
return malloc(size);
}
// Default deallocator (uses free)
-void default_dealloc(void* ptr, uint8_t* user) {
+void default_dealloc(cm_u8* ptr, cm_u8* user) {
(void)user;
free(ptr);
}