some updates and tests for the equals function

This commit is contained in:
2026-05-25 20:42:53 +02:00
parent 5ea8d2ea32
commit e1bd55e470
5 changed files with 107 additions and 26 deletions
+13 -8
View File
@@ -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 bool (*key_equals_func_t)(const void *key1, const void *key2);
typedef struct map_header { typedef struct map_header {
unsigned int capacity; uint32_t capacity;
unsigned int item_size; uint32_t item_size;
unsigned int key_size; uint32_t key_size;
unsigned int mapping_capacity; uint32_t mapping_capacity;
unsigned int n_items; uint32_t n_items;
unsigned int key_offset; uint32_t key_offset;
allocator_t allocator; allocator_t allocator;
key_hash_func_t hash; key_hash_func_t hash;
key_equals_func_t equals; key_equals_func_t equals;
int *mapping_arr; int32_t *mapping_arr;
union { union {
uint8_t bytes[1]; uint8_t bytes[1];
any_align_t _[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 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); 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); 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 // TODO: NOT DONE!!! FIRST try to get the existing in
#define set_add(THIS, VALUE) do { \ #define set_add(THIS, VALUE) do { \
map_assure_growable_by_1((void**)THIS, __FILE__, __LINE__); \ map_assure_growable_by_1((void**)THIS, __FILE__, __LINE__); \
unsigned int len = map_len(*(THIS)); \ unsigned int len = map_len(*(THIS)); \
(*(THIS))[len] = VALUE; \ (*(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; \ (*(THIS))[map_place((*(THIS)), idx_pair)] = VALUE; \
} while (0) } while (0)
+6 -2
View File
@@ -1,5 +1,5 @@
CC := "zig cc" 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" { LDFLAGS := if os() == "macos" {
"$(pkg-config --libs --cflags criterion)" "$(pkg-config --libs --cflags criterion)"
} else { } else {
@@ -12,9 +12,11 @@ TESTBIN := TMP/"all_tests"
set shell := ["bash", "-cu"] set shell := ["bash", "-cu"]
RUNNER := if os() == "linux" { "valgrind" } else { "" }
[default] [default]
test: build test: build
{{TESTBIN}} {{RUNNER}} {{TESTBIN}}
test_memcheck: build test_memcheck: build
valgrind --leak-check=full \ valgrind --leak-check=full \
@@ -28,6 +30,8 @@ build:
DEPENDENCY_HEADERS := if os() == "macos" { DEPENDENCY_HEADERS := if os() == "macos" {
"$(pkg-config --cflags-only-I criterion | sed 's/-I//g')" "$(pkg-config --cflags-only-I criterion | sed 's/-I//g')"
} else if os() == "linux" {
"/usr/include/"
} else { } else {
"TODO" "TODO"
} }
+8 -16
View File
@@ -17,12 +17,9 @@
#define DEFAULT ESC "0m" #define DEFAULT ESC "0m"
#define COLORED(COLOR, TEXT) COLOR TEXT DEFAULT #define COLORED(COLOR, TEXT) COLOR TEXT DEFAULT
static int __map_mod(int a, int b) { uint32_t map_mod_index(const map_header_t *header, uint32_t i) {
int r = a % b; return i % header->mapping_capacity;
if (r < 0) r += (b > 0 ? b : -b);
return r;
} }
#define mod(a, b) __map_mod(a, b)
void map_print_mapping_state(void *this, FILE *file) { void map_print_mapping_state(void *this, FILE *file) {
map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this); 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]); return (const uint8_t *) (&pair[this->key_offset]);
} }
// TODO: just make these internal probably bool map_key_equals(map_header_t *header, const uint8_t *key1_bytes, const uint8_t *key2_bytes) {
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);
if (header->equals != NULL) { 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++ ) { for ( unsigned int i = 0; i < header->key_size; i++ ) {
if (key1_bytes[i] != key2_bytes[i]) { if (key1_bytes[i] != key2_bytes[i]) {
return false; 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) { unsigned int map_place(void *this, index_pair_t idx) {
map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this); map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this);
if (idx.has_old) { if (idx.has_old) {
header->mapping_arr[idx.new_i_into_mapping] = header->mapping_arr[idx.old_index]; header->mapping_arr[idx.new_i_into_mapping] = header->mapping_arr[idx.old_i_into_mapping];
header->mapping_arr[idx.old_index] = FLAG_TOMBSTONE; header->mapping_arr[idx.old_i_into_mapping] = FLAG_TOMBSTONE;
for ( long i = idx.old_index; i != idx.new_i_into_mapping; mod(i-1, header->mapping_capacity) ) { 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) { if (header->mapping_arr[i] == FLAG_TOMBSTONE) {
header->mapping_arr[i] = FLAG_FREE; header->mapping_arr[i] = FLAG_FREE;
} else { } else {
@@ -182,8 +175,7 @@ index_pair_t map_pair_hash(void *this, const uint8_t *pair) {
.new_i_into_mapping=i_into_mapping, .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 // TODO: search all occurances of **this. The whole point is to reassign to the
View File
+80
View File
@@ -0,0 +1,80 @@
#include <criterion/criterion.h>
#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
);
}
}