Created
November 29, 2025 07:42
-
-
Save leok7v/25ad567d49e6a6ceeeee4aa8dfdb2d9f to your computer and use it in GitHub Desktop.
map_test.c (see map.h/map.c)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "map.h" | |
| #include <assert.h> | |
| #include <string.h> | |
| #include <stdio.h> | |
| #define TEST_INT_PAIR(name, T, v1, v2) \ | |
| static void map_test_##name(void) { \ | |
| struct name map_of(T, T); \ | |
| struct name m = {}; \ | |
| bool ok = map_alloc(&m, 0); assert(ok); \ | |
| ok = map_put(&m, (T)(v1), (T)(v2)); assert(ok); \ | |
| T* r = map_get(&m, (T)(v1)); assert(r && *r == (T)(v2)); \ | |
| ok = map_remove(&m, (T)(v1)); assert(ok); \ | |
| assert(!map_has(&m, (T)(v1))); \ | |
| ok = map_put(&m, (T)(v1), (T)(v2)); assert(ok); \ | |
| r = map_get(&m, (T)(v1)); assert(r && *r == (T)(v2)); \ | |
| map_free(&m); \ | |
| } | |
| #define TEST_FOREACH_NUM(name, T) \ | |
| static void map_test_foreach_##name(void) { \ | |
| struct fe_##name map_of(T, T); \ | |
| struct fe_##name m = {}; \ | |
| bool ok = map_alloc(&m, 0); assert(ok); \ | |
| int count = 0; \ | |
| map_foreach(&m, k, v, { count++; (void)k; (void)v; }); \ | |
| assert(count == 0); \ | |
| for (int i = 1; i <= 5; i++) { \ | |
| ok = map_put(&m, (T)i, (T)(i*i)); assert(ok); \ | |
| } \ | |
| count = 0; \ | |
| map_foreach(&m, k, v, { count++; assert(v == k*k); }); \ | |
| assert(count == 5); \ | |
| ok = map_remove(&m, (T)3); assert(ok); \ | |
| count = 0; \ | |
| map_foreach(&m, k, v, { count++; (void)k; (void)v; }); \ | |
| assert(count == 4); \ | |
| map_free(&m); \ | |
| } | |
| #define TEST_CLEAR_NUM(name, T) \ | |
| static void map_test_clear_##name(void) { \ | |
| struct cl_##name map_of(T, T); \ | |
| struct cl_##name m = {}; \ | |
| bool ok = map_alloc(&m, 16); assert(ok); \ | |
| for (int i = 0; i < 5; i++) { \ | |
| ok = map_put(&m, (T)i, (T)(i*10)); assert(ok); \ | |
| } \ | |
| map_clear(&m); \ | |
| assert(m.count == 0); \ | |
| ok = map_put(&m, (T)99, (T)999); assert(ok); \ | |
| assert(!map_has(&m, (T)0)); \ | |
| assert(*map_get(&m, (T)99) == (T)999); \ | |
| map_free(&m); \ | |
| } | |
| #define TEST_GROW_SHRINK_NUM(name, T) \ | |
| static void map_test_grow_shrink_##name(void) { \ | |
| struct gs_##name map_of(T, T); \ | |
| struct gs_##name m = {}; \ | |
| bool ok = map_alloc(&m, 8); assert(ok); \ | |
| for (int i = 0; i < 5; i++) { \ | |
| ok = map_put(&m, (T)i, (T)(i*i)); assert(ok); \ | |
| } \ | |
| ok = map_grow(&m, 128); assert(ok); \ | |
| for (int i = 0; i < 5; i++) { \ | |
| assert(*map_get(&m, (T)i) == (T)(i*i)); \ | |
| } \ | |
| ok = map_shrink(&m, 16); assert(ok); \ | |
| for (int i = 0; i < 5; i++) { \ | |
| assert(*map_get(&m, (T)i) == (T)(i*i)); \ | |
| } \ | |
| map_free(&m); \ | |
| } | |
| TEST_INT_PAIR(i8, int8_t, -128, 127) | |
| TEST_INT_PAIR(u8, uint8_t, 0, 255) | |
| TEST_INT_PAIR(i16, int16_t, -32768, 32767) | |
| TEST_INT_PAIR(u16, uint16_t, 0, 65535) | |
| TEST_INT_PAIR(i32, int32_t, -2147483647-1, 2147483647) | |
| TEST_INT_PAIR(u32, uint32_t, 0, 0xFFFFFFFFu) | |
| TEST_INT_PAIR(i64, int64_t, -9223372036854775807LL-1, 9223372036854775807LL) | |
| TEST_INT_PAIR(u64, uint64_t, 0, 0xFFFFFFFFFFFFFFFFULL) | |
| TEST_INT_PAIR(sc, signed char, -128, 127) | |
| TEST_INT_PAIR(uc, unsigned char, 0, 255) | |
| TEST_INT_PAIR(sh, short, -32768, 32767) | |
| TEST_INT_PAIR(us, unsigned short, 0, 65535) | |
| TEST_INT_PAIR(lg, long, -1000000, 1000000) | |
| TEST_INT_PAIR(ul, unsigned long, 0, 999999999) | |
| TEST_INT_PAIR(ll, long long, -9000000000LL, 9000000000LL) | |
| TEST_INT_PAIR(ull, unsigned long long, 0, 0xFFFFFFFFFFFFFFFFULL) | |
| TEST_FOREACH_NUM(i32, int32_t) | |
| TEST_FOREACH_NUM(f32, float) | |
| TEST_FOREACH_NUM(f64, double) | |
| TEST_CLEAR_NUM(i32, int32_t) | |
| TEST_CLEAR_NUM(f32, float) | |
| TEST_CLEAR_NUM(f64, double) | |
| TEST_GROW_SHRINK_NUM(i32, int32_t) | |
| TEST_GROW_SHRINK_NUM(f64, double) | |
| static void map_test_s2s(void) { | |
| struct s2s map_of(const char*, const char*); | |
| struct s2s m = {}; | |
| bool ok = map_alloc(&m, 1); assert(ok); | |
| ok = map_put(&m, "hello", "world"); assert(ok); | |
| ok = map_put(&m, "foo", "bar"); assert(ok); | |
| assert(strcmp(*map_get(&m, "hello"), "world") == 0); | |
| ok = map_put(&m, "hello", "WORLD"); assert(ok); | |
| assert(strcmp(*map_get(&m, "hello"), "WORLD") == 0); | |
| ok = map_remove(&m, "foo"); assert(ok); | |
| assert(!map_has(&m, "foo")); | |
| ok = map_put(&m, "foo", "baz"); assert(ok); | |
| for (int i = 0; i < 50; i++) { | |
| char key[32], val[32]; | |
| snprintf(key, sizeof(key), "k%d", i); | |
| snprintf(val, sizeof(val), "v%d", i); | |
| ok = map_put(&m, key, val); assert(ok); | |
| } | |
| map_free(&m); | |
| } | |
| static void map_test_foreach_s2s(void) { | |
| struct fes2s map_of(const char*, const char*); | |
| struct fes2s m = {}; | |
| bool ok = map_alloc(&m, 0); assert(ok); | |
| ok = map_put(&m, "a", "A"); assert(ok); | |
| ok = map_put(&m, "b", "B"); assert(ok); | |
| int count = 0; | |
| map_foreach(&m, k, v, { count++; assert(k && v); }); | |
| assert(count == 2); | |
| map_free(&m); | |
| } | |
| static void map_test_clear_s2s(void) { | |
| struct cls2s map_of(const char*, const char*); | |
| struct cls2s m = {}; | |
| bool ok = map_alloc(&m, 0); assert(ok); | |
| ok = map_put(&m, "x", "y"); assert(ok); | |
| map_clear(&m); | |
| assert(m.count == 0); | |
| ok = map_put(&m, "a", "b"); assert(ok); | |
| assert(!map_has(&m, "x")); | |
| map_free(&m); | |
| } | |
| static void map_test_grow_s2s(void) { | |
| struct grs2s map_of(const char*, const char*); | |
| struct grs2s m = {}; | |
| bool ok = map_alloc(&m, 8); assert(ok); | |
| ok = map_put(&m, "one", "1"); assert(ok); | |
| ok = map_put(&m, "two", "2"); assert(ok); | |
| ok = map_grow(&m, 64); assert(ok); | |
| assert(strcmp(*map_get(&m, "one"), "1") == 0); | |
| assert(strcmp(*map_get(&m, "two"), "2") == 0); | |
| ok = map_shrink(&m, 16); assert(ok); | |
| assert(strcmp(*map_get(&m, "one"), "1") == 0); | |
| map_free(&m); | |
| } | |
| static void map_test_s2i(void) { | |
| struct s2i map_of(const char*, int32_t); | |
| struct s2i m = {}; | |
| bool ok = map_alloc(&m, 0); assert(ok); | |
| ok = map_put(&m, "one", 1); assert(ok); | |
| ok = map_put(&m, "neg", -999); assert(ok); | |
| assert(*map_get(&m, "one") == 1); | |
| ok = map_put(&m, "one", 111); assert(ok); | |
| assert(*map_get(&m, "one") == 111); | |
| ok = map_remove(&m, "neg"); assert(ok); | |
| map_free(&m); | |
| } | |
| static void map_test_i2s(void) { | |
| struct i2s map_of(int32_t, const char*); | |
| struct i2s m = {}; | |
| bool ok = map_alloc(&m, 0); assert(ok); | |
| ok = map_put(&m, 1, "one"); assert(ok); | |
| ok = map_put(&m, -1, "neg"); assert(ok); | |
| assert(strcmp(*map_get(&m, 1), "one") == 0); | |
| ok = map_put(&m, 1, "ONE"); assert(ok); | |
| assert(strcmp(*map_get(&m, 1), "ONE") == 0); | |
| ok = map_remove(&m, -1); assert(ok); | |
| map_free(&m); | |
| } | |
| static void map_test_d2s(void) { | |
| struct d2s map_of(double, const char*); | |
| struct d2s m = {}; | |
| bool ok = map_alloc(&m, 0); assert(ok); | |
| ok = map_put(&m, 3.14, "pi"); assert(ok); | |
| assert(strcmp(*map_get(&m, 3.14), "pi") == 0); | |
| ok = map_put(&m, 3.14, "PI"); assert(ok); | |
| assert(strcmp(*map_get(&m, 3.14), "PI") == 0); | |
| ok = map_remove(&m, 3.14); assert(ok); | |
| ok = map_put(&m, 3.14, "pi2"); assert(ok); | |
| map_free(&m); | |
| } | |
| static void map_test_f2s(void) { | |
| struct f2s map_of(float, const char*); | |
| struct f2s m = {}; | |
| bool ok = map_alloc(&m, 0); assert(ok); | |
| ok = map_put(&m, 2.71f, "e"); assert(ok); | |
| assert(strcmp(*map_get(&m, 2.71f), "e") == 0); | |
| ok = map_remove(&m, 2.71f); assert(ok); | |
| ok = map_put(&m, 2.71f, "E"); assert(ok); | |
| map_free(&m); | |
| } | |
| static void map_test_zero_normalization(void) { | |
| struct zf map_of(float, int); | |
| struct zf mf = {}; | |
| bool ok = map_alloc(&mf, 0); assert(ok); | |
| ok = map_put(&mf, -0.0f, 42); assert(ok); | |
| assert(map_has(&mf, 0.0f) && map_has(&mf, -0.0f)); | |
| assert(*map_get(&mf, 0.0f) == 42); | |
| ok = map_put(&mf, 0.0f, 99); assert(ok); | |
| assert(*map_get(&mf, -0.0f) == 99 && mf.count == 1); | |
| map_free(&mf); | |
| struct zd map_of(double, int); | |
| struct zd md = {}; | |
| ok = map_alloc(&md, 0); assert(ok); | |
| ok = map_put(&md, -0.0, 123); assert(ok); | |
| assert(map_has(&md, 0.0) && *map_get(&md, 0.0) == 123); | |
| ok = map_put(&md, 0.0, 456); assert(ok); | |
| assert(*map_get(&md, -0.0) == 456 && md.count == 1); | |
| map_free(&md); | |
| } | |
| static void map_test_empty_ops(void) { | |
| struct eo map_of(int, int); | |
| struct eo m = {}; | |
| bool ok = map_alloc(&m, 0); assert(ok); | |
| assert(!map_has(&m, 42)); | |
| assert(map_get(&m, 42) == NULL); | |
| assert(!map_remove(&m, 42)); | |
| assert(m.count == 0 && m.capacity == 0); | |
| map_clear(&m); | |
| map_free(&m); | |
| } | |
| static void map_test_alloc_default(void) { | |
| struct ad map_of(int, int); | |
| struct ad m = {}; | |
| bool ok = map_alloc(&m); assert(ok); | |
| assert(m.capacity == 16); | |
| ok = map_put(&m, 1, 10); assert(ok); | |
| assert(*map_get(&m, 1) == 10); | |
| map_free(&m); | |
| } | |
| static void map_test_tombstone_chain(void) { | |
| struct tc map_of(int, int); | |
| struct tc m = {}; | |
| bool ok = map_alloc(&m, 8); assert(ok); | |
| for (int i = 0; i < 6; i++) { | |
| ok = map_put(&m, i, i * 10); assert(ok); | |
| } | |
| ok = map_remove(&m, 1); assert(ok); | |
| ok = map_remove(&m, 3); assert(ok); | |
| assert(map_has(&m, 0) && !map_has(&m, 1) && map_has(&m, 2)); | |
| ok = map_put(&m, 100, 1000); assert(ok); | |
| assert(*map_get(&m, 100) == 1000); | |
| map_free(&m); | |
| } | |
| static void map_test_shrink_auto(void) { | |
| struct sa map_of(int, int); | |
| struct sa m = {}; | |
| bool ok = map_alloc(&m, 128); assert(ok); | |
| int32_t initial_cap = m.capacity; | |
| for (int i = 0; i < 20; i++) { | |
| ok = map_put(&m, i, i); assert(ok); | |
| } | |
| assert(m.capacity == initial_cap); | |
| for (int i = 0; i < 18; i++) { | |
| ok = map_remove(&m, i); assert(ok); | |
| } | |
| assert(m.count == 2); | |
| assert(m.capacity < initial_cap); | |
| assert(*map_get(&m, 18) == 18); | |
| assert(*map_get(&m, 19) == 19); | |
| map_free(&m); | |
| } | |
| static void map_test_heavy_collision(void) { | |
| struct hc map_of(int, int); | |
| struct hc m = {}; | |
| bool ok = map_alloc(&m, 8); assert(ok); | |
| for (int i = 0; i < 100; i++) { | |
| ok = map_put(&m, i, i * i); assert(ok); | |
| } | |
| for (int i = 0; i < 100; i++) { | |
| int* r = map_get(&m, i); | |
| assert(r && *r == i * i); | |
| } | |
| for (int i = 0; i < 100; i += 2) { | |
| ok = map_remove(&m, i); assert(ok); | |
| } | |
| for (int i = 1; i < 100; i += 2) { | |
| int* r = map_get(&m, i); | |
| assert(r && *r == i * i); | |
| } | |
| for (int i = 0; i < 100; i += 2) { | |
| ok = map_put(&m, i, i + 1000); assert(ok); | |
| } | |
| for (int i = 0; i < 100; i += 2) { | |
| int* r = map_get(&m, i); | |
| assert(r && *r == i + 1000); | |
| } | |
| map_free(&m); | |
| } | |
| static void map_test_string_variations(void) { | |
| struct sv map_of(const char*, int); | |
| struct sv m = {}; | |
| bool ok = map_alloc(&m, 0); assert(ok); | |
| ok = map_put(&m, "", 0); assert(ok); | |
| assert(map_has(&m, "") && *map_get(&m, "") == 0); | |
| const char* lng = "this is a very long string key for testing"; | |
| ok = map_put(&m, lng, 999); assert(ok); | |
| assert(*map_get(&m, lng) == 999); | |
| ok = map_put(&m, "a\nb", 1); assert(ok); | |
| assert(map_has(&m, "a\nb")); | |
| map_free(&m); | |
| } | |
| static void map_test_repeated_ops(void) { | |
| struct rp map_of(int, int); | |
| struct rp m = {}; | |
| bool ok = map_alloc(&m, 0); assert(ok); | |
| for (int r = 0; r < 10; r++) { | |
| ok = map_put(&m, 42, r); assert(ok); | |
| assert(*map_get(&m, 42) == r); | |
| ok = map_remove(&m, 42); assert(ok); | |
| } | |
| assert(m.count == 0); | |
| map_free(&m); | |
| } | |
| void map_test(void) { | |
| map_test_i8(); map_test_u8(); | |
| map_test_i16(); map_test_u16(); | |
| map_test_i32(); map_test_u32(); | |
| map_test_i64(); map_test_u64(); | |
| map_test_sc(); map_test_uc(); | |
| map_test_sh(); map_test_us(); | |
| map_test_lg(); map_test_ul(); | |
| map_test_ll(); map_test_ull(); | |
| map_test_foreach_i32(); | |
| map_test_foreach_f32(); | |
| map_test_foreach_f64(); | |
| map_test_foreach_s2s(); | |
| map_test_clear_i32(); | |
| map_test_clear_f32(); | |
| map_test_clear_f64(); | |
| map_test_clear_s2s(); | |
| map_test_grow_shrink_i32(); | |
| map_test_grow_shrink_f64(); | |
| map_test_grow_s2s(); | |
| map_test_s2s(); | |
| map_test_s2i(); | |
| map_test_i2s(); | |
| map_test_d2s(); | |
| map_test_f2s(); | |
| map_test_zero_normalization(); | |
| map_test_empty_ops(); | |
| map_test_alloc_default(); | |
| map_test_tombstone_chain(); | |
| map_test_shrink_auto(); | |
| map_test_heavy_collision(); | |
| map_test_string_variations(); | |
| map_test_repeated_ops(); | |
| } | |
| void map_test_memory_pressure(void) { | |
| const int N = 1000 * 1000; | |
| for (int i = 0; i < N; i++) { | |
| map_test(); | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
map.h
map.c
is here:
https://gist.github.com/leok7v/a8fd17d649a4de6673c40c0fefda327f