jrk

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

jrk.h (40975B)


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