From e1bd55e47050756b99a10a60153587f5ac6ccc60 Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Mon, 25 May 2026 20:42:53 +0200 Subject: [PATCH] some updates and tests for the equals function --- cig.h | 21 +++++++----- justfile | 8 +++-- map.c | 24 +++++-------- map_key_equals.c | 0 test_map_key_equals.c | 80 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 26 deletions(-) create mode 100644 map_key_equals.c create mode 100644 test_map_key_equals.c diff --git a/cig.h b/cig.h index 1ff4d29..b178392 100644 --- a/cig.h +++ b/cig.h @@ -239,16 +239,16 @@ typedef unsigned int (*key_hash_func_t)(const void *key); typedef bool (*key_equals_func_t)(const void *key1, const void *key2); typedef struct map_header { - unsigned int capacity; - unsigned int item_size; - unsigned int key_size; - unsigned int mapping_capacity; - unsigned int n_items; - unsigned int key_offset; + uint32_t capacity; + uint32_t item_size; + uint32_t key_size; + uint32_t mapping_capacity; + uint32_t n_items; + uint32_t key_offset; allocator_t allocator; key_hash_func_t hash; key_equals_func_t equals; - int *mapping_arr; + int32_t *mapping_arr; union { uint8_t bytes[1]; any_align_t _[1]; @@ -317,14 +317,19 @@ typedef struct index_pair { * index with a tombstone if they are going to write a new value for that key. */ index_pair_t map_pair_hash(void *this, const uint8_t *pair); +bool map_key_equals(map_header_t *header, const uint8_t *key1_bytes, const uint8_t *key2_bytes); unsigned int map_place(void *this, index_pair_t idx_pair); +// Exists to take a hash of a key and modulo it so it fits within the maps +// capacity. +uint32_t map_mod_index(const map_header_t *header, uint32_t i); + // TODO: NOT DONE!!! FIRST try to get the existing in #define set_add(THIS, VALUE) do { \ map_assure_growable_by_1((void**)THIS, __FILE__, __LINE__); \ unsigned int len = map_len(*(THIS)); \ (*(THIS))[len] = VALUE; \ - index_pair_t idx_pair = map_pair_hash((*(THIS)), &(*(THIS))[len]); \ + index_pair_t idx_pair = map_pair_hash((*(THIS)), (const uint8_t*) (&(*(THIS))[len])); \ (*(THIS))[map_place((*(THIS)), idx_pair)] = VALUE; \ } while (0) diff --git a/justfile b/justfile index d217a69..88b9841 100644 --- a/justfile +++ b/justfile @@ -1,5 +1,5 @@ CC := "zig cc" -CFLAGS := "-pedantic -Wall -Wextra -Wno-override-init -O0 -g -fno-omit-frame-pointer -fno-inline" +CFLAGS := "-pedantic -Wall -Wextra -Wno-override-init -O0 -g3 -fno-omit-frame-pointer -fno-inline -fsanitize=address,undefined -fno-sanitize-recover=all" LDFLAGS := if os() == "macos" { "$(pkg-config --libs --cflags criterion)" } else { @@ -12,9 +12,11 @@ TESTBIN := TMP/"all_tests" set shell := ["bash", "-cu"] +RUNNER := if os() == "linux" { "valgrind" } else { "" } + [default] test: build - {{TESTBIN}} + {{RUNNER}} {{TESTBIN}} test_memcheck: build valgrind --leak-check=full \ @@ -28,6 +30,8 @@ build: DEPENDENCY_HEADERS := if os() == "macos" { "$(pkg-config --cflags-only-I criterion | sed 's/-I//g')" +} else if os() == "linux" { + "/usr/include/" } else { "TODO" } diff --git a/map.c b/map.c index 6eef28a..f1b69dd 100644 --- a/map.c +++ b/map.c @@ -17,12 +17,9 @@ #define DEFAULT ESC "0m" #define COLORED(COLOR, TEXT) COLOR TEXT DEFAULT -static int __map_mod(int a, int b) { - int r = a % b; - if (r < 0) r += (b > 0 ? b : -b); - return r; +uint32_t map_mod_index(const map_header_t *header, uint32_t i) { + return i % header->mapping_capacity; } -#define mod(a, b) __map_mod(a, b) void map_print_mapping_state(void *this, FILE *file) { map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this); @@ -104,14 +101,10 @@ static const uint8_t *__cig_key_ptr_from_pair_ptr(const map_header_t *this, cons return (const uint8_t *) (&pair[this->key_offset]); } -// TODO: just make these internal probably -bool map_key_equals(void *this, const void *key1, const void *key2) { - map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this); +bool map_key_equals(map_header_t *header, const uint8_t *key1_bytes, const uint8_t *key2_bytes) { if (header->equals != NULL) { - return header->equals(key1, key2); + return header->equals(key1_bytes, key2_bytes); } - const char *key1_bytes = key1; - const char *key2_bytes = key2; for ( unsigned int i = 0; i < header->key_size; i++ ) { if (key1_bytes[i] != key2_bytes[i]) { return false; @@ -123,9 +116,9 @@ bool map_key_equals(void *this, const void *key1, const void *key2) { unsigned int map_place(void *this, index_pair_t idx) { map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this); if (idx.has_old) { - header->mapping_arr[idx.new_i_into_mapping] = header->mapping_arr[idx.old_index]; - header->mapping_arr[idx.old_index] = FLAG_TOMBSTONE; - for ( long i = idx.old_index; i != idx.new_i_into_mapping; mod(i-1, header->mapping_capacity) ) { + header->mapping_arr[idx.new_i_into_mapping] = header->mapping_arr[idx.old_i_into_mapping]; + header->mapping_arr[idx.old_i_into_mapping] = FLAG_TOMBSTONE; + for ( long i = idx.old_i_into_mapping; i != idx.new_i_into_mapping; map_mod_index(header, i-1) ) { if (header->mapping_arr[i] == FLAG_TOMBSTONE) { header->mapping_arr[i] = FLAG_FREE; } else { @@ -182,8 +175,7 @@ index_pair_t map_pair_hash(void *this, const uint8_t *pair) { .new_i_into_mapping=i_into_mapping, }; } - map_key_equals(this, const void *key1, const void *key2); - TODO this + // TODO THIS!! } // TODO: search all occurances of **this. The whole point is to reassign to the diff --git a/map_key_equals.c b/map_key_equals.c new file mode 100644 index 0000000..e69de29 diff --git a/test_map_key_equals.c b/test_map_key_equals.c new file mode 100644 index 0000000..7e2d1e1 --- /dev/null +++ b/test_map_key_equals.c @@ -0,0 +1,80 @@ +#include +#include "cig.h" + +Test(map_key_equals, ints) { + { // should be equal + int key1 = 20; + int key2 = 20; + map_header_t header = (map_header_t) { 0 }; + header.key_size = sizeof(key1); + cr_assert( + map_key_equals( + &header, + (const uint8_t*)&key1, + (const uint8_t*)&key2 + ), + "key %d is not equal to key %d", + key1, + key2 + ); + } + { // should not be equal + int key1 = 20; + int key2 = 21; + map_header_t header = (map_header_t) { 0 }; + header.key_size = sizeof(key1); + cr_assert( + !map_key_equals( + &header, + (const uint8_t*)&key1, + (const uint8_t*)&key2 + ), + "key %d is equal to key %d", + key1, + key2 + ); + } +} + +static bool inverse_int_equals(const void *key1, const void *key2) { + int key1_i = *((int*)key1); + int key2_i = *((int*)key2); + return key1_i != key2_i; +} + +Test(map_key_equals, custom) { + { // should be equal + int key1 = 20; + int key2 = 21; + map_header_t header = (map_header_t) { 0 }; + header.key_size = sizeof(key1); + header.equals = inverse_int_equals; + cr_assert( + map_key_equals( + &header, + (const uint8_t*)&key1, + (const uint8_t*)&key2 + ), + "key %d is equal to key %d", + key1, + key2 + ); + } + { // should not be equal + int key1 = 20; + int key2 = 20; + map_header_t header = (map_header_t) { 0 }; + header.key_size = sizeof(key1); + header.equals = inverse_int_equals; + cr_assert( + !map_key_equals( + &header, + (const uint8_t*)&key1, + (const uint8_t*)&key2 + ), + "key %d is not equal to key %d", + key1, + key2 + ); + } +}