aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-12 17:12:38 +0200
committerBad Diode <bd@badd10de.dev>2024-06-12 17:12:38 +0200
commit94b95f76ddbc5552c7356753d07bf081a3ae3bb6 (patch)
treefe2df5e386f03b504642a8b21795fb6cead9350c
parent872d0a536280550c7742f0ea805fdfefddd44d9f (diff)
downloadmic-main.tar.gz
mic-main.zip
Add Queue and map iteratorsHEADmain
-rw-r--r--src/app.c174
-rw-r--r--src/shorthand.h173
2 files changed, 201 insertions, 146 deletions
diff --git a/src/app.c b/src/app.c
index 3d28077..371c132 100644
--- a/src/app.c
+++ b/src/app.c
@@ -2,6 +2,11 @@
2#include "app.h" 2#include "app.h"
3#include "platform.h" 3#include "platform.h"
4 4
5#include <stdio.h>
6#include <ctype.h>
7#define printstr(s) if (s) printf("%.*s", (int)(s)->size, (s)->mem);
8#define printstrln(s) if (s) printf("%.*s\n", (int)(s)->size, (s)->mem);
9
5static inline bool 10static inline bool
6app_init(AppState *s, PlatformAPI p) { 11app_init(AppState *s, PlatformAPI p) {
7 p.log("INIT"); 12 p.log("INIT");
@@ -53,10 +58,6 @@ profile_end(PlatformAPI p, char *name) {
53} 58}
54 59
55 60
56#include <stdio.h>
57#define printstr(s) printf("%.*s", (int)(s)->size, (s)->mem);
58#define printstrln(s) printf("%.*s\n", (int)(s)->size, (s)->mem);
59
60bool 61bool
61eq_func(void *a, void *b) { 62eq_func(void *a, void *b) {
62 Str *x = a; 63 Str *x = a;
@@ -76,7 +77,7 @@ hash_func(void *x) {
76} 77}
77 78
78void 79void
79print_node(HashNode *item) { 80print_node(MapNode *item) {
80 if (!item) { 81 if (!item) {
81 return; 82 return;
82 } 83 }
@@ -85,7 +86,7 @@ print_node(HashNode *item) {
85 printstr((Str*)item->key); 86 printstr((Str*)item->key);
86 printf("\\n%ld\", shape=record]\n", (sz)item->val); 87 printf("\\n%ld\", shape=record]\n", (sz)item->val);
87 for (sz i = 0; i < 4; i++) { 88 for (sz i = 0; i < 4; i++) {
88 HashNode *child = item->child[i]; 89 MapNode *child = item->child[i];
89 if (child) { 90 if (child) {
90 printstr((Str*)item->key); 91 printstr((Str*)item->key);
91 printf(" -> "); 92 printf(" -> ");
@@ -96,7 +97,7 @@ print_node(HashNode *item) {
96} 97}
97 98
98void 99void
99print_map(HashMap m) { 100print_map(Map m) {
100 if (m.root == NULL) { 101 if (m.root == NULL) {
101 return; 102 return;
102 } 103 }
@@ -105,16 +106,28 @@ print_map(HashMap m) {
105 printf("}\n"); 106 printf("}\n");
106} 107}
107 108
109void
110iterate_map(Map map, Arena *scratch) {
111 MapIter it = map_iterator(map, scratch);
112 MapNode *item;
113 while ((item = map_next(&it, scratch)) != NULL) {
114 Str *key = item->key;
115 printf("{ ");
116 printstr(key);
117 printf(", %ld }\n", (sz)item->val);
118 }
119}
120
108// Find how many of the given strings are unique. 121// Find how many of the given strings are unique.
109sz 122sz
110unique(Str *strings, sz len, Arena scratch) { 123unique(Str *strings, sz len, Arena *scratch) {
111 sz count = 0; 124 sz count = 0;
112 HashMap map = { 125 Map map = {
113 .eq_func = eq_func, 126 .eq_func = eq_func,
114 .hash_func = hash_func, 127 .hash_func = hash_func,
115 }; 128 };
116 for (sz i = 0; i < len; i++) { 129 for (sz i = 0; i < len; i++) {
117 HashNode *item = upsert(&map, &strings[i], &scratch); 130 MapNode *item = map_upsert(&map, &strings[i], scratch);
118 sz cnt = (sz)item->val; 131 sz cnt = (sz)item->val;
119 item->val = (void*)(++cnt); 132 item->val = (void*)(++cnt);
120 if ((sz)item->val <= 1) { 133 if ((sz)item->val <= 1) {
@@ -122,12 +135,10 @@ unique(Str *strings, sz len, Arena scratch) {
122 } 135 }
123 } 136 }
124 // print_map(map); 137 // print_map(map);
138 // iterate_map(map, scratch);
125 return count; 139 return count;
126} 140}
127 141
128#include <stdio.h>
129#include <ctype.h>
130
131sz 142sz
132token_split(Str s) { 143token_split(Str s) {
133 if (s.size) { 144 if (s.size) {
@@ -170,72 +181,56 @@ token_split(Str s) {
170 return splitter.size; 181 return splitter.size;
171 } 182 }
172 } 183 }
173
174 // splitter = cstr("digraph");
175 // if(str_eq((Str){s.mem, splitter.size}, splitter)) {
176 // return splitter.size;
177 // }
178 // splitter = cstr("node");
179 // if(str_eq((Str){s.mem, splitter.size}, splitter)) {
180 // return splitter.size;
181 // }
182 // splitter = cstr("STRICT");
183 // if(str_eq((Str){s.mem, splitter.size}, splitter)) {
184 // return splitter.size;
185 // }
186 // splitter = cstr("graph");
187 // if(str_eq((Str){s.mem, splitter.size}, splitter)) {
188 // return splitter.size;
189 // }
190 } 184 }
185 // iterate_map(map, scratch);
191 return 0; 186 return 0;
192} 187}
193 188
189sz
190unique_tokenize(Str data, Arena *scratch) {
191 (void)data;
192 sz count = 0;
193 Map map = {
194 .eq_func = eq_func,
195 .hash_func = hash_func,
196 };
197 Str strings[] = {
198 cstr("a"),
199 cstr("b"),
200 cstr("c"),
201 cstr("d"),
202 cstr("e"),
203 cstr("f"),
204 cstr("g"),
205 };
206 for (sz i = 0; i < len(strings); i++) {
207 map_insert(&map, &strings[i], (void*)i, scratch);
208 }
209 iterate_map(map, scratch);
210 // print_map(map);
211 return count;
212}
213
194static inline bool 214static inline bool
195app_step(AppState *s, PlatformAPI p) { 215app_step(AppState *s, PlatformAPI p) {
196 // Passing an arena by value makes the operation self cleaning. 216 // Passing an arena by value makes the operation self cleaning.
197 Arena scratch = s->scratch; 217 Arena scratch = s->scratch;
198 // TODO: split a file into "words" or "tokens" 218 Queue q = {0};
199 // Str strings[] = { 219 queue_push(&q, &cstr("HI!"), &scratch);
200 // cstr("test"), 220 queue_push(&q, &cstr("HO!"), &scratch);
201 // cstr("test"), 221 queue_push(&q, &cstr("HU!"), &scratch);
202 // cstr("test"), 222 Str *val;
203 // cstr("toast"), 223 val = queue_peek(&q); printstrln(val);
204 // cstr("test"), 224 val = queue_pop(&q); printstrln(val);
205 // cstr("helllo"), 225 val = queue_pop(&q); printstrln(val);
206 // cstr("dummy"), 226 val = queue_pop(&q); printstrln(val);
207 // cstr("sasfdladsf"), 227 // Str file_name = cstr("WebstersEnglishDictionary.txt");
208 // cstr("yodog"), 228 Str file_name = cstr("./README.md");
209 // cstr("kazuya"),
210 // cstr("hello"),
211 // cstr("world"),
212 // cstr("what"),
213 // cstr("hello"),
214 // cstr("whot"),
215 // };
216 // sz u = unique(strings, len(strings), scratch);
217 // // return false;
218 // p.log("unique: %ld", u);
219 // u8 * p1 = arena_malloc(10, &scratch);
220 // u8 * p2 = arena_malloc(8, &scratch);
221 // u8 * p3 = arena_malloc(8, &scratch);
222 // p.log("scratch size: %ld", scratch.size);
223 // p.log("ptraddr1: 0x%x", p1);
224 // p.log("ptraddr2: 0x%x", p2);
225 // p.log("ptraddr3: 0x%x", p3);
226 // p.log("base: 0x%x", scratch.beg);
227 Str file_name = cstr("WebstersEnglishDictionary.txt");
228 // Str file_name = cstr("test.dot");
229 FileContents file_content; 229 FileContents file_content;
230 profile("reading_file") { 230 profile("reading_file") {
231 file_content = p.read_file(file_name, &scratch); 231 file_content = p.read_file(file_name, &scratch);
232 } 232 }
233 if (!file_content.err) { 233 if (!file_content.err) {
234 // p.log("file content: `%.*s` (size: %ld)\n"
235 // "%.*s",
236 // file_content.path.size, file_content.path.mem,
237 // file_content.data.size,
238 // MIN(50, file_content.data.size), file_content.data.mem);
239 Str data = file_content.data; 234 Str data = file_content.data;
240 profile("str_replace_all") { 235 profile("str_replace_all") {
241 str_replace_all(&data, cstr("\n"), cstr(" ")); 236 str_replace_all(&data, cstr("\n"), cstr(" "));
@@ -243,37 +238,22 @@ app_step(AppState *s, PlatformAPI p) {
243 Str *tokens = NULL; 238 Str *tokens = NULL;
244 array_init(tokens, 256, &scratch); 239 array_init(tokens, 256, &scratch);
245 profile("create_tokens") { 240 profile("create_tokens") {
246 while (data.size > 0) { 241 while (data.size > 0) {
247 // // Str line = str_split(&data, cstr("\n")); printstrln(&line); 242 // Str token = str_split(&data, cstr(" "));
248 // // Str line = str_split(&data, cstr("\n")); printstrln(&line); 243 Str token = str_split_fn(&data, token_split);
249 // // Str token = str_split(&data, cstr(" ")); 244 if (token.size > 0) {
250 Str token = str_split_fn(&data, token_split); 245 array_push(tokens, token, &scratch);
251 if (token.size > 0) { 246 }
252 // printstrln(&token);
253 // // printf("has_prefix: `app_`: %d ", str_has_prefix(token, cstr("app_")));
254 // // printf("has_suffix: `API`: %d ", str_has_suffix(token, cstr("API")));
255 // // printf("token_size: %03ld | ", token.size); printstr(&token);
256 // // printf(" -> ");
257 // // token = str_remove_prefix(token, cstr("app_")); printstr(&token)
258 // // printf(" -> ");
259 // // token = str_remove_suffix(token, cstr("API")); printstr(&token)
260 // p.log("N: %ld", array_size(tokens));
261 array_push(tokens, token, &scratch);
262 // // printf("\n");
263 } 247 }
264 } 248 }
265 }
266 // for (sz i = 0; i < array_size(tokens); i++) {
267 // // printstrln(&tokens[i]);
268 // }
269 // for (sz i = 0; i < len(strings); i++) {
270 // array_push(tokens, strings[i], &scratch);
271 // }
272 sz u; 249 sz u;
273 profile("find unique") { 250 profile("find unique") {
274 u = unique(tokens, array_size(tokens), scratch); 251 u = unique(tokens, array_size(tokens), &scratch);
252 }
253 p.log("unique: %ld", u);
254 profile("find unique (directly)") {
255 u = unique_tokenize(file_content.data, &scratch);
275 } 256 }
276 // return false;
277 p.log("unique: %ld", u); 257 p.log("unique: %ld", u);
278 } else { 258 } else {
279 Str err_msg = err_str[file_content.err]; 259 Str err_msg = err_str[file_content.err];
@@ -281,16 +261,16 @@ app_step(AppState *s, PlatformAPI p) {
281 err_msg.size, err_msg.mem, 261 err_msg.size, err_msg.mem,
282 file_name.size, file_name.mem); 262 file_name.size, file_name.mem);
283 } 263 }
284 // p.log("Used memory: scratch -> %lld/%lld KB, perm -> %lld/%lld KB",
285 // scratch.size / 1024,
286 // scratch.cap / 1024,
287 // s->perm.size / 1024,
288 // s->perm.cap / 1024);
289 p.log("Used memory: scratch -> %lld/%lld MB, perm -> %lld/%lld MB", 264 p.log("Used memory: scratch -> %lld/%lld MB, perm -> %lld/%lld MB",
290 scratch.size / 1024 / 1024, 265 scratch.size / 1024 / 1024,
291 scratch.cap / 1024 / 1024, 266 scratch.cap / 1024 / 1024,
292 s->perm.size / 1024 / 1024, 267 s->perm.size / 1024 / 1024,
293 s->perm.cap / 1024 / 1024); 268 s->perm.cap / 1024 / 1024);
269 // p.log("Used memory: scratch -> %lld/%lld KB, perm -> %lld/%lld KB",
270 // scratch.size / 1024,
271 // scratch.cap / 1024,
272 // s->perm.size / 1024,
273 // s->perm.cap / 1024);
294 // p.log("Used memory: scratch -> %lld/%lld B, perm -> %lld/%lld B", 274 // p.log("Used memory: scratch -> %lld/%lld B, perm -> %lld/%lld B",
295 // scratch.size, 275 // scratch.size,
296 // scratch.cap, 276 // scratch.cap,
diff --git a/src/shorthand.h b/src/shorthand.h
index 879b8ed..f70c792 100644
--- a/src/shorthand.h
+++ b/src/shorthand.h
@@ -3,15 +3,10 @@
3 3
4// TODO: 4// TODO:
5// - Add string operations. 5// - Add string operations.
6// - eq
7// - sub 6// - sub
8// - contains 7// - contains
9// - remove_prefix
10// - remove_suffix
11// - find_first 8// - find_first
12// - find_last 9// - find_last
13// - pop_split
14// - split
15// - Add string buffer operations. 10// - Add string buffer operations.
16// - make 11// - make
17// - append 12// - append
@@ -19,7 +14,6 @@
19// - remove 14// - remove
20// - to_str 15// - to_str
21// - Add math operations for vectors and matrices. 16// - Add math operations for vectors and matrices.
22// - Add darray and hash_map.
23// - Can we remove the PlatformAPI function pointers and just use extern 17// - Can we remove the PlatformAPI function pointers and just use extern
24// references? 18// references?
25// - Breakdown this file in the different library parts. 19// - Breakdown this file in the different library parts.
@@ -277,7 +271,7 @@ arena_calloc(sz size, void *ctx) {
277 271
278void 272void
279arena_free(void *ptr, sz size, void *ctx) { 273arena_free(void *ptr, sz size, void *ctx) {
280 // Undo the latest allocation. 274 // Undo the latest allocation if possible.
281 Arena *a = (Arena *)ctx; 275 Arena *a = (Arena *)ctx;
282 sz padding = -size & (ARENA_ALIGNMENT - 1); 276 sz padding = -size & (ARENA_ALIGNMENT - 1);
283 size += padding; 277 size += padding;
@@ -288,6 +282,9 @@ arena_free(void *ptr, sz size, void *ctx) {
288 282
289void * 283void *
290arena_realloc(void *ptr, sz old_size, sz new_size, void *ctx) { 284arena_realloc(void *ptr, sz old_size, sz new_size, void *ctx) {
285 // This function can avoid copying memory around if we could just extend the
286 // latest allocation, otherwise a new malloc will be performed (keeping the
287 // previous data alive!).
291 Arena *a = (Arena *)ctx; 288 Arena *a = (Arena *)ctx;
292 sz old_padding = -old_size & (ARENA_ALIGNMENT - 1); 289 sz old_padding = -old_size & (ARENA_ALIGNMENT - 1);
293 old_size += old_padding; 290 old_size += old_padding;
@@ -328,27 +325,84 @@ arena_reset(Arena *a) {
328 a->size = 0; 325 a->size = 0;
329} 326}
330 327
331struct HashTable; 328//
329// Queue.
330//
331
332typedef struct QueueVal {
333 struct QueueVal *next;
334 void *val;
335} QueueVal;
336
337typedef struct Queue {
338 struct QueueVal *head;
339 struct QueueVal *tail;
340 sz size;
341} Queue;
342
343void
344queue_push(Queue *l, void *val, Arena *a) {
345 assert(l);
346 QueueVal *next = (QueueVal*)arena_calloc(sizeof(QueueVal), a);
347 next->val = val;
348 if (l->size == 0) {
349 l->head = next;
350 l->tail = next;
351 l->size = 1;
352 return;
353 }
354 QueueVal *cur = l->tail;
355 cur->next = next;
356 l->tail = next;
357 l->size++;
358}
359
360void *
361queue_peek(Queue *l) {
362 assert(l);
363 if (l->size == 0) {
364 return NULL;
365 }
366 QueueVal *cur = l->head;
367 return cur->val;
368}
369
370void *
371queue_pop(Queue *l) {
372 assert(l);
373 if (l->size == 0) {
374 return NULL;
375 }
376 QueueVal *cur = l->head;
377 l->head = cur->next;
378 l->size--;
379 return cur->val;
380}
381
382//
383// Map.
384//
385
332typedef u64 (HashFunc)(void *in); 386typedef u64 (HashFunc)(void *in);
333typedef bool (EqFunc)(void *a, void *b); 387typedef bool (EqFunc)(void *a, void *b);
334 388
335typedef struct HashNode { 389typedef struct MapNode {
336 struct HashNode *child[4]; 390 struct MapNode *child[4];
337 void *key; 391 void *key;
338 void *val; 392 void *val;
339} HashNode; 393} MapNode;
340 394
341typedef struct HashMap { 395typedef struct Map {
342 HashFunc *hash_func; 396 HashFunc *hash_func;
343 EqFunc *eq_func; 397 EqFunc *eq_func;
344 HashNode *root; 398 MapNode *root;
345 Arena *storage; 399 Arena *storage;
346} HashMap; 400} Map;
347 401
348HashNode * 402MapNode *
349upsert(HashMap *m, void *key, Arena *a) { 403map_upsert(Map *m, void *key, Arena *a) {
350 u64 h = m->hash_func(key); 404 u64 h = m->hash_func(key);
351 HashNode **item = &m->root; 405 MapNode **item = &m->root;
352 while (*item) { 406 while (*item) {
353 if (m->eq_func(key, (*item)->key)) { 407 if (m->eq_func(key, (*item)->key)) {
354 return *item; 408 return *item;
@@ -356,15 +410,32 @@ upsert(HashMap *m, void *key, Arena *a) {
356 h = (h << 2) | (h >> 62); 410 h = (h << 2) | (h >> 62);
357 item = &(*item)->child[h & 0x3]; 411 item = &(*item)->child[h & 0x3];
358 } 412 }
359 *item = (HashNode *)arena_calloc(sizeof(HashNode), a); 413 *item = (MapNode *)arena_calloc(sizeof(MapNode), a);
360 (*item)->key = key; 414 (*item)->key = key;
361 return *item; 415 return *item;
362} 416}
363 417
364HashNode * 418void
365lookup(HashMap *m, void *key) { 419map_insert(Map *m, void *key, void *val, Arena *a) {
366 u64 h = m->hash_func(key); 420 u64 h = m->hash_func(key);
367 HashNode **item = &m->root; 421 MapNode **item = &m->root;
422 while (*item) {
423 if (m->eq_func(key, (*item)->key)) {
424 (*item)->val = val;
425 return;
426 }
427 h = (h << 2) | (h >> 62);
428 item = &(*item)->child[h & 0x3];
429 }
430 *item = (MapNode *)arena_calloc(sizeof(MapNode), a);
431 (*item)->key = key;
432 (*item)->val = val;
433}
434
435MapNode *
436map_lookup(Map *m, void *key) {
437 u64 h = m->hash_func(key);
438 MapNode **item = &m->root;
368 while (*item) { 439 while (*item) {
369 if (m->eq_func(key, (*item)->key)) { 440 if (m->eq_func(key, (*item)->key)) {
370 return *item; 441 return *item;
@@ -375,34 +446,38 @@ lookup(HashMap *m, void *key) {
375 return NULL; 446 return NULL;
376} 447}
377 448
378// u64 449typedef struct MapIter {
379// hash(Str s) { 450 Queue queue;
380// u64 h = 0x100; 451} MapIter;
381// for (sz i = 0; i < s.size; i++) { 452
382// h ^= s.mem[i]; 453MapIter
383// h *= 1111111111111111111u; 454map_iterator(Map map, Arena *a) {
384// } 455 MapIter it = {0};
385// return h; 456 queue_push(&it.queue, map.root, a);
386// } 457 return it;
387 458}
388// typedef struct StrMap { 459
389// struct StrMap *child[4]; 460MapNode *
390// Str key; 461map_next(MapIter *it, Arena *a) {
391// sz val; 462 assert(it);
392// } StrMap; 463 assert(a);
393 464 while (it->queue.head) {
394// StrMap * 465 MapNode *item = (MapNode *)queue_pop(&it->queue);
395// upsert(StrMap **m, Str key, Arena *a) { 466 for (sz i = 0; i < 4; i++) {
396// for (u64 h = hash(key); *m; h <<= 2) { 467 MapNode *child = item->child[i];
397// if (str_eq(key, (*m)->key)) { 468 if (child) {
398// return *m; 469 queue_push(&it->queue, child, a);
399// } 470 }
400// m = &(*m)->child[h >> 62]; 471 }
401// } 472 return item;
402// *m = (StrMap *)arena_calloc(sizeof(StrMap), a); 473 }
403// (*m)->key = key; 474 return NULL;
404// return *m; 475}
405// } 476
477
478//
479// Dynamic arrays.
480//
406 481
407typedef struct ArrayHeader { 482typedef struct ArrayHeader {
408 sz size; 483 sz size;