@@ -8,6 +8,208 @@ date: 2025-11-29 12:00:00 +0100
88
99[ Compiler Explorer] ( https://godbolt.org/z/PaoT9j1Ed )
1010
11+ ``` c
12+ #include < assert.h>
13+ #include < stdbool.h>
14+ #include < stddef.h>
15+ #include < stdint.h>
16+ #include < stdio.h>
17+ #include < string.h>
18+
19+ typedef enum ErrorCode {
20+ SUCCESS = 0,
21+ STACK_FULL = -1,
22+ STACK_EMPTY = -2,
23+ } ErrorCode;
24+
25+ typedef struct stack {
26+ void *data;
27+ size_t size;
28+ size_t capacity;
29+ size_t element_size;
30+ } stack;
31+
32+ static inline void stack_init (stack * s, void * buffer, size_t element_size, size_t capacity) {
33+ s->data = buffer;
34+ s->size = 0;
35+ s->capacity = capacity;
36+ s->element_size = element_size;
37+ }
38+
39+ static inline ErrorCode stack_push(stack * s, const void * element) {
40+ if (s->size >= s->capacity) {
41+ return STACK_FULL;
42+ }
43+ memcpy((unsigned char * )s->data + s->size * s->element_size, element, s->element_size);
44+ s->size++;
45+ return SUCCESS;
46+ }
47+
48+ static inline ErrorCode stack_pop(stack * s, void * out) {
49+ if (s->size == 0) {
50+ return STACK_EMPTY;
51+ }
52+ s->size--;
53+ memcpy(out, (unsigned char * )s->data + s->size * s->element_size, s->element_size);
54+ return SUCCESS;
55+ }
56+
57+ static inline bool stack_empty(const stack * s) {
58+ return s->size == 0;
59+ }
60+
61+ typedef struct {
62+ uint32_t a;
63+ uint32_t b;
64+ } Pair32;
65+
66+ int main(void) {
67+ Pair32 buffer[ 100] ;
68+ stack s;
69+ stack_init(&s, buffer, sizeof(Pair32), 100);
70+
71+ Pair32 p1 = {.a = 10, .b = 20};
72+ Pair32 p2 = {.a = 111, .b = 222};
73+
74+ assert(stack_push(&s, &p1) == SUCCESS);
75+ assert(stack_push(&s, &p2) == SUCCESS);
76+
77+ Pair32 out2;
78+ assert(stack_pop(&s, &out2) == SUCCESS);
79+ assert(out2.a == 111 && out2.b == 222);
80+
81+ Pair32 out1;
82+ assert(stack_pop(&s, &out1) == SUCCESS);
83+ assert(out1.a == 10 && out1.b == 20);
84+
85+ assert(stack_empty(&s));
86+
87+ printf("Stack test passed.\n");
88+ }
89+ ```
90+
1191# Generic Hash Map
1292
1393[Compiler Explorer](https://godbolt.org/z/16xhne83s)
94+
95+ ```c
96+ #include <assert.h>
97+ #include <stdbool.h>
98+ #include <math.h>
99+ #include <stddef.h>
100+ #include <stdio.h>
101+ #include <string.h>
102+
103+ typedef struct {
104+ bool occupied;
105+ unsigned char key_value[];
106+ } entry;
107+
108+ typedef struct {
109+ void *entries;
110+ size_t capacity, key_size, value_size, entry_size;
111+ } hashmap;
112+
113+ static inline void hashmap_init(hashmap *m, void *buf, size_t ks, size_t vs, size_t cap) {
114+ m->entries = buf;
115+ m->capacity = cap;
116+ m->key_size = ks;
117+ m->value_size = vs;
118+ m->entry_size = sizeof(entry) + ks + vs;
119+ memset(buf, 0, cap * m->entry_size);
120+ }
121+
122+ static inline size_t hash(const void *key, size_t size) {
123+ size_t h = 0;
124+ for (size_t i = 0; i < size; i++)
125+ h = h * 31 + ((unsigned char*)key)[i];
126+ return h;
127+ }
128+
129+ __attribute__((always_inline)) // Necessary for GCC, not Clang
130+ static inline void hashmap_insert(hashmap *m, const void *key, const void *val) {
131+ size_t idx = hash(key, m->key_size) % m->capacity;
132+ for (size_t i = 0; i < m->capacity; i++) {
133+ entry *e = (entry*)((unsigned char*)m->entries + ((idx + i) % m->capacity) * m->entry_size);
134+ if (!e->occupied || memcmp(e->key_value, key, m->key_size) == 0) {
135+ e->occupied = true;
136+ memcpy(e->key_value, key, m->key_size);
137+ memcpy(e->key_value + m->key_size, val, m->value_size);
138+ return;
139+ }
140+ }
141+ }
142+
143+ static inline bool hashmap_get(hashmap *m, const void *key, void *out) {
144+ size_t idx = hash(key, m->key_size) % m->capacity;
145+ for (size_t i = 0; i < m->capacity; i++) {
146+ entry *e = (entry*)((unsigned char*)m->entries + ((idx + i) % m->capacity) * m->entry_size);
147+ if (!e->occupied) return false;
148+ if (memcmp(e->key_value, key, m->key_size) == 0) {
149+ memcpy(out, e->key_value + m->key_size, m->value_size);
150+ return true;
151+ }
152+ }
153+ return false;
154+ }
155+
156+ // Type-safe wrapper for (int, char*) map
157+ typedef struct {
158+ bool occupied;
159+ int key;
160+ char *value;
161+ } IntStrMap_entry;
162+
163+ // Type-safe wrapper for (int, double) map
164+ typedef struct {
165+ bool occupied;
166+ int key;
167+ double value;
168+ } IntDblMap_entry;
169+
170+ int main(void) {
171+ // Test (int, char*) map
172+ IntStrMap_entry buf1[8] = {0};
173+ hashmap m1;
174+ hashmap_init(&m1, buf1, sizeof(int), sizeof(char*), 8);
175+
176+ int k1 = 42;
177+ char *v1 = "foo";
178+ hashmap_insert(&m1, &k1, &v1);
179+
180+ int k2 = 7;
181+ char *v2 = "bar";
182+ hashmap_insert(&m1, &k2, &v2);
183+
184+ char *r1;
185+ hashmap_get(&m1, &k1, &r1);
186+ char *r2;
187+ hashmap_get(&m1, &k2, &r2);
188+
189+ assert(strcmp(r1, "foo") == 0);
190+ assert(strcmp(r2, "bar") == 0);
191+
192+ // Test (int, double) map
193+ IntDblMap_entry buf2[8] = {0};
194+ hashmap m2;
195+ hashmap_init(&m2, buf2, sizeof(int), sizeof(double), 8);
196+
197+ int k3 = 10;
198+ double v3 = 3.14159;
199+ hashmap_insert(&m2, &k3, &v3);
200+
201+ int k4 = 20;
202+ double v4 = 2.71828;
203+ hashmap_insert(&m2, &k4, &v4);
204+
205+ double d1;
206+ hashmap_get(&m2, &k3, &d1);
207+ double d2;
208+ hashmap_get(&m2, &k4, &d2);
209+
210+ assert(fabs(d1 - 3.14159) < 0.00001);
211+ assert(fabs(d2 - 2.71828) < 0.00001);
212+
213+ printf("Hash map test passed.\n");
214+ }
215+ ```
0 commit comments