jrk

my own c stdlib to keep myself sane
git clone git://git.jakekoroman.com/jrk
Log | Files | Refs

jrk.h (39946B)


      1 /*
      2  * TODO:
      3  *  - remove strnlen/strncmp from hm impl. should probably be using
      4  *    jrk_StringView's.
      5  *
      6  *  - add a log interface to give user control of logging.
      7  *    disable completely, log to file, log format, etc.
      8  *
      9  *  - add an arg parsing api.
     10  *
     11  *  - add real random api. and remove the rand() wrappers.
     12  *
     13  */
     14 
     15 #include <stdbool.h>
     16 #include <stdint.h>
     17 
     18 typedef int8_t i8;
     19 typedef int16_t i16;
     20 typedef int32_t i32;
     21 typedef int64_t i64;
     22 
     23 typedef uint8_t u8;
     24 typedef uint16_t u16;
     25 typedef uint32_t u32;
     26 typedef uint64_t u64;
     27 
     28 typedef float f32;
     29 typedef double f64;
     30 
     31 #define JRK_UNUSED(x) (void)x
     32 #define JRK_ARRLENGTH(arr) (sizeof(arr) / sizeof(arr[0]))
     33 #define JRK_MIN(a, b) ((a) < (b) ? (a) : (b))
     34 #define JRK_MAX(a, b) ((a) > (b) ? (a) : (b))
     35 
     36 #define jrk_return_defer(value) \
     37     do { result = value; goto defer; } while(0)
     38 
     39 #define JRK_KILOBYTES(x) ((u64)x*1024)
     40 #define JRK_MEGABYTES(x) ((u64)JRK_KILOBYTES((u64)x*1024))
     41 #define JRK_GIGABYTES(x) ((u64)JRK_MEGABYTES((u64)x*1024))
     42 #define JRK_TERABYTES(x) ((u64)JRK_GIGABYTES((u64)x*1024))
     43 
     44 #define JRK_TMPSTRINGS_ARR_CAPACITY 4
     45 #define JRK_TMPSTRINGS_STR_CAPACITY JRK_KILOBYTES(1)
     46 
     47 typedef struct {
     48 	u8 *data;
     49 	u64 offset;
     50 	u64 prev_offset;
     51 	u64 capacity;
     52 } jrk_Arena;
     53 
     54 typedef struct {
     55 	char *data;
     56 	u64 size;
     57 } jrk_String;
     58 
     59 void *jrk_ecalloc(u64, u64);
     60 void *jrk_erealloc(void*, u64);
     61 
     62 void *jrk_array_alloc_function_arena(u64, u64, void*);
     63 void *jrk_array_realloc_function_arena(void*, u64, u64, void*);
     64 
     65 jrk_Arena jrk_arena_create(u8*, u64);
     66 void *jrk_arena_push(jrk_Arena*, u64);
     67 char *jrk_arena_push_strf(jrk_Arena*, char*, ...);
     68 void jrk_arena_reset(jrk_Arena*);
     69 void *jrk_arena_resize(jrk_Arena*, void*, u64, u64);
     70 
     71 i32 jrk_rand_num(i32);
     72 i32 jrk_rand_num_range(i32, i32);
     73 
     74 i32 jrk_fd_open_read(char*);
     75 i32 jrk_fd_open_write(char*);
     76 i32 jrk_fd_open_write_append(char*);
     77 bool jrk_fd_size(i32, u64*);
     78 void jrk_fd_close(i32);
     79 
     80 jrk_String jrk_string_from_parts(char*, u64);
     81 jrk_String jrk_string_trim_right(jrk_String);
     82 jrk_String jrk_string_trim_left(jrk_String);
     83 jrk_String jrk_string_trim(jrk_String);
     84 jrk_String jrk_string_from_cstr(char*);
     85 jrk_String jrk_string_chop_delim(jrk_String*, char delim);
     86 bool jrk_string_equals(jrk_String*, jrk_String*);       // takes the lowest size and matches up to that size
     87 bool jrk_string_equals_exact(jrk_String*, jrk_String*); // must be same size to be equals
     88 
     89 char *jrk_tmpstrings_push(char*);
     90 char *jrk_tmpstrings_pushf(char*, ...);
     91 
     92 /* XXX: im not thrilled with this api, the memory can get messy real fast */
     93 #define jrk_string_chop_delim_loop(str, it, delim) \
     94     for (jrk_String it = jrk_string_chop_delim(str, delim); it.size != 0; it = jrk_string_chop_delim(str, delim))
     95 
     96 #ifndef jrk_die
     97   #define jrk_die(x)                                                   \
     98       do {                                                             \
     99           fprintf(stderr, "%s:%d: error: "x" \n", __FILE__, __LINE__); \
    100           exit(69);                                                    \
    101       } while (0)
    102 #endif
    103 
    104 #ifndef jrk_diev
    105   #define jrk_diev(x, ...)                                                         \
    106       do {                                                                         \
    107           fprintf(stderr, "%s:%d: error: "x"\n", __FILE__, __LINE__, __VA_ARGS__); \
    108           exit(69);                                                                \
    109       } while (0)
    110 #endif
    111 
    112 #define jrk_edie(x) jrk_diev(x": %s", strerror(errno))
    113 #define jrk_ediev(x, ...) jrk_diev(x": %s", __VA_ARGS__, strerror(errno))
    114 
    115 #ifndef jrk_log
    116   #define jrk_log(x)                    \
    117     do {                                \
    118         fprintf(stderr, "info: "x"\n"); \
    119     } while (0)
    120 #endif
    121 
    122 #ifndef jrk_logv
    123   #define jrk_logv(x, ...)                            \
    124     do {                                              \
    125         fprintf(stderr, "info: "x"\n",  __VA_ARGS__); \
    126     } while (0)
    127 #endif
    128 
    129 #ifndef jrk_elog
    130   #define jrk_elog(x) jrk_log(x": %s", strerror(errno))
    131 #endif
    132 
    133 #ifndef jrk_elogv
    134   #define jrk_elogv(x, ...) jrk_logv(x": %s", __VA_ARGS__, strerror(errno))
    135 #endif
    136 
    137 #ifndef jrk_error
    138   #define jrk_error(x)                   \
    139     do {                                 \
    140         fprintf(stderr, "error: "x"\n"); \
    141     } while (0)
    142 #endif
    143 
    144 #ifndef jrk_errorv
    145   #define jrk_errorv(x, ...)                           \
    146     do {                                               \
    147         fprintf(stderr, "error: "x"\n",  __VA_ARGS__); \
    148     } while (0)
    149 #endif
    150 
    151 #ifndef jrk_eerror
    152   #define jrk_eerror(x) jrk_errorv(x": %s", strerror(errno))
    153 #endif
    154 
    155 #ifndef jrk_eerrorv
    156   #define jrk_eerrorv(x, ...) jrk_errorv(x": %s", __VA_ARGS__, strerror(errno))
    157 #endif
    158 
    159 #define jrk_assert(c, msg) do { if (!(c)) jrk_die("jrk_assert: "msg); } while(0)
    160 #define jrk_assertv(c, msg, ...) do { if (!(c)) jrk_diev("jrk_assert: "msg, __VA_ARGS__); } while(0)
    161 
    162 #define jrk_shift(x, n) ((n)--, *(x)++)
    163 #define jrk_shift_loop(x, n, it) for (char *it = jrk_shift(x, n); n >= 0; it = jrk_shift(x, n))
    164 
    165 #define jrk_emalloc(n) jrk_ecalloc(1, n)
    166 
    167 #define JRK_ARRAY_DEFAULT_INIT_CAPACITY 16
    168 
    169 #ifndef JRK_ARRAY_DEFAULT_ALLOC_FN
    170     #define JRK_ARRAY_DEFAULT_ALLOC_FN jrk_ecalloc
    171 #endif
    172 
    173 #ifndef JRK_ARRAY_DEFAULT_REALLOC_FN
    174     #define JRK_ARRAY_DEFAULT_REALLOC_FN jrk_erealloc
    175 #endif
    176 
    177 #ifndef JRK_ARRAY_DEFAULT_FREE_FN
    178     #define JRK_ARRAY_DEFAULT_FREE_FN free
    179 #endif
    180 
    181 typedef void *(*jrk_array_alloc_function_t) (u64, u64, void*);
    182 typedef void *(*jrk_array_realloc_function_t) (void*, u64, u64, void*);
    183 
    184 #define __jrk_array_alloc(arr, count, size) (arr)->allocfn ? (arr)->allocfn((count), (size), (arr)->allocfn_user) : JRK_ARRAY_DEFAULT_ALLOC_FN((count), (size))
    185 #define __jrk_array_realloc(arr, _size) (arr)->reallocfn ? (arr)->reallocfn((arr)->items, (arr)->size * sizeof((arr)->items[0]), (_size), (arr)->allocfn_user) : JRK_ARRAY_DEFAULT_REALLOC_FN((arr)->items, (_size))
    186 
    187 #define jrk_array_prototype(type)                                                                                             \
    188     typedef struct {                                                                                                          \
    189         type *items;                                                                                                          \
    190         u64 size;                                                                                                             \
    191         u64 capacity;                                                                                                         \
    192         jrk_array_alloc_function_t allocfn;                                                                                   \
    193         jrk_array_realloc_function_t reallocfn;                                                                               \
    194         void *allocfn_user;                                                                                                   \
    195     } jrk_Array_##type;                                                                                                       \
    196                                                                                                                               \
    197     bool jrk_array_##type##_init_ex(jrk_Array_##type*, u64, jrk_array_alloc_function_t, jrk_array_realloc_function_t, void*); \
    198     bool jrk_array_##type##_init(jrk_Array_##type*, u64);                                                                     \
    199     void jrk_array_##type##_deinit(jrk_Array_##type*);                                                                        \
    200     bool jrk_array_##type##_setcap(jrk_Array_##type*, u64);                                                                   \
    201     bool jrk_array_##type##_push(jrk_Array_##type*, type);                                                                    \
    202     bool jrk_array_##type##_pushn(jrk_Array_##type*, type*, u64)
    203 
    204 #define jrk_array_impl(type)                                                                                                                                             \
    205     bool jrk_array_##type##_init_ex(jrk_Array_##type *arr, u64 capacity, jrk_array_alloc_function_t allocfn, jrk_array_realloc_function_t reallocfn, void *allocfn_user) \
    206     {                                                                                                                                                                    \
    207         (arr)->allocfn = (allocfn) ? (allocfn) : NULL;                                                                                                                   \
    208         (arr)->reallocfn = (reallocfn) ? (reallocfn) : NULL;                                                                                                             \
    209         (arr)->allocfn_user = (allocfn_user) ? (allocfn_user) : NULL;                                                                                                    \
    210         (arr)->size = 0;                                                                                                                                                 \
    211         (arr)->capacity = (capacity);                                                                                                                                    \
    212         (arr)->items = __jrk_array_alloc((arr), (arr)->capacity, sizeof(type));                                                                                          \
    213         if (!(arr)->items) return false;                                                                                                                                 \
    214         memset((arr)->items, 0, (arr)->capacity * sizeof(type));                                                                                                         \
    215         return true;                                                                                                                                                     \
    216     }                                                                                                                                                                    \
    217                                                                                                                                                                          \
    218     bool jrk_array_##type##_init(jrk_Array_##type *arr, u64 capacity)                                                                                                    \
    219     {                                                                                                                                                                    \
    220         return jrk_array_##type##_init_ex(arr, capacity, NULL, NULL, NULL);                                                                                              \
    221     }                                                                                                                                                                    \
    222                                                                                                                                                                          \
    223     void jrk_array_##type##_deinit(jrk_Array_##type *arr)                                                                                                                \
    224     {                                                                                                                                                                    \
    225         if ((arr)->items && !(arr)->allocfn)                                                                                                                             \
    226             JRK_ARRAY_DEFAULT_FREE_FN((arr)->items);                                                                                                                     \
    227     }                                                                                                                                                                    \
    228                                                                                                                                                                          \
    229     bool jrk_array_##type##_setcap(jrk_Array_##type *arr, u64 new_capacity)                                                                                              \
    230     {                                                                                                                                                                    \
    231         if (new_capacity < (arr)->capacity) return false;                                                                                                                \
    232         (arr)->items = __jrk_array_realloc((arr), new_capacity * sizeof(type));                                                                                          \
    233         if (!(arr)->items) return false;                                                                                                                                 \
    234         memset((arr)->items + (arr)->size, 0, (new_capacity * sizeof(type)) - ((arr)->capacity * sizeof(type)));                                                         \
    235         (arr)->capacity = new_capacity;                                                                                                                                  \
    236         return true;                                                                                                                                                     \
    237     }                                                                                                                                                                    \
    238                                                                                                                                                                          \
    239     bool jrk_array_##type##_push(jrk_Array_##type *arr, type val)                                                                                                        \
    240     {                                                                                                                                                                    \
    241         if ((arr)->size + 1 > (arr)->capacity) {                                                                                                                         \
    242             while ((arr)->size + 1 > ((arr)->capacity))                                                                                                                  \
    243                 (arr)->capacity = (arr->capacity) ? (arr)->capacity * 2 : JRK_ARRAY_DEFAULT_INIT_CAPACITY;                                                               \
    244             (arr)->items = __jrk_array_realloc((arr), (arr)->capacity * sizeof(type));                                                                                   \
    245             if (!(arr)->items) return false;                                                                                                                             \
    246         }                                                                                                                                                                \
    247         (arr)->items[(arr)->size++] = (val);                                                                                                                             \
    248         return true;                                                                                                                                                     \
    249     }                                                                                                                                                                    \
    250                                                                                                                                                                          \
    251     bool jrk_array_##type##_pushn(jrk_Array_##type *arr, type *vals, u64 count)                                                                                          \
    252     {                                                                                                                                                                    \
    253         if ((arr)->size + count > (arr)->capacity) {                                                                                                                     \
    254             while ((arr)->size + count > ((arr)->capacity))                                                                                                              \
    255                 (arr)->capacity = (arr->capacity) ? (arr)->capacity * 2 : JRK_ARRAY_DEFAULT_INIT_CAPACITY;                                                               \
    256             (arr)->items = __jrk_array_realloc((arr), (arr)->capacity * sizeof(type));                                                                                   \
    257             if (!(arr)->items) return false;                                                                                                                             \
    258             memset((arr)->items + (arr)->size, 0, count * sizeof(type));                                                                                                 \
    259         }                                                                                                                                                                \
    260         memcpy(&(arr)->items[(arr)->size], (vals), sizeof(type) * (count));                                                                                              \
    261         (arr)->size += count;                                                                                                                                            \
    262         return true;                                                                                                                                                     \
    263     }
    264 
    265 #define jrk_array_foreach(type, it, arr) for (type *it = (arr)->items; it < (arr)->items + (arr)->size; ++it)
    266 
    267 jrk_array_prototype(char);
    268 typedef jrk_Array_char jrk_StringBuilder;
    269 
    270 #define jrk_sb_append_null(sb) jrk_array_char_push((sb), 0)
    271 #define jrk_sb_append_cstr(sb, str) jrk_sb_appendf((sb), (str))
    272 #define jrk_sb_append_buf(sb, buf, bufsz) jrk_array_char_pushn((sb), (buf), (bufsz))
    273 #define jrk_sb_init_ex(sb, size, allocfn, reallocfn, userarg) jrk_array_char_init_ex((sb), (size), (allocfn), (reallocfn), (userarg))
    274 #define jrk_sb_init_arena(sb, size, arena) jrk_sb_init_ex((sb), (size), jrk_array_alloc_function_arena, jrk_array_realloc_function_arena, (void *)(arena))
    275 #define jrk_sb_deinit(sb) jrk_array_char_deinit((sb))
    276 #define jrk_sb_to_string(sb) jrk_string_from_parts((sb).items, (sb).size)
    277 
    278 bool jrk_sb_appendf(jrk_StringBuilder*, char*, ...);
    279 bool jrk_sb_append_buf_at(jrk_StringBuilder*, char*, u64, u64);
    280 bool jrk_sb_fd_write(jrk_StringBuilder*, i32);
    281 bool jrk_sb_write_entire_file(jrk_StringBuilder *, char *);
    282 bool jrk_sb_fd_read_all(jrk_StringBuilder*, i32);
    283 bool jrk_sb_read_entire_file(jrk_StringBuilder*, char*);
    284 
    285 // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
    286 // for 64 bit hash
    287 #define JRK_FNV1A_64_OFFSET_BASIS 0xCBF29CE484222325
    288 #define JRK_FNV1A_64_PRIME        0x100000001B3
    289 u64 jrk_fnv1a_64(u8*, u64);
    290 
    291 #define jrk_hm_prototype(type, max_key_size)                                                          \
    292     typedef struct {                                                                                  \
    293         char key[(max_key_size)];                                                                     \
    294         type val;                                                                                     \
    295     } jrk_HashMapItem_##type;                                                                         \
    296                                                                                                       \
    297     typedef struct {                                                                                  \
    298         jrk_HashMapItem_##type *items;                                                                \
    299         u64 capacity;                                                                                 \
    300     } jrk_HashMap_##type;                                                                             \
    301                                                                                                       \
    302     bool jrk_hm_##type##_init(jrk_HashMap_##type *map, jrk_HashMapItem_##type *items, u64 items_cap); \
    303     bool jrk_hm_##type##_push(jrk_HashMap_##type *map, char *key, type val);                          \
    304     bool jrk_hm_##type##_get(jrk_HashMap_##type *map, char *key, type *outval);
    305 
    306 #define jrk_hm_impl(type)                                                                                               \
    307     bool                                                                                                                \
    308     jrk_hm_##type##_init(jrk_HashMap_##type *map, jrk_HashMapItem_##type *items, u64 items_cap)                         \
    309     {                                                                                                                   \
    310         if (!map) {                                                                                                     \
    311             fprintf(stderr, "error: failed to init hashmap: map pointer is NULL\n");                                    \
    312             return false;                                                                                               \
    313         }                                                                                                               \
    314         if (!items) {                                                                                                   \
    315             fprintf(stderr, "error: failed to init hashmap: buf pointer is NULL\n");                                    \
    316             return false;                                                                                               \
    317         }                                                                                                               \
    318         map->items = items;                                                                                             \
    319         map->capacity = items_cap;                                                                                      \
    320         return true;                                                                                                    \
    321     }                                                                                                                   \
    322                                                                                                                         \
    323     bool                                                                                                                \
    324     jrk_hm_##type##_push(jrk_HashMap_##type *map, char *key, type val)                                                  \
    325     {                                                                                                                   \
    326         if (!key) {                                                                                                     \
    327             fprintf(stderr, "error: failed to push key into hashmap: key pointer is NULL\n");                           \
    328             return false;                                                                                               \
    329         }                                                                                                               \
    330         if (!map) {                                                                                                     \
    331             fprintf(stderr, "error: failed to push key '%s' into hashmap: map pointer is NULL\n", key);                 \
    332             return false;                                                                                               \
    333         }                                                                                                               \
    334         u64 keylen = sizeof(map->items->key);                                                                           \
    335         u64 idx = jrk_fnv1a_64((u8 *) key, strnlen(key, keylen)) % map->capacity;                                       \
    336         jrk_HashMapItem_##type *item = &map->items[idx];                                                                \
    337         if (item->key[0] != 0 && 0 != strncmp(item->key, key, sizeof(map->items->key)))                                 \
    338             printf("%s collision with %s\n", key, item->key);                                                           \
    339         for (; item < &map->items[map->capacity] && item->key[0] != 0 && 0 != strncmp(item->key, key, keylen); ++item); \
    340         if (item == &map->items[map->capacity]) {                                                                       \
    341             for (item = &map->items[0]; item < &map->items[idx] && item->key[0] != 0; ++item);                          \
    342             if (item == &map->items[idx]) {                                                                             \
    343                 fprintf(stderr, "error: no space found for key '%s': hashmap is full\n", key);                          \
    344                 return false;                                                                                           \
    345             }                                                                                                           \
    346         }                                                                                                               \
    347         memcpy(item->key, key, strlen(key));                                                                            \
    348         item->val = val;                                                                                                \
    349         return true;                                                                                                    \
    350     }                                                                                                                   \
    351                                                                                                                         \
    352     bool                                                                                                                \
    353     jrk_hm_##type##_get(jrk_HashMap_##type *map, char *key, type *outval)                                               \
    354     {                                                                                                                   \
    355         if (!key) {                                                                                                     \
    356             fprintf(stderr, "error: failed to get key from hashmap: key pointer is NULL\n");                            \
    357             return false;                                                                                               \
    358         }                                                                                                               \
    359         if (!map) {                                                                                                     \
    360             fprintf(stderr, "error: failed to get key '%s' from hashmap: map pointer is NULL\n", key);                  \
    361             return false;                                                                                               \
    362         }                                                                                                               \
    363         if (!outval) {                                                                                                  \
    364             fprintf(stderr, "error: failed to get key '%s' from hashmap: outval pointer is NULL\n", key);               \
    365             return false;                                                                                               \
    366         }                                                                                                               \
    367         u64 keylen = sizeof(map->items->key);                                                                           \
    368         u64 idx = jrk_fnv1a_64((u8 *) key, strnlen(key, keylen)) % map->capacity;                                       \
    369         jrk_HashMapItem_##type *item = &map->items[idx];                                                                \
    370         if (0 == strncmp(item->key, key, keylen)) {                                                                     \
    371             *outval = item->val;                                                                                        \
    372             return true;                                                                                                \
    373         }                                                                                                               \
    374         for (; item < &map->items[map->capacity] && 0 != strncmp(item->key, key, keylen); ++item)                       \
    375             if (item->key[0] == 0)                                                                                      \
    376                 return false;                                                                                           \
    377         if (item == &map->items[map->capacity]) {                                                                       \
    378             for (item = &map->items[0]; item < &map->items[idx] && 0 != strncmp(item->key, key, keylen); ++item);       \
    379             if (item == &map->items[idx])                                                                               \
    380                 return false;                                                                                           \
    381         }                                                                                                               \
    382         *outval = item->val;                                                                                            \
    383         return true;                                                                                                    \
    384     }
    385 
    386 #ifdef JRK_IMPLEMENTATION
    387 #include <ctype.h>
    388 #include <errno.h>
    389 #include <fcntl.h>
    390 #include <stdarg.h>
    391 #include <stdio.h>
    392 #include <stdlib.h>
    393 #include <string.h>
    394 #include <sys/stat.h>
    395 #include <unistd.h>
    396 
    397 // NOTE: for jrk_StringBuilder
    398 jrk_array_impl(char)
    399 
    400 void *
    401 jrk_array_alloc_function_arena(u64 size, u64 count, void *user)
    402 {
    403 	void *result = NULL;
    404 	jrk_Arena *arena = (jrk_Arena *) user;
    405 	result = jrk_arena_push(arena, size * count);
    406 	return result;
    407 }
    408 
    409 void *
    410 jrk_array_realloc_function_arena(void *ptr, u64 old_size, u64 new_size, void *user)
    411 {
    412 	void *result = NULL;
    413 	jrk_Arena *arena = (jrk_Arena *) user;
    414 	result = jrk_arena_resize(arena, ptr, old_size, new_size);
    415 	return result;
    416 }
    417 
    418 bool
    419 jrk_sb_appendf(jrk_StringBuilder *sb, char *fmt, ...)
    420 {
    421 	char buf[JRK_KILOBYTES(1)];
    422 	va_list args;
    423 	va_start(args, fmt);
    424 
    425 	i32 buf_sz = vsnprintf(buf, sizeof(buf), fmt, args);
    426 	if (buf_sz < 0) {
    427 		jrk_eerrorv("jrk_sb_appendf(%p, %s): failed to create full string from '%s'", (void *) sb, fmt, fmt);
    428 		return false;
    429 	}
    430 	va_end(args);
    431 
    432 	i32 actual_sz = 0;
    433 	if ((u32) buf_sz > JRK_ARRLENGTH(buf)) {
    434 		actual_sz = JRK_ARRLENGTH(buf);
    435 		jrk_errorv("jrk_sb_appendf(%p, %s): pushing '%s' into sb caused truncation of %ld bytes",
    436 		           (void *) sb, fmt, fmt, buf_sz - JRK_ARRLENGTH(buf));
    437 		return false;
    438 	} else {
    439 		actual_sz = buf_sz;
    440 	}
    441 
    442 	if (!jrk_array_char_pushn(sb, buf, actual_sz)) {
    443 		jrk_errorv("jrk_sb_appendf(%p, %s): failed to push '%s' into sb", (void *) sb, fmt, fmt);
    444 		return false;
    445 	}
    446 
    447 	return true;
    448 }
    449 
    450 bool
    451 jrk_sb_append_buf_at(jrk_StringBuilder *sb, char *buf, u64 buf_sz, u64 idx)
    452 {
    453 	if (idx > sb->size) {
    454 		jrk_errorv("jrk_sb_append_buf_at(%p, %s, %ld, %ld): idx is greater than sb.size",
    455 		           (void *)sb, buf, buf_sz, idx);
    456 		return false;
    457 	}
    458 
    459 	if (sb->size + (buf_sz) > sb->capacity) {
    460 		while (sb->size + (buf_sz) > sb->capacity) {
    461 			sb->capacity *= 2;
    462 		}
    463 		sb->items = __jrk_array_realloc(sb, sb->capacity);
    464 		if (!sb->items) return false;
    465 		memset(sb->items + sb->size, 0, sb->capacity - sb->size);
    466 	}
    467 
    468 	memmove(sb->items + idx + buf_sz, sb->items + idx, sb->size - idx);
    469 	memcpy(sb->items + idx, buf, buf_sz);
    470 
    471 	sb->size += buf_sz;
    472 	return true;
    473 }
    474 
    475 bool
    476 jrk_sb_fd_read_all(jrk_StringBuilder *sb, i32 fd)
    477 {
    478 	bool result = true;
    479 	u64 filesize = 0;
    480 	if (!jrk_fd_size(fd, &filesize)) jrk_return_defer(false);
    481 	char *buf = jrk_emalloc(filesize);
    482 	if (read(fd, buf, filesize) < 0) {
    483 		jrk_eerrorv("jrk_sb_fd_read_all(%p, %d)", (void *)sb, fd);
    484 		jrk_return_defer(false);
    485 	}
    486 
    487 	if (!jrk_sb_append_buf(sb, buf, filesize)) jrk_return_defer(false);
    488 defer:
    489 	free(buf);
    490 	return result;
    491 }
    492 
    493 bool
    494 jrk_sb_fd_write(jrk_StringBuilder *sb, i32 fd)
    495 {
    496 	i64 result;
    497 	result = write(fd, (void *) sb->items, sb->size);
    498 	if (result < 0) {
    499 		jrk_eerrorv("jrk_sb_fd_write_all(%p, %d)", (void *)sb, fd);
    500 		return -1;
    501 	}
    502 
    503 	return result;
    504 }
    505 
    506 bool
    507 jrk_sb_read_entire_file(jrk_StringBuilder *sb, char *filename)
    508 {
    509 	bool result = true;
    510 	i32 fd = jrk_fd_open_read(filename);
    511 	if (fd < 0) return false;
    512 	if (!jrk_sb_fd_read_all(sb, fd)) jrk_return_defer(false);
    513 
    514 defer:
    515 	jrk_fd_close(fd);
    516 	return result;
    517 }
    518 
    519 bool
    520 jrk_sb_write_entire_file(jrk_StringBuilder *sb, char *filename)
    521 {
    522 	bool result = true;
    523 	i32 fd = jrk_fd_open_write(filename);
    524 	if (fd < 0) return false;
    525 	if (!jrk_sb_fd_write(sb, fd)) jrk_return_defer(false);
    526 
    527 defer:
    528 	jrk_fd_close(fd);
    529 	return result;
    530 }
    531 
    532 void *
    533 jrk_ecalloc(u64 nmemb, u64 size)
    534 {
    535 	void *p;
    536 
    537 	if (!(p = calloc(nmemb, size)))
    538 		jrk_ediev("jrk_ecalloc(%ld, %ld): buy more ram lol", nmemb, size);
    539 	return p;
    540 }
    541 
    542 void *
    543 jrk_erealloc(void *ptr, u64 size)
    544 {
    545 	void *p;
    546 
    547 	if (!(p = realloc(ptr, size)))
    548 		jrk_ediev("jrk_erealloc(%p, %ld): buy more ram lol", ptr, size);
    549 	return p;
    550 }
    551 
    552 // NOTE: only allocate space for translation units with JRK_IMPLEMENTATION
    553 static char jrk__tmpstrings[JRK_TMPSTRINGS_ARR_CAPACITY][JRK_TMPSTRINGS_STR_CAPACITY];
    554 static u32 jrk__tmpstrings_idx = 0;
    555 
    556 char *
    557 jrk_tmpstrings_push(char *str)
    558 {
    559 	char *result;
    560 	result = jrk_tmpstrings_pushf(str);
    561 	return result;
    562 }
    563 
    564 char *
    565 jrk_tmpstrings_pushf(char *fmt, ...)
    566 {
    567 	char *result = jrk__tmpstrings[jrk__tmpstrings_idx];
    568 
    569 	va_list args;
    570 	va_start(args, fmt);
    571 	vsnprintf(result, JRK_TMPSTRINGS_STR_CAPACITY, fmt, args);
    572 	va_end(args);
    573 
    574 	if (++jrk__tmpstrings_idx >= JRK_TMPSTRINGS_ARR_CAPACITY)
    575 		jrk__tmpstrings_idx = 0;
    576 
    577 	return result;
    578 }
    579 
    580 jrk_Arena
    581 jrk_arena_create(u8 *buffer, u64 buffer_count)
    582 {
    583 	jrk_Arena result = {0};
    584 	result.data = buffer;
    585 	result.capacity = buffer_count;
    586 	result.offset = 0;
    587 	result.prev_offset = 0;
    588 	return result;
    589 }
    590 
    591 void *
    592 jrk_arena_push(jrk_Arena *arena, u64 n)
    593 {
    594 	if (arena->offset + n > arena->capacity) {
    595 		jrk_errorv("jrk_arena_push(%p, %ld): arena push requires %ld bytes but has a capacity of %ld bytes",
    596 		           (void *) arena, n, arena->offset + n, arena->capacity);
    597 		return NULL;
    598 	}
    599 
    600 	void *result = &arena->data[arena->offset];
    601 	arena->prev_offset = arena->offset;
    602 	arena->offset += n;
    603 	memset(result, 0, n);
    604 
    605 	return result;
    606 }
    607 
    608 char *
    609 jrk_arena_push_strf(jrk_Arena *arena, char *fmt, ...)
    610 {
    611 	char *result = NULL;
    612 
    613 	va_list args;
    614 	va_start(args, fmt);
    615 	i32 n = vsnprintf(NULL, 0, fmt, args);
    616 	va_end(args);
    617 
    618 	result = jrk_arena_push(arena, (u64) n + 1);
    619 	if (!result) return NULL;
    620 
    621 	va_start(args, fmt);
    622 	vsnprintf(result, n + 1, fmt, args);
    623 	va_end(args);
    624 
    625 	return result;
    626 }
    627 
    628 void *
    629 jrk_arena_resize(jrk_Arena *arena, void *old, u64 old_size, u64 new_size)
    630 {
    631 	u8 *result = NULL;
    632 
    633 	if (new_size < old_size) {
    634 		jrk_errorv("jrk_arena_resize(%p, %p, %ld, %ld): new_size is smaller than the old_size",
    635 		           (void *) arena, old, old_size, new_size);
    636 		return result;
    637 	}
    638 
    639 	if (arena->offset + (new_size - old_size) > arena->capacity) {
    640 		jrk_errorv("jrk_arena_resize(%p, %p, %ld, %ld): arena resize requires %ld bytes but has a capacity of %ld bytes",
    641 		           (void *) arena, old, old_size, new_size, arena->offset + (new_size - old_size), arena->capacity);
    642 		return result;
    643 	}
    644 
    645 	if (old == &arena->data[arena->prev_offset]) {
    646 		result = old;
    647 		arena->prev_offset = arena->offset;
    648 		arena->offset += new_size;
    649 		memset(&arena->data[arena->prev_offset], 0, new_size - old_size);
    650 	} else {
    651 		result = &arena->data[arena->offset];
    652 		arena->prev_offset = arena->offset;
    653 		arena->offset += new_size;
    654 		if (arena->offset > arena->capacity) {
    655 			jrk_errorv("jrk_arena_resize(%p, %p, %ld, %ld): arena resize requires %ld bytes but has a capacity of %ld bytes",
    656 			           (void *) arena, old, old_size, new_size, arena->offset, arena->capacity);
    657 			return NULL;
    658 		}
    659 		memmove(result, old, old_size);
    660 		memset(result + old_size, 0, new_size - old_size);
    661 	}
    662 
    663 	return (void *) result;
    664 }
    665 
    666 void
    667 jrk_arena_reset(jrk_Arena *arena)
    668 {
    669 	arena->offset = 0;
    670 	arena->prev_offset = 0;
    671 	memset(arena->data, 0, arena->capacity);
    672 }
    673 
    674 bool
    675 jrk_fd_size(i32 fd, u64 *size)
    676 {
    677 	if (!size) {
    678 		jrk_errorv("jrk_fd_size(%d, %p): size ptr is NULL", fd, (void *) size);
    679 		return false;
    680 	}
    681 
    682 	struct stat statbuf = {0};
    683 	if (fstat(fd, &statbuf) < 0) {
    684 		jrk_eerrorv("jrk_fd_size(%d, %p)", fd, (void *) size);
    685 		return false;
    686 	}
    687 
    688 	*size = statbuf.st_size;
    689 	return true;
    690 }
    691 
    692 void
    693 jrk_fd_close(i32 fd)
    694 {
    695 	close(fd);
    696 }
    697 
    698 i32
    699 jrk_fd_open_read(char *path)
    700 {
    701 	i32 result = open(path, O_RDONLY);
    702 
    703 	if (result < 0) {
    704 		jrk_eerrorv("jrk_fd_open_read(%s)", path);
    705 		return -1;
    706 	}
    707 
    708 	return result;
    709 }
    710 
    711 i32
    712 jrk_fd_open_write(char *path)
    713 {
    714 	i32 result = open(path,
    715 	                  O_WRONLY | O_CREAT | O_TRUNC,
    716 	                  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    717 
    718 	if (result < 0) {
    719 		jrk_eerrorv("jrk_fd_open_write(%s)", path);
    720 		return -1;
    721 	}
    722 
    723 	return result;
    724 }
    725 
    726 i32
    727 jrk_fd_open_write_append(char *path)
    728 {
    729 	i32 result = open(path,
    730 	                  O_WRONLY | O_CREAT | O_APPEND,
    731 	                  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    732 
    733 	if (result < 0) {
    734 		jrk_eerrorv("jrk_fd_open_write_append(%s)", path);
    735 		return -1;
    736 	}
    737 
    738 	return result;
    739 }
    740 
    741 jrk_String
    742 jrk_string_from_parts(char *data, u64 size)
    743 {
    744 	jrk_String result = {0};
    745 	result.data = data;
    746 	result.size = size;
    747 	return result;
    748 }
    749 
    750 jrk_String
    751 jrk_string_from_cstr(char *data)
    752 {
    753 	jrk_String result = {0};
    754 	result.data = data;
    755 	result.size = strlen(data);
    756 	return result;
    757 }
    758 
    759 jrk_String
    760 jrk_string_trim_right(jrk_String str)
    761 {
    762 	u64 i = 0;
    763 	for (; i < str.size && isspace(str.data[str.size - 1 - i]); ++i);
    764 	return jrk_string_from_parts(str.data, str.size - i);
    765 }
    766 
    767 jrk_String
    768 jrk_string_trim_left(jrk_String str)
    769 {
    770 	u64 i = 0;
    771 	for (; i < str.size && isspace(str.data[i]); ++i);
    772 	return jrk_string_from_parts(str.data + i, str.size - i);
    773 }
    774 
    775 jrk_String
    776 jrk_string_trim(jrk_String str)
    777 {
    778 	return jrk_string_trim_right(jrk_string_trim_left(str));
    779 }
    780 
    781 jrk_String
    782 jrk_string_chop_delim(jrk_String *str, char delim)
    783 {
    784 	u64 i = 0;
    785 	while (i < str->size && str->data[i] != delim)
    786 		++i;
    787 
    788 	jrk_String result = jrk_string_from_parts(str->data, i);
    789 
    790 	if (i < str->size) {
    791 		str->data += i + 1;
    792 		str->size -= i + 1;
    793 	} else {
    794 		str->data += i;
    795 		str->size -= i;
    796 	}
    797 
    798 	return result;
    799 }
    800 
    801 bool
    802 jrk_string_equals(jrk_String *a, jrk_String *b)
    803 {
    804 	for (u64 i = 0; i < JRK_MIN(a->size, b->size); ++i)
    805 		if (a->data[i] != b->data[i]) return false;
    806 
    807 	return true;
    808 }
    809 
    810 bool
    811 jrk_string_equals_exact(jrk_String *a, jrk_String *b)
    812 {
    813 	if (a->size != b->size) return false;
    814 
    815 	for (u64 i = 0; i < a->size; ++i)
    816 		if (a->data[i] != b->data[i]) return false;
    817 
    818 	return true;
    819 }
    820 
    821 u64 jrk_fnv1a_64(u8 *data, u64 size)
    822 {
    823 	u64 result = JRK_FNV1A_64_OFFSET_BASIS;
    824 	for (u64 i = 0; i < size; ++i) {
    825 		result ^= data[i];
    826 		result *= JRK_FNV1A_64_PRIME;
    827 	}
    828 	return result;
    829 }
    830 
    831 i32
    832 jrk_rand_num(i32 upbound)
    833 {
    834 	return rand() % upbound + 1;
    835 }
    836 
    837 i32
    838 jrk_rand_num_range(i32 min, i32 max)
    839 {
    840 	return rand() % (max - min + 1) + min;
    841 }
    842 
    843 #endif // JRK_IMPLEMENTATION