This commit is contained in:
Gvidas Juknevičius 2025-02-04 15:03:27 +02:00
parent 69811ba0f2
commit 049b901278
Signed by: MCorange
GPG Key ID: 12B1346D720B7FBB
10 changed files with 312 additions and 70 deletions

21
BUILDING.md Normal file
View File

@ -0,0 +1,21 @@
# Building
You can build this in several different ways:
You can run the make file and have a static library of this lib.
You can compile the library directly into your program:
```c
// Run this to comile:
// $ gcc -o main main.c -I$MCUTIL_PATH/include
// Only do this ***once***
#define MCUTIL_IMPLEMENTATION
#include <mcutil/mcutil.h>
int main(int argc, char** argv) {
mcu_hash_map_t hm = {0};
return 0;
}

View File

@ -2,14 +2,12 @@
OUTD ?= ./build
CC = gcc
LD = gcc
CC = clang
LD = clang
AR = ar
# -fblocks
CCARGS = -fpic -Wall -O3 -Wall -I include
LDARGS =
# -lBlocksRuntime
CCARGS = -fpic -Wall -O3 -Wall -I include -fblocks
LDARGS = -lBlocksRuntime
srcs = $(wildcard src/**/*.c) $(wildcard src/*.c)
objs = $(patsubst src/%.c,$(OUTD)/obj/%.o,$(srcs))

View File

@ -6,28 +6,28 @@
#include <stdlib.h>
#include "mcutil/mcutil.h"
typedef struct mcu_hash_map_node_s {
typedef struct mcu_gen_hm_node_s {
uint8_t key[16];
void* value;
struct mcu_hash_map_node_s* next;
} mcu_hash_map_node_t;
struct mcu_gen_hm_node_s* next;
} mcu_gen_hm_node_t;
typedef struct mcu_hash_map_s {
mcu_hash_map_node_t* nodes;
} mcu_hash_map_t;
typedef struct mcu_gen_hm_s {
mcu_gen_hm_node_t* nodes;
} mcu_gen_hm_t;
#define mcu_hm_insert(hm, key, value) _mcu_hm_insert((hm), (key), (const size_t)sizeof(key), (value));
#define mcu_hm_get(hm, key) _mcu_hm_insert((hm), (key), (const size_t)sizeof(key));
#define mcu_hm_remove(hm, key) _mcu_hm_insert((hm), (key), (const size_t)sizeof(key));
MCU_API mcu_hash_map_t mcu_hm_new();
MCU_API void _mcu_hm_insert(mcu_hash_map_t* hm, const void* key, const size_t key_len, const void* value);
MCU_API void* _mcu_hm_get (mcu_hash_map_t* hm, const void* key, const size_t key_len);
MCU_API void* _mcu_hm_remove(mcu_hash_map_t* hm, const void* key, const size_t key_len);
MCU_API mcu_gen_hm_t mcu_hm_new();
MCU_API void _mcu_hm_insert(mcu_gen_hm_t* hm, const void* key, const size_t key_len, const void* value);
MCU_API void* _mcu_hm_get (mcu_gen_hm_t* hm, const void* key, const size_t key_len);
MCU_API void* _mcu_hm_remove(mcu_gen_hm_t* hm, const void* key, const size_t key_len);
/// Frees the hashmap but not the pointers inside the values
MCU_API void mcu_free(mcu_hash_map_t* hm);
MCU_API void mcu_free(mcu_gen_hm_t* hm);
/// Frees the hashmap and the pointers inside the values
MCU_API void mcu_free_all(mcu_hash_map_t* hm);
MCU_API void mcu_free_all(mcu_gen_hm_t* hm);
#endif // _H_MCU_COLLECT_HASH_MAP

View File

@ -5,17 +5,18 @@
#include "mcutil/mcutil.h"
#include <stddef.h>
#define MCU_GEN_VEC_INITIAL_SIZE 32
typedef struct gen_vec_s {
typedef struct mcu_gen_vec_s {
void** inner;
size_t count;
size_t capacity;
} gen_vec_t;
} mcu_gen_vec_t;
MCU_API void mcu_gen_vec_insert_front(gen_vec_t* gv, void* data);
MCU_API void mcu_gen_vec_insert_back(gen_vec_t* gv, void* data);
MCU_API void* mcu_gen_vec_remove_back(gen_vec_t *gv);
MCU_API void* mcu_gen_vec_remove_front(gen_vec_t *gv);
MCU_API void mcu_gen_vec_init(mcu_gen_vec_t* gv);
MCU_API void mcu_gen_vec_insert_front(mcu_gen_vec_t* gv, void* data);
MCU_API void mcu_gen_vec_insert_back(mcu_gen_vec_t* gv, void* data);
MCU_API void* mcu_gen_vec_remove_back(mcu_gen_vec_t *gv);
MCU_API void* mcu_gen_vec_remove_front(mcu_gen_vec_t *gv);
#endif

View File

@ -0,0 +1,136 @@
#ifndef _H_MCU_COLLECT_TYPED_HASH_MAP
#define _H_MCU_COLLECT_TYPED_HASH_MAP
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "mcutil/mcutil.h"
#define MCU_TYPED_HM_DEFINE(name_prefix, key_t, value_t) \
typedef struct name_prefix##_hm_node_s { \
uint8_t key_hash[16]; \
key_t key; \
value_t value; \
struct mcu_hash_map_node_s* next; \
} name_prefix##_hm_node_t; \
\
typedef struct name_prefix##_hm_s { \
name_prefix##_hm_node_t* nodes; \
} name_prefix##_hm_t;
#define MCU_TYPED_HM_IMPL(pfx, key_t, value_t) \
MCU_API pfx##_hm_t mcu_hm_new() { \
return (pfx##_hm_t){ \
.nodes = MCU_ALLOC(sizeof(pfx##_hm_t)), \
}; \
} \
\
MCU_API void pfx##_hm_insert( \
pfx##_hm_t* hm, \
const key_t* key, \
const value_t* value) { \
assert(hm && "HashMap ptr is null"); \
mcu_md5_context ctx = {0}; \
mcu_md5_init(&ctx); \
mcu_md5_digest(&ctx, (void*)key, sizeof(key_t)); \
uint8_t key_res[16]; \
mcu_md5_output(&ctx, key_res); \
\
if (!(hm)->nodes) \
(hm)->nodes = MCU_ALLOC(sizeof(pfx##_hm_node_t)); \
\
pfx##_hm_node_t* node = hm->nodes; \
while (true) { \
if (!node->next) { \
node->next = MCU_ALLOC(sizeof(pfx##_hm_node_t));\
node->next->next = NULL; \
node->next->key = key; \
memcpy(node->next->key_hash, key_res, 16); \
node->next->value = (void*)value; \
return; \
} \
node = node->next; \
} \
} \
\
MCU_API void* pfx##_hm_get( \
pfx##_hm_t* hm, \
const key_t key, \
) { \
assert(hm && "HashMap ptr is null"); \
mcu_md5_context ctx = {0}; \
mcu_md5_init(&ctx); \
mcu_md5_digest(&ctx, (void*)key, sizeof(key_t)); \
uint8_t key_res[16]; \
mcu_md5_output(&ctx, key_res); \
\
if (!(hm)->nodes) \
(hm)->nodes = MCU_ALLOC(sizeof(pfx##_hm_node_t)); \
pfx##_hm_node_t* node = hm->nodes; \
while (true) { \
if (memcmp(node->key, key_res, 16) == 0) { \
return node->value; \
} else { \
if (!node->next) return NULL; \
node = node->next; \
} \
} \
} \
\
MCU_API void* pfx##_hm_remove( \
pfx##_hm_t* hm, \
const key_t key, \
const size_t key_len \
) { \
assert(hm && "HashMap ptr is null"); \
mcu_md5_context ctx = {0}; \
mcu_md5_init(&ctx); \
mcu_md5_digest(&ctx, (void*)key, sizeof(key_t)); \
uint8_t key_res[16]; \
mcu_md5_output(&ctx, key_res); \
\
if (!(hm)->nodes) \
(hm)->nodes = MCU_ALLOC(sizeof(pfx##_hm_node_t)); \
\
pfx##_hm_node_t* node = hm->nodes; \
pfx##_hm_node_t* prev = hm->nodes; \
while (true) { \
if (memcmp(node->key, key_res, 16) == 0) { \
void* val = node->value; \
prev->next = node->next; \
return val; \
} else { \
if (!node->next) return NULL; \
prev = node; \
node = node->next; \
} \
} \
} \
\
MCU_API void pfx##_hm_free(pfx##_hm_t* hm) { \
assert(hm && "HashMap ptr is null"); \
pfx##_hm_node_t* node = hm->nodes; \
if (!node) return; \
\
while (true) { \
if (node->next) return; \
MCU_FREE(node); \
node = node->next; \
} \
} \
\
MCU_API void pfx##_hm_free_all(pfx##_hm_t* hm) { \
assert(hm && "HashMap ptr is null"); \
pfx##_hm_node_t* node = hm->nodes; \
if (!node) return; \
while (true) { \
if (node->next) return; \
MCU_FREE(node); \
MCU_FREE(node->value); \
MCU_FREE(node->key); \
node = node->next; \
} \
}
#endif // _H_MCU_COLLECT_TYPED_HASH_MAP

View File

View File

@ -7,22 +7,21 @@ typedef struct mcu_test_case_s {
int (*test_fn)(void);
// If `test_fn` returns non zero, it will get the (ret_val - 1) value of this array,
// if this is null it will show up as `(none)`, so return 1 for the first error type.
const char* error_types[];
char** error_types;
} mcu_test_case_t;
#define RUN_TEST_CASES(cases) \
for (size_t i = 0; i < sizeof(cases)/sizeof(mcu_test_case_t); i++) { \
mcu_test_case_t* test_case = &(cases)[i]; \
printf("(%s): ", test_case->short_name); \
int ret = (test_case->test_fn)(); \
if (!ret) { \
printf("(%s): FAIL - Returned non zero (%d)\n", \
test_case->short_name, ret); \
printf("(%s): REASON: %s\n", \
test_case->short_name, test_case->error_types[ret-1]); \
if (ret) { \
printf("FAIL - Returned non zero (%d)\n", ret); \
printf("REASON: %s\n", test_case->error_types[ret]); \
exit(1); \
} else { \
printf("(%s): FAIL\n", test_case->short_name); \
printf("PASS\n"); \
} \
}

View File

@ -1,4 +1,5 @@
#include "mcutil/collect/hash_map.h"
#include "mcutil/collect/gen_hash_map.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
@ -7,23 +8,28 @@
#include "mcutil/mcutil.h"
#include "mcutil/hash/md5.h"
MCU_API mcu_hash_map_t mcu_hm_new() {
return (mcu_hash_map_t){
.nodes = MCU_ALLOC(sizeof(mcu_hash_map_node_t)),
#define CREATE_HM_NODES_IF_NULL(hm) { if (!(hm)->nodes) (hm)->nodes = MCU_ALLOC(sizeof(mcu_gen_hm_node_t)); }
MCU_API mcu_gen_hm_t mcu_hm_new() {
return (mcu_gen_hm_t){
.nodes = MCU_ALLOC(sizeof(mcu_gen_hm_node_t)),
};
}
MCU_API void _mcu_hm_insert(mcu_hash_map_t* hm, const void* key, const size_t key_len, const void* value) {
MCU_API void _mcu_hm_insert(mcu_gen_hm_t* hm, const void* key, const size_t key_len, const void* value) {
assert(hm && "HashMap ptr is null");
mcu_md5_context ctx = {0};
mcu_md5_init(&ctx);
mcu_md5_digest(&ctx, (void*)key, key_len);
uint8_t key_res[16];
mcu_md5_output(&ctx, key_res);
mcu_hash_map_node_t* node = hm->nodes;
CREATE_HM_NODES_IF_NULL(hm);
mcu_gen_hm_node_t* node = hm->nodes;
while (true) {
if (!node->next) {
node->next = MCU_ALLOC(sizeof(mcu_hash_map_node_t));
node->next = MCU_ALLOC(sizeof(mcu_gen_hm_node_t));
node->next->next = NULL;
memcpy(node->next->key, key_res, 16);
node->next->value = (void*)value;
@ -33,14 +39,16 @@ MCU_API void _mcu_hm_insert(mcu_hash_map_t* hm, const void* key, const size_t ke
}
}
MCU_API void* _mcu_hm_get(mcu_hash_map_t* hm, const void* key, const size_t key_len) {
MCU_API void* _mcu_hm_get(mcu_gen_hm_t* hm, const void* key, const size_t key_len) {
assert(hm && "HashMap ptr is null");
mcu_md5_context ctx = {0};
mcu_md5_init(&ctx);
mcu_md5_digest(&ctx, (void*)key, key_len);
uint8_t key_res[16];
mcu_md5_output(&ctx, key_res);
mcu_hash_map_node_t* node = hm->nodes;
CREATE_HM_NODES_IF_NULL(hm);
mcu_gen_hm_node_t* node = hm->nodes;
while (true) {
if (memcmp(node->key, key_res, 16) == 0) {
return node->value;
@ -51,15 +59,18 @@ MCU_API void* _mcu_hm_get(mcu_hash_map_t* hm, const void* key, const size_t key_
}
}
MCU_API void* _mcu_hm_remove(mcu_hash_map_t* hm, const void* key, const size_t key_len) {
MCU_API void* _mcu_hm_remove(mcu_gen_hm_t* hm, const void* key, const size_t key_len) {
assert(hm && "HashMap ptr is null");
mcu_md5_context ctx = {0};
mcu_md5_init(&ctx);
mcu_md5_digest(&ctx, (void*)key, key_len);
uint8_t key_res[16];
mcu_md5_output(&ctx, key_res);
mcu_hash_map_node_t* node = hm->nodes;
mcu_hash_map_node_t* prev = hm->nodes;
CREATE_HM_NODES_IF_NULL(hm);
mcu_gen_hm_node_t* node = hm->nodes;
mcu_gen_hm_node_t* prev = hm->nodes;
while (true) {
if (memcmp(node->key, key_res, 16) == 0) {
void* val = node->value;
@ -73,8 +84,11 @@ MCU_API void* _mcu_hm_remove(mcu_hash_map_t* hm, const void* key, const size_t k
}
}
MCU_API void mcu_free(mcu_hash_map_t* hm) {
mcu_hash_map_node_t* node = hm->nodes;
MCU_API void mcu_free(mcu_gen_hm_t* hm) {
assert(hm && "HashMap ptr is null");
mcu_gen_hm_node_t* node = hm->nodes;
if (!node) return;
while (true) {
if (node->next) return;
MCU_FREE(node);
@ -82,8 +96,10 @@ MCU_API void mcu_free(mcu_hash_map_t* hm) {
}
}
MCU_API void mcu_free_all(mcu_hash_map_t* hm) {
mcu_hash_map_node_t* node = hm->nodes;
MCU_API void mcu_free_all(mcu_gen_hm_t* hm) {
assert(hm && "HashMap ptr is null");
mcu_gen_hm_node_t* node = hm->nodes;
if (!node) return;
while (true) {
if (node->next) return;
MCU_FREE(node);

View File

@ -1,17 +1,20 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "mcutil/mcutil.h"
#include "mcutil/collect/gen_vec.h"
MCU_API void mcu_gen_vec_init(gen_vec_t* gv) {
#define MCU_GEN_VEC_INITIAL_SIZE 32
MCU_API void mcu_gen_vec_init(mcu_gen_vec_t* gv) {
gv->inner = MCU_ALLOC(sizeof(void*)*MCU_GEN_VEC_INITIAL_SIZE);
gv->capacity = MCU_GEN_VEC_INITIAL_SIZE;
}
MCU_API void mcu_gen_vec_insert_front(gen_vec_t* gv, void* data) {
assert(gv && "Null ptr passed as gen_vec_t");
MCU_API void mcu_gen_vec_insert_front(mcu_gen_vec_t* gv, void* data) {
assert(gv && "Null ptr passed as mcu_gen_vec_t");
if (!gv->inner) mcu_gen_vec_init(gv);
if (gv->count == gv->capacity) {
gv->inner = MCU_REALLOC(gv->inner, (gv->capacity * sizeof(void*)) * 2);
@ -23,34 +26,33 @@ MCU_API void mcu_gen_vec_insert_front(gen_vec_t* gv, void* data) {
memcpy(tmp, gv->inner, count);
memcpy(gv->inner + sizeof(void*), tmp, count);
gv->inner[0] = data;
gv->count += 1;
MCU_FREE(tmp);
}
MCU_API void mcu_gen_vec_insert_back(gen_vec_t* gv, void* data) {
assert(gv && "Null ptr passed as gen_vec_t");
MCU_API void mcu_gen_vec_insert_back(mcu_gen_vec_t* gv, void* data) {
assert(gv && "Null ptr passed as mcu_gen_vec_t");
if (!gv->inner) mcu_gen_vec_init(gv);
if (gv->count == gv->capacity) {
gv->inner = MCU_REALLOC(gv->inner, (gv->capacity * sizeof(void*)) * 2);
gv->inner = MCU_REALLOC(gv->inner, (gv->capacity * 2) * sizeof(void*));
gv->capacity *= 2;
}
gv->inner[gv->count++] = data;
}
MCU_API void* mcu_gen_vec_remove_back(gen_vec_t *gv) {
assert(gv && "Null ptr passed as gen_vec_t");
MCU_API void* mcu_gen_vec_remove_back(mcu_gen_vec_t *gv) {
assert(gv && "Null ptr passed as mcu_gen_vec_t");
if (gv->count == 0) return NULL;
return gv->inner[gv->count--];
}
MCU_API void* mcu_gen_vec_remove_front(gen_vec_t *gv) {
assert(gv && "Null ptr passed as gen_vec_t");
MCU_API void* mcu_gen_vec_remove_front(mcu_gen_vec_t *gv) {
assert(gv && "Null ptr passed as mcu_gen_vec_t");
if (gv->count == 0) return NULL;
void* data = gv->inner[0];
size_t count = sizeof(void*)*gv->count;
void* tmp = MCU_ALLOC(count);
memcpy(tmp, gv->inner, count);
memcpy(gv->inner - sizeof(void*), tmp, count);
MCU_FREE(tmp);
for (int i = 0; i < gv->count; i++) {
gv->inner[i] = gv->inner[i + 1];
}
gv->count--;
return data;
}

83
test.c
View File

@ -1,13 +1,82 @@
#include <mcutil/test.h>
#include <stdio.h>
#include <stdlib.h>
#include <mcutil/test.h>
#include <mcutil/iter.h>
#include <mcutil/lambda.h>
#include <mcutil/result.h>
#include <mcutil/hash/md5.h>
#include <mcutil/collect/str.h>
#include <mcutil/collect/gen_vec.h>
#include <mcutil/collect/gen_hash_map.h>
#include <mcutil/collect/typed_vec.h>
#include <mcutil/collect/typed_hash_map.h>
#include <string.h>
int main(void) {
int a = 1;
mcu_result_t good = Ok(&a);
mcu_result_t bad = Err("Owo?");
mcu_result_unwrap(good);
mcu_result_unwrap(bad);
#define GEN_VEC_ERR_BAD_ORDER 1
const char* gen_vec_error_t[] = {
[GEN_VEC_ERR_BAD_ORDER] = "Returned items in bad order",
};
int test_gen_vec() {
char* a = malloc(2);
char* b = malloc(2);
char* c = malloc(2);
char* d = malloc(2);
memcpy(a, "A", 2);
memcpy(b, "B", 2);
memcpy(c, "C", 2);
memcpy(d, "D", 2);
// C A B D
mcu_gen_vec_t vec = {0};
mcu_gen_vec_init(&vec);
mcu_gen_vec_insert_front(&vec, (void*)a);
mcu_gen_vec_insert_back(&vec, (void*)b);
mcu_gen_vec_insert_front(&vec, (void*)c);
mcu_gen_vec_insert_back(&vec, (void*)d);
printf("\nAr: %s\n", (char*) vec.inner[0]);
printf("Br: %s\n", (char*) vec.inner[1]);
printf("Cr: %s\n", (char*) vec.inner[2]);
printf("Dr: %s\n", (char*) vec.inner[3]);
char* res_d = mcu_gen_vec_remove_back(&vec);
char* res_c = mcu_gen_vec_remove_front(&vec);
char* res_b = mcu_gen_vec_remove_back(&vec);
char* res_a = mcu_gen_vec_remove_front(&vec);
printf("A: %s\n", res_a);
printf("B: %s\n", res_b);
printf("C: %s\n", res_c);
printf("D: %s\n", res_d);
if ((
strcmp(res_a, "A") ||
strcmp(res_b, "B") ||
strcmp(res_c, "C") ||
strcmp(res_d, "D")
)) {
return GEN_VEC_ERR_BAD_ORDER;
}
return 0;
}
mcu_test_case_t cases[] = {
{
.short_name="GEN_VEC",
.test_fn=test_gen_vec,
.error_types = (char**)gen_vec_error_t,
}
};
int main(void) {
RUN_TEST_CASES(cases);
return 0;
}