jrk

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

jrk.h (19999B)


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