aboutsummaryrefslogtreecommitdiffstats
path: root/src/badlib.h
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-14 17:55:51 +0200
committerBad Diode <bd@badd10de.dev>2024-06-14 17:55:51 +0200
commit3aae2f36047e9adc6a59b886492254eb4370777d (patch)
tree7d8f8fc069393dd38e9688d8d7cf77117ba5235f /src/badlib.h
parentdeaf192df939c9ec9a62ef4febaf76ade0dcbb01 (diff)
downloadbdl-3aae2f36047e9adc6a59b886492254eb4370777d.tar.gz
bdl-3aae2f36047e9adc6a59b886492254eb4370777d.zip
Starting fresh with the `badlang`
Diffstat (limited to 'src/badlib.h')
-rw-r--r--src/badlib.h876
1 files changed, 876 insertions, 0 deletions
diff --git a/src/badlib.h b/src/badlib.h
new file mode 100644
index 0000000..f7a7974
--- /dev/null
+++ b/src/badlib.h
@@ -0,0 +1,876 @@
1#ifndef BADLIB_H
2#define BADLIB_H
3
4// TODO:
5// - Add string operations.
6// - sub
7// - Add math operations for vectors and matrices.
8// - Can we remove the PlatformAPI function pointers and just use extern
9// references?
10// - Breakdown this file in the different library parts.
11// - Sort arrays / linked lists with custom functions?
12// - Implement binary search for searching into an array:
13// SearchResult find_array(Array haystack, Array needle).
14//
15
16#include <stdbool.h>
17#include <stddef.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <strings.h>
22#define printstr(s) \
23 if (s) printf("%.*s", (int)(s)->size, (s)->mem);
24#define printstrln(s) \
25 if (s) printf("%.*s\n", (int)(s)->size, (s)->mem);
26
27//
28// This simple header just typedefs the basic C define types to a shorter name,
29// loads the quality of life bool macro for _Bool and defines shorthand macros
30// for byte sizes. We need that the targeted architecture uses the floating
31// point representation as described on the IEEE-754 standard.
32//
33
34_Static_assert(sizeof(double) == 8, "no support for IEEE-754");
35_Static_assert(sizeof(float) == 4, "no support for IEEE-754");
36
37typedef uint8_t u8;
38typedef uint16_t u16;
39typedef uint32_t u32;
40typedef uint64_t u64;
41typedef int8_t s8;
42typedef int16_t s16;
43typedef int32_t s32;
44typedef int64_t s64;
45typedef float f32;
46typedef double f64;
47typedef ptrdiff_t sz;
48typedef uintptr_t ptrsize;
49typedef size_t usize;
50
51#define KB(N) ((sz)(N)*1024)
52#define MB(N) ((sz)KB(N) * 1024)
53#define GB(N) ((sz)MB(N) * 1024)
54#define TB(N) ((sz)GB(N) * 1024)
55
56// Custom assert macro, better for debugging.
57#ifdef DEBUG
58#define assert(c) \
59 while (!(c)) \
60 __builtin_unreachable()
61#else
62#define assert(c) ;
63#endif
64
65// Abort macro without stdlib.
66#define abort() __builtin_trap()
67
68// Utility macros for numeric comparisons.
69#define MIN(A, B) ((A) <= (B) ? (A) : (B))
70#define MAX(A, B) ((A) >= (B) ? (A) : (B))
71#define ABS(A) \
72 (((A) ^ ((A) >> (sizeof(A) * 8 - 1))) - ((A) >> (sizeof(A) * 8 - 1)))
73#define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX) : (X))
74#define LEN(a) (sz)(sizeof(a) / sizeof(*(a)))
75
76// Handy defer bacro for scoped operations.
77#define MACRO_VAR_CONCAT_HELPER(X, Y) X##Y
78#define MACRO_VAR_CONCAT(X, Y) MACRO_VAR_CONCAT_HELPER(X, Y)
79#define MACRO_VAR(name) MACRO_VAR_CONCAT(name, __LINE__)
80#define defer(begin, end) \
81 for (sz MACRO_VAR(_i_) = (begin, 0); !MACRO_VAR(_i_); \
82 (MACRO_VAR(_i_) += 1), end)
83
84//
85// Allocators and Arenas.
86//
87
88typedef struct Allocator {
89 void *(*malloc)(sz, void *ctx);
90 void *(*calloc)(sz, void *ctx);
91 void (*free)(void *, void *ctx);
92 void *(*realloc)(void *ptr, sz old_size, sz new_size, void *ctx);
93 void *ctx;
94} Allocator;
95
96typedef struct Arena {
97 u8 *beg;
98 sz size;
99 sz cap;
100} Arena;
101
102#define ARENA_ALIGNMENT 8
103
104void *
105arena_malloc(sz size, void *ctx) {
106 assert(size > 0);
107 Arena *a = (Arena *)ctx;
108 sz padding = -size & (ARENA_ALIGNMENT - 1);
109 sz available = a->cap - a->size;
110 if (available < 0 || available < size) {
111 abort();
112 }
113 void *p = a->beg + a->size;
114 a->size += padding + size;
115 return p;
116}
117
118void *
119arena_calloc(sz size, void *ctx) {
120 void *mem = arena_malloc(size, ctx);
121 return memset(mem, 0, size);
122}
123
124void
125arena_free(void *ptr, sz size, void *ctx) {
126 // Undo the latest allocation if possible.
127 Arena *a = (Arena *)ctx;
128 sz padding = -size & (ARENA_ALIGNMENT - 1);
129 size += padding;
130 if (ptr == a->beg + a->size - size) {
131 a->size -= size;
132 }
133}
134
135void *
136arena_realloc(void *ptr, sz old_size, sz new_size, void *ctx) {
137 // This function can avoid copying memory around if we could just extend the
138 // latest allocation, otherwise a new malloc will be performed (keeping the
139 // previous data alive!).
140 Arena *a = (Arena *)ctx;
141 sz old_padding = -old_size & (ARENA_ALIGNMENT - 1);
142 old_size += old_padding;
143 if (ptr == a->beg + a->size - old_size) {
144 sz new_padding = -new_size & (ARENA_ALIGNMENT - 1);
145 new_size += new_padding;
146 a->size += new_size - old_size;
147 return ptr;
148 }
149 u8 *p = (u8 *)arena_malloc(new_size, ctx);
150 memcpy(p, ptr, old_size);
151 return p;
152}
153
154Arena
155arena_create(sz cap, Allocator allocator) {
156 Arena arena = {0};
157 arena.beg = (u8 *)allocator.malloc(cap, allocator.ctx);
158 arena.cap = arena.beg ? cap : 0;
159 return arena;
160}
161
162void
163arena_destroy(Arena *arena, Allocator allocator) {
164 allocator.free(arena->beg, allocator.ctx);
165}
166
167void
168arena_reset(Arena *a) {
169 a->size = 0;
170}
171
172//
173// Arrays, Buffers and Strings.
174//
175
176// A fixed buffer or buffer view, represented as a fat pointer.
177typedef struct Array {
178 u8 *mem;
179 sz size;
180} Array;
181
182typedef struct SearchResult {
183 // Position on the buffer where a result was found.
184 sz pos;
185 // Size of the matched query.
186 sz matched;
187 // Wether the search was successful or not.
188 bool found;
189} SearchResult;
190
191bool
192array_eq(Array a, Array b) {
193 return a.size == b.size && !memcmp(a.mem, b.mem, a.size);
194}
195
196SearchResult
197array_find_next(Array haystack, Array needle) {
198 sz pos = 0;
199 while (haystack.size >= needle.size) {
200 if (*haystack.mem == *needle.mem) {
201 Array candidate = (Array){
202 .mem = haystack.mem,
203 .size = needle.size,
204 };
205 if (array_eq(candidate, needle)) {
206 return (SearchResult){
207 .pos = pos,
208 .matched = needle.size,
209 .found = true,
210 };
211 }
212 }
213 haystack.mem++;
214 haystack.size--;
215 pos++;
216 }
217 return (SearchResult){.found = false};
218}
219
220// A growable arena backed buffer.
221typedef struct Buf {
222 u8 *mem;
223 sz size;
224 sz cap;
225} Buf;
226
227// Reserve a given amount of bytes for a growable buffer.
228void
229buf_reserve(Buf *buf, sz size, Arena *a) {
230 assert(buf);
231 buf->mem = arena_realloc(buf->mem, buf->size, size, a);
232 buf->size = 0;
233 buf->cap = size;
234}
235
236// Zero initialize a growable buffer.
237void
238buf_zero(Buf *buf, sz size, Arena *a) {
239 buf_reserve(buf, size, a);
240 memset(buf->mem, 0, buf->cap);
241}
242
243// Insert a number of bytes into a growable buffer.
244void
245buf_insert(Buf *buf, void *value, sz size, Arena *a) {
246 assert(buf);
247 if (size == 0) {
248 return;
249 }
250 if (!buf->mem) {
251 buf->mem = arena_malloc(size, a);
252 buf->size = size;
253 buf->cap = size;
254 memcpy(buf->mem, value, size);
255 return;
256 }
257 while (buf->cap < buf->size + size) {
258 arena_realloc(buf->mem, buf->cap, buf->cap * 2, a);
259 buf->cap *= 2;
260 }
261 memcpy(buf->mem + buf->size, value, size);
262 buf->size += size;
263}
264
265// Gets a reference to a given position of the buffer. It doesn't copy any
266// information so bear in mind it could become invalidated if the buffer is
267// modified.
268void *
269buf_ref(Buf *buf, sz pos, sz size) {
270 return buf->mem + pos * size;
271}
272
273// Copies a number of bytes from an indexed position from growable buffer into
274// the given destination.
275void
276buf_get(Buf *buf, void *dst, sz pos, sz size) {
277 memcpy(dst, buf->mem + pos * size, size);
278}
279
280// Pops a number of bytes from a growable buffer into the given destination,
281// copying the result and reducing the size of the buffer.
282void
283buf_pop(Buf *buf, void *dst, sz size) {
284 assert(buf->mem + buf->size - size >= buf->mem);
285 memcpy(dst, buf->mem + buf->size - size, size);
286 buf->size -= size;
287}
288
289// A string or string view.
290typedef Array Str;
291
292// Create a string view from a C literal with these.
293#define cstr(s) \
294 (Str) { \
295 (u8 *)s, LEN(s) - 1 \
296 }
297
298bool
299str_eq(Str a, Str b) {
300 return array_eq(a, b);
301}
302
303Str
304str_split(Str *a, Str split) {
305 assert(a != NULL);
306 Str ret = *a;
307 SearchResult res = array_find_next(*a, split);
308 if (res.found) {
309 ret.size = res.pos;
310 a->mem += res.pos + res.matched;
311 a->size -= res.pos + res.matched;
312 return ret;
313 }
314 *a = (Str){0};
315 return ret;
316}
317
318// A customizable splitting function.
319typedef sz(StrSplitFn)(Str s);
320
321Str
322str_split_fn(Str *a, StrSplitFn split_fn) {
323 assert(a != NULL);
324 Str ret = *a;
325 while (a->size > 0) {
326 sz advance = split_fn(*a);
327 if (advance) {
328 ret.size -= a->size;
329 a->size -= advance;
330 a->mem += advance;
331 return ret;
332 }
333 a->size--;
334 a->mem++;
335 }
336 return ret;
337}
338
339// Replaces a single pattern on a string. `from` and `to` have to be of the same
340// size.
341void
342str_replace(Str *a, Str from, Str to) {
343 assert(a != NULL);
344 assert(from.size == to.size);
345 SearchResult res = array_find_next(*a, from);
346 if (res.found) {
347 memcpy(a->mem + res.pos, to.mem, res.matched);
348 return;
349 }
350}
351
352// Same as `str_replace` but applied to all occurences of `from`.
353void
354str_replace_all(Str *a, Str from, Str to) {
355 assert(a != NULL);
356 assert(from.size == to.size);
357 Str data = *a;
358 SearchResult res = array_find_next(data, from);
359 while (res.found) {
360 memcpy(data.mem + res.pos, to.mem, res.matched);
361 data.mem += res.pos;
362 data.size -= res.pos;
363 res = array_find_next(data, from);
364 }
365}
366
367bool
368str_has_prefix(Str str, Str prefix) {
369 if (str.size < prefix.size) {
370 return false;
371 }
372 Str candidate = (Str){
373 .mem = str.mem,
374 .size = prefix.size,
375 };
376 return str_eq(candidate, prefix);
377}
378
379bool
380str_has_suffix(Str str, Str suffix) {
381 if (str.size < suffix.size) {
382 return false;
383 }
384 Str candidate = (Str){
385 .mem = str.mem + str.size - suffix.size,
386 .size = suffix.size,
387 };
388 return str_eq(candidate, suffix);
389}
390
391Str
392str_remove_prefix(Str str, Str prefix) {
393 if (!str_has_prefix(str, prefix)) {
394 return str;
395 }
396 str.mem += prefix.size;
397 str.size -= prefix.size;
398 return str;
399}
400
401Str
402str_remove_suffix(Str str, Str suffix) {
403 if (!str_has_suffix(str, suffix)) {
404 return str;
405 }
406 str.size -= suffix.size;
407 return str;
408}
409
410// Concat.
411Str
412str_concat(Str x, Str y, Arena *a) {
413 Buf buf = {0};
414 buf_insert(&buf, x.mem, x.size, a);
415 buf_insert(&buf, y.mem, y.size, a);
416 return (Str){
417 .mem = buf.mem,
418 .size = buf.size,
419 };
420}
421
422Str
423str_insert(Str orig, Str value, sz position, Arena *a) {
424 Buf buf = {0};
425 buf_insert(&buf, orig.mem, position, a);
426 buf_insert(&buf, value.mem, value.size, a);
427 buf_insert(&buf, orig.mem + position, orig.size - position, a);
428 return (Str){
429 .mem = buf.mem,
430 .size = buf.size,
431 };
432}
433
434// Str
435// str_delete(Str orig, Str value, Arena *a) {
436// Buf buf = {0};
437// // TODO: find first location
438// // TODO: insert orig until that location
439// // TODO: insert orig after location + value.size
440// // buf_insert(&buf, orig.mem, position, a);
441// // buf_insert(&buf, value.mem, value.size, a);
442// // buf_insert(&buf, orig.mem + position, orig.size - position, a);
443// return (Str){
444// .mem = buf.mem,
445// .size = buf.size,
446// };
447// }
448
449//
450// Queue.
451//
452
453typedef struct QueueVal {
454 struct QueueVal *next;
455 void *val;
456} QueueVal;
457
458typedef struct Queue {
459 QueueVal *head;
460 QueueVal *tail;
461 sz size;
462} Queue;
463
464void
465queue_push(Queue *l, void *val, Arena *a) {
466 assert(l);
467 QueueVal *next = (QueueVal *)arena_calloc(sizeof(QueueVal), a);
468 next->val = val;
469 if (l->size == 0) {
470 l->head = next;
471 l->tail = next;
472 l->size = 1;
473 return;
474 }
475 QueueVal *cur = l->tail;
476 cur->next = next;
477 l->tail = next;
478 l->size++;
479}
480
481void *
482queue_peek(Queue *l) {
483 assert(l);
484 if (l->size == 0) {
485 return NULL;
486 }
487 QueueVal *cur = l->head;
488 return cur->val;
489}
490
491void *
492queue_pop(Queue *l) {
493 assert(l);
494 if (l->size == 0) {
495 return NULL;
496 }
497 QueueVal *cur = l->head;
498 l->head = cur->next;
499 l->size--;
500 return cur->val;
501}
502
503//
504// Map.
505//
506
507typedef u64(HashFunc)(void *in);
508typedef bool(EqFunc)(void *a, void *b);
509
510typedef struct MapNode {
511 struct MapNode *child[4];
512 void *key;
513 void *val;
514} MapNode;
515
516typedef struct Map {
517 HashFunc *hash_func;
518 EqFunc *eq_func;
519 MapNode *root;
520 Arena *storage;
521} Map;
522
523MapNode *
524map_upsert(Map *m, void *key, Arena *a) {
525 u64 h = m->hash_func(key);
526 MapNode **item = &m->root;
527 while (*item) {
528 if (m->eq_func(key, (*item)->key)) {
529 return *item;
530 }
531 h = (h << 2) | (h >> 62);
532 item = &(*item)->child[h & 0x3];
533 }
534 *item = (MapNode *)arena_calloc(sizeof(MapNode), a);
535 (*item)->key = key;
536 return *item;
537}
538
539void
540map_insert(Map *m, void *key, void *val, Arena *a) {
541 u64 h = m->hash_func(key);
542 MapNode **item = &m->root;
543 while (*item) {
544 if (m->eq_func(key, (*item)->key)) {
545 (*item)->val = val;
546 return;
547 }
548 h = (h << 2) | (h >> 62);
549 item = &(*item)->child[h & 0x3];
550 }
551 *item = (MapNode *)arena_calloc(sizeof(MapNode), a);
552 (*item)->key = key;
553 (*item)->val = val;
554}
555
556MapNode *
557map_lookup(Map *m, void *key) {
558 u64 h = m->hash_func(key);
559 MapNode **item = &m->root;
560 while (*item) {
561 if (m->eq_func(key, (*item)->key)) {
562 return *item;
563 }
564 h = (h << 2) | (h >> 62);
565 item = &(*item)->child[h & 0x3];
566 }
567 return NULL;
568}
569
570typedef struct MapIter {
571 Queue queue;
572} MapIter;
573
574MapIter
575map_iterator(Map map, Arena *a) {
576 MapIter it = {0};
577 queue_push(&it.queue, map.root, a);
578 return it;
579}
580
581MapNode *
582map_next(MapIter *it, Arena *a) {
583 assert(it);
584 assert(a);
585 while (it->queue.head) {
586 MapNode *item = (MapNode *)queue_pop(&it->queue);
587 for (sz i = 0; i < 4; i++) {
588 MapNode *child = item->child[i];
589 if (child) {
590 queue_push(&it->queue, child, a);
591 }
592 }
593 return item;
594 }
595 return NULL;
596}
597
598//
599// Dynamic arrays.
600//
601
602typedef struct ArrayHeader {
603 sz size;
604 sz cap;
605} ArrayHeader;
606
607// Header/Size/capacity accessors.
608#define array_head(ARR) ((ArrayHeader *)((char *)(ARR) - sizeof(ArrayHeader)))
609#define array_size(ARR) ((ARR) ? array_head(ARR)->size : 0)
610#define array_cap(ARR) ((ARR) ? array_head(ARR)->cap : 0)
611
612// Initialize a dynamic array ARR with N elements. The initialization doesn't
613// zero out the data, so thread carefully..
614#define array_init(ARR, N, ARENA) \
615 ((ARR) = _array_reserve(N, sizeof(*(ARR)), (ARENA)))
616
617// Push a given element T to the dynamic array ARR.
618#define array_push(ARR, T, ARENA) \
619 ((ARR) = _array_maybe_grow((ARR), sizeof(T), (ARENA)), \
620 (ARR)[array_head(ARR)->size++] = (T))
621
622// Return the last element of the array. Can be used to build stacks.
623#define array_pop(ARR) (ARR)[--array_head(ARR)->size]
624
625// Return the value stored at the OFFSET position from the tail of the array.
626#define array_peek(ARR, OFFSET) (ARR)[array_head(ARR)->size - 1 - (OFFSET)]
627
628// Insert N bytes from the SRC array into the ARR dynamic array.
629#define array_insert(ARR, SRC, N, ARENA) \
630 ((ARR) = _array_insert((ARR), (SRC), (N), sizeof(*(ARR)), (ARENA)))
631
632// Free the memory from the original allocated position.
633#define array_free(ARR) ((ARR) ? free(array_head(ARR)), (ARR) = NULL : 0)
634
635static inline void *
636_array_reserve(sz num_elem, sz type_size, Arena *a) {
637 u8 *p = (u8 *)arena_malloc(num_elem * type_size + sizeof(ArrayHeader), a);
638 p += sizeof(ArrayHeader);
639 array_head(p)->size = 0;
640 array_head(p)->cap = num_elem;
641 return p;
642}
643
644static inline void *
645_array_maybe_grow(void *arr, sz type_size, Arena *a) {
646 ArrayHeader *head = array_head(arr);
647 if (head->cap == head->size) {
648 sz prev_size = head->cap * type_size + sizeof(ArrayHeader);
649 if (head->cap == 0) {
650 head->cap++;
651 } else {
652 head->cap *= 2;
653 }
654 sz new_size = head->cap * type_size + sizeof(ArrayHeader);
655 head = (ArrayHeader *)arena_realloc(head, prev_size, new_size, a);
656 }
657 arr = (char *)head + sizeof(ArrayHeader);
658 return arr;
659}
660
661static inline char *
662_array_insert(char *arr, const char *src, sz n_bytes, sz type_size, Arena *a) {
663 ArrayHeader *head = array_head(arr);
664 sz new_size = n_bytes + head->size;
665 if (new_size > head->cap * type_size) {
666 sz prev_size = head->cap * type_size + sizeof(ArrayHeader);
667 if (head->cap == 0) {
668 head->cap = 1;
669 }
670 while (new_size >= head->cap * type_size) {
671 head->cap *= 2;
672 }
673 sz new_size = head->cap * type_size + sizeof(ArrayHeader);
674 head = (ArrayHeader *)arena_realloc(head, prev_size, new_size, a);
675 }
676 arr = (char *)head + sizeof(ArrayHeader);
677 memcpy((arr + head->size), src, n_bytes);
678 head->size = new_size;
679 return arr;
680}
681
682//
683// Math.
684//
685
686typedef union Vec2f {
687 struct {
688 f32 x, y;
689 };
690 struct {
691 f32 u, v;
692 };
693 struct {
694 f32 left, right;
695 };
696 struct {
697 f32 width, height;
698 };
699 f32 data[2];
700} Vec2f;
701
702typedef union Vec3f {
703 struct {
704 f32 x, y, z;
705 };
706 struct {
707 f32 u, v, w;
708 };
709 struct {
710 f32 r, g, b;
711 };
712 struct {
713 Vec2f xy;
714 f32 _z;
715 };
716 struct {
717 f32 _x;
718 Vec2f yz;
719 };
720 struct {
721 Vec2f uv;
722 f32 _w;
723 };
724 struct {
725 f32 _u;
726 Vec2f vw;
727 };
728 f32 data[2];
729} Vec3f;
730
731typedef union Vec4f {
732 struct {
733 f32 x, y, z, w;
734 };
735 struct {
736 Vec3f xyz;
737 f32 _w;
738 };
739 struct {
740 union {
741 Vec3f rgb;
742 struct {
743 f32 r, g, b;
744 };
745 };
746 f32 a;
747 };
748 struct {
749 Vec2f xy;
750 f32 _y0;
751 f32 _z0;
752 };
753 struct {
754 f32 _x0;
755 Vec2f yz;
756 f32 _z1;
757 };
758 struct {
759 f32 _x1;
760 f32 _y1;
761 Vec2f zw;
762 };
763 f32 data[4];
764} Vec4f;
765
766//
767// OS/Platform stuff.
768//
769
770typedef enum {
771 FILE_ERR_OK = 0,
772 FILE_ERR_CANT_OPEN,
773 FILE_ERR_READ_ERR,
774 FILE_ERR_PATH_TOO_BIG,
775 FILE_ERR_EMPTY,
776 FILE_ERR_NUM,
777} FileErr;
778
779Str file_err_str[FILE_ERR_NUM] = {
780 cstr(""),
781 cstr("couldn't open file"),
782 cstr("couldn't read file"),
783 cstr("file path too big"),
784 cstr("file is empty"),
785};
786
787typedef struct FileContents {
788 Str path;
789 Array data;
790 FileErr err;
791} FileContents;
792
793FileContents
794platform_read_file(Str path, Arena *a) {
795 // Transform Str to cstr.
796 char path_str[KB(1)];
797 if (path.size >= KB(1) - 1) {
798 return (FileContents){
799 .path = path,
800 .err = FILE_ERR_PATH_TOO_BIG,
801 };
802 }
803 memcpy(path_str, path.mem, path.size);
804 path_str[path.size] = 0;
805
806 // Read the entire file into memory.
807 sz file_size = 0;
808 FILE *fp = fopen(path_str, "rb+");
809 if (!fp) {
810 return (FileContents){
811 .path = path,
812 .err = FILE_ERR_CANT_OPEN,
813 };
814 }
815 fseek(fp, 0, SEEK_END);
816 file_size = ftell(fp);
817 rewind(fp);
818 u8 *memory = arena_malloc(file_size, a);
819 sz read = fread(memory, 1, file_size, fp);
820 fclose(fp);
821 if (read == 0) {
822 return (FileContents){
823 .path = path,
824 .err = FILE_ERR_EMPTY,
825 };
826 }
827
828 return (FileContents){
829 .path = path,
830 .data = (Array){.mem = (u8 *)memory, .size = file_size},
831 .err = FILE_ERR_OK,
832 };
833}
834
835void *
836platform_calloc(sz size, void *ctx) {
837 (void)ctx;
838 return calloc(1, size);
839}
840
841void *
842platform_malloc(sz size, void *ctx) {
843 (void)ctx;
844 return malloc(size);
845}
846
847void *
848platform_realloc(void *ptr, sz old_size, sz new_size, void *ctx) {
849 (void)ctx;
850 (void)old_size;
851 (void)new_size;
852 return realloc(ptr, new_size);
853}
854
855void
856platform_free(void *ptr, void *ctx) {
857 (void)ctx;
858 free(ptr);
859}
860
861#include <time.h>
862#include <unistd.h>
863
864void
865platform_sleep(size_t microseconds) {
866 usleep(microseconds);
867}
868
869sz
870platform_time(void) {
871 struct timespec ts;
872 timespec_get(&ts, TIME_UTC);
873 return ts.tv_sec * 1000000000 + ts.tv_nsec;
874}
875
876#endif // BADLIB_H