jrk

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

jrk.h (14831B)


      1 /*
      2  * TODO:
      3  *   - application shouldn't be dying on all failures, have a way
      4  *     to configure that ... just die without calling exit()
      5  *   - look at at the jrk_sv_chop_delim_loop stuff. there must
      6  *     must be a better way of handling things.
      7  */
      8 
      9 #include <stdint.h>
     10 
     11 #ifdef JRK_IMPLEMENTATION_WITH_SHORTNAMES
     12   #define JRK_IMPLEMENTATION
     13   #define JRK_SHORTNAMES
     14 #endif // JRK_IMPLEMENTATION_WITH_SHORTNAMES
     15 
     16 typedef int8_t i8;
     17 typedef int16_t i16;
     18 typedef int32_t i32;
     19 typedef int64_t i64;
     20 
     21 typedef uint8_t u8;
     22 typedef uint16_t u16;
     23 typedef uint32_t u32;
     24 typedef uint64_t u64;
     25 
     26 typedef float f32;
     27 typedef double f64;
     28 
     29 #define JRK_UNUSED(x) (void)x
     30 #define JRK_ARRSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
     31 
     32 #define JRK_TMPSTRINGS_ARR_CAPACITY 4
     33 #define JRK_TMPSTRINGS_STR_CAPACITY 1024
     34 
     35 typedef struct {
     36     u8 *data;
     37     u64 count;
     38     u64 capacity;
     39 } jrk_Arena;
     40 
     41 typedef struct {
     42     char *items;
     43     u64 count;
     44     u64 capacity;
     45 } jrk_StringBuilder;
     46 
     47 typedef struct {
     48     char *data;
     49     u64 count;
     50 } jrk_StringView;
     51 
     52 void *jrk_ecalloc(u64, u64);
     53 void *jrk_erealloc(void*, u64);
     54 
     55 jrk_Arena jrk_arena_create(u64);
     56 void *jrk__arena_push(jrk_Arena*, u64);
     57 
     58 i32 jrk_rand_num(i32);
     59 i32 jrk_rand_num_range(i32, i32);
     60 
     61 i32 jrk_fd_open_read(char*);
     62 i32 jrk_fd_open_write(char*);
     63 i32 jrk_fd_open_write_append(char*);
     64 u64 jrk_fd_size(i32);
     65 void jrk_fd_close(i32);
     66 
     67 i32 jrk_sb_appendf(jrk_StringBuilder*, const char*, ...);
     68 void jrk_sb_fd_read_all(jrk_StringBuilder*, i32);
     69 u64 jrk_sb_fd_write_all(jrk_StringBuilder*, i32);
     70 void jrk_sb_write_file(jrk_StringBuilder*, char*);
     71 void jrk_sb_read_entire_file(jrk_StringBuilder*, char*);
     72 void jrk_sb_append_buf_at(jrk_StringBuilder*, char*, u64, u64);
     73 
     74 jrk_StringView jrk_sv_from_parts(char*, u64);
     75 jrk_StringView jrk_sv_trim_right(jrk_StringView);
     76 jrk_StringView jrk_sv_trim_left(jrk_StringView);
     77 jrk_StringView jrk_sv_trim(jrk_StringView);
     78 jrk_StringView jrk_sv_from_cstr(char*);
     79 jrk_StringView jrk_sv_chop_delim(jrk_StringView*, char delim);
     80 
     81 char *jrk_tmpstrings_push(char *);
     82 char *jrk_tmpstrings_pushf(char *, ...);
     83 
     84 /* XXX: im not thrilled with this api, the memory can get messy real fast */
     85 #define jrk_sv_chop_delim_loop(sv, it, delim) \
     86     for (jrk_StringView it = jrk_sv_chop_delim(sv, delim); it.count != 0; it = jrk_sv_chop_delim(sv, delim))
     87 
     88 /* NOTE: no shortname as 'assert' is just too generic */
     89 #define jrk_assert(c, msg) do { if (!(c)) jrk_die("jrk_assert: "msg); } while(0)
     90 #define jrk_assertv(c, msg, ...) do { if (!(c)) jrk_diev("jrk_assert: "msg, __VA_ARGS__); } while(0)
     91 
     92 #define jrk_shift(x, n) ((n)--, *(x)++)
     93 #define jrk_shift_loop(x, n, it) for (char *it = jrk_shift(x, n); n >= 0; it = jrk_shift(x, n))
     94 
     95 #define jrk_emalloc(n) jrk_ecalloc(1, n)
     96 
     97 #define jrk_arena_destroy(arena) ((arena.data) ? free(arena.data) : (void) 0)
     98 #define jrk_arena_push_array(arena, type, n) (type *) jrk__arena_push(arena, sizeof(type) * n)
     99 #define jrk_arena_push_struct(arena, type) (type *) jrk__arena_push(arena, sizeof(type))
    100 
    101 #define jrk_sb_to_sv(sb) jrk_sv_from_parts((sb).items, (sb).count)
    102 
    103 #define JRK_DA_DEFAULT_INIT_CAPACITY 16
    104 #define jrk_da_reserve(da, expected_capacity)                                               \
    105     do {                                                                                    \
    106         if ((expected_capacity) > (da)->capacity) {                                         \
    107             if ((da)->capacity == 0) {                                                      \
    108                 (da)->capacity = JRK_DA_DEFAULT_INIT_CAPACITY;                              \
    109             }                                                                               \
    110             while ((expected_capacity) > (da)->capacity) {                                  \
    111                 (da)->capacity *= 2;                                                        \
    112             }                                                                               \
    113             (da)->items = jrk_erealloc((da)->items, (da)->capacity * sizeof(*(da)->items)); \
    114         }                                                                                   \
    115     } while (0)
    116 
    117 #define jrk_da_append(da, item)                \
    118     do {                                       \
    119         jrk_da_reserve((da), (da)->count + 1); \
    120         (da)->items[(da)->count++] = (item);   \
    121     } while (0);
    122 
    123 #define jrk_da_append_many(da, new_items, new_items_count)                                      \
    124     do {                                                                                        \
    125         jrk_da_reserve((da), (da)->count + (new_items_count));                                  \
    126         memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \
    127         (da)->count += (new_items_count);                                                       \
    128     } while (0)
    129 
    130 #define jrk_da_create(name, type) \
    131     struct name {                 \
    132         type *items;              \
    133         u64 count;                \
    134         u64 capacity;             \
    135     };                            \
    136     typedef struct name name
    137 
    138 #define jrk_da_free(da)                                                   \
    139     do {                                                                  \
    140         jrk_assert((da).items, "bad free: jrk_da_free da.items is NULL"); \
    141         free((da).items);                                                 \
    142     } while (0)
    143 
    144 #define jrk_da_foreach(type,it,da) for (type *it = (da)->items; it < (da)->items + (da)->count; ++it)
    145 
    146 #define jrk_sb_append_null(sb) jrk_da_append(sb, '\0')
    147 #define jrk_sb_free(sb) jrk_da_free(sb)
    148 
    149 #define jrk_sb_append_cstr(sb, cstr)  \
    150     do {                              \
    151         const char *s = (cstr);       \
    152         i64 n = strlen(cstr);         \
    153         jrk_da_append_many(sb, s, n); \
    154     } while (0)
    155 
    156 #define jrk_sb_append_buf(sb, buf, size) jrk_da_append_many(sb, buf, size)
    157 
    158 #ifdef JRK_SHORTNAMES
    159   #define UNUSED               JRK_UNUSED
    160   #define ARRSIZE              JRK_ARRSIZE
    161 
    162   #define Arena                jrk_Arena
    163   #define StringBuilder        jrk_StringBuilder
    164   #define StringView           jrk_StringView
    165 
    166   #define tmpstrings_push      jrk_tmpstrings_push
    167   #define tmpstrings_pushf     jrk_tmpstrings_pushf
    168 
    169   #define sb_appendf           jrk_sb_appendf
    170   #define sb_append_null       jrk_sb_append_null
    171   #define sb_append_buf        jrk_sb_append_buf
    172   #define sb_append_buf_at     jrk_sb_append_buf_at
    173   #define sb_append_cstr       jrk_sb_append_cstr
    174   #define sb_free              jrk_sb_free
    175   #define sb_fd_read_all       jrk_sb_fd_read_all
    176   #define sb_fd_write_all      jrk_sb_fd_write_all
    177   #define sb_to_sv             jrk_sb_to_sv
    178   #define sb_write_file        jrk_sb_write_file
    179   #define sb_read_entire_file  jrk_sb_read_entire_file
    180 
    181   #define sv_trim_left         jrk_sv_trim_left
    182   #define sv_trim_right        jrk_sv_trim_right
    183   #define sv_trim              jrk_sv_trim
    184   #define sv_from_cstr         jrk_sv_from_cstr
    185   #define sv_from_parts        jrk_sv_from_parts
    186   #define sv_chop_delim        jrk_sv_chop_delim
    187 
    188   #define ecalloc              jrk_ecalloc
    189   #define erealloc             jrk_erealloc
    190   #define emalloc              jrk_emalloc
    191 
    192   #define da_reserve           jrk_da_reserve
    193   #define da_append            jrk_da_append
    194   #define da_append_many       jrk_da_append_many
    195   #define da_foreach           jrk_da_foreach
    196   #define da_create            jrk_da_create
    197   #define da_free              jrk_da_free
    198 
    199   #define arena_create         jrk_arena_create
    200   #define arena_destroy        jrk_arena_destroy
    201   #define arena_push_struct    jrk_arena_push_struct
    202   #define arena_push_array     jrk_arena_push_array
    203 
    204   #define rand_num             jrk_rand_num
    205   #define rand_num_range       jrk_rand_num_range
    206 
    207   #define fd_close             jrk_fd_close
    208   #define fd_open_read         jrk_fd_open_read
    209   #define fd_open_write        jrk_fd_open_write
    210   #define fd_open_write_append jrk_fd_open_write_append
    211 
    212   #define shift                jrk_shift
    213   #define shift_loop           jrk_shift_loop
    214 #endif // JRK_SHORTNAMES
    215 
    216 #ifdef JRK_IMPLEMENTATION
    217 #include <ctype.h>
    218 #include <errno.h>
    219 #include <fcntl.h>
    220 #include <stdarg.h>
    221 #include <stdio.h>
    222 #include <stdlib.h>
    223 #include <string.h>
    224 #include <sys/stat.h>
    225 #include <unistd.h>
    226 
    227 #define jrk_die(x)                                                   \
    228     do {                                                             \
    229         fprintf(stderr, "%s:%d: error: "x" \n", __FILE__, __LINE__); \
    230         exit(69);                                                    \
    231     } while(0)
    232 
    233 #define jrk_diev(x, ...)                                                              \
    234     do {                                                                              \
    235         fprintf(stderr, "%s:%d: error: "x"\n", __FILE__, __LINE__, __VA_ARGS__);      \
    236         exit(69);                                                                     \
    237     } while(0)
    238 
    239 #define jrk_edie(x) jrk_diev(x": %s", strerror(errno))
    240 #define jrk_ediev(x, ...) jrk_diev(x": %s", __VA_ARGS__, strerror(errno))
    241 
    242 #ifdef JRK_SHORTNAMES
    243   #define die  jrk_die
    244   #define diev  jrk_diev
    245   #define edie jrk_edie
    246   #define ediev jrk_ediev
    247 #endif // JRK_SHORTNAMES
    248 
    249 void *
    250 jrk_ecalloc(u64 nmemb, u64 size)
    251 {
    252     void *p;
    253 
    254     if (!(p = calloc(nmemb, size)))
    255         jrk_ediev("jrk_ecalloc(%ld, %ld)", nmemb, size);
    256     return p;
    257 }
    258 
    259 void *
    260 jrk_erealloc(void *ptr, u64 size)
    261 {
    262     void *p;
    263 
    264     if (!(p = realloc(ptr, size)))
    265         jrk_ediev("jrk_erealloc(%p, %ld)", ptr, size);
    266     return p;
    267 }
    268 
    269 // NOTE: only allocate space for translation units with JRK_IMPLEMENTATION
    270 static char jrk__tmpstrings[JRK_TMPSTRINGS_ARR_CAPACITY][JRK_TMPSTRINGS_STR_CAPACITY];
    271 static u32 jrk__tmpstrings_idx = 0;
    272 
    273 char *
    274 jrk_tmpstrings_push(char *str)
    275 {
    276     char *result;
    277     result = jrk_tmpstrings_pushf(str);
    278     return result;
    279 }
    280 
    281 char *
    282 jrk_tmpstrings_pushf(char *fmt, ...)
    283 {
    284     char *result = jrk__tmpstrings[jrk__tmpstrings_idx];
    285 
    286     va_list args;
    287     va_start(args, fmt);
    288     vsnprintf(result, JRK_TMPSTRINGS_STR_CAPACITY, fmt, args);
    289     va_end(args);
    290 
    291     if (++jrk__tmpstrings_idx >= JRK_TMPSTRINGS_ARR_CAPACITY)
    292         jrk__tmpstrings_idx = 0;
    293 
    294     return result;
    295 }
    296 
    297 jrk_Arena
    298 jrk_arena_create(u64 n)
    299 {
    300     jrk_Arena result;
    301     result.count = 0;
    302     result.capacity = n;
    303     result.data = jrk_ecalloc(result.capacity, 1);
    304     return result;
    305 }
    306 
    307 void *
    308 jrk__arena_push(jrk_Arena *arena, u64 n)
    309 {
    310     jrk_assertv(arena->count + n <= arena->capacity,
    311                 "jrk__arena_push(%p, %ld): arena push requires %ld bytes but has a capacity of %ld bytes",
    312                 arena, n, arena->count + n, arena->capacity
    313         );
    314 
    315     void *result = &arena->data[arena->count];
    316     arena->count += n;
    317     return result;
    318 }
    319 
    320 i32
    321 jrk_sb_appendf(jrk_StringBuilder *sb, const char *fmt, ...)
    322 {
    323     va_list args;
    324     va_start(args, fmt);
    325     i32 n = vsnprintf(NULL, 0, fmt, args);
    326     va_end(args);
    327 
    328     jrk_da_reserve(sb, sb->count + n + 1);
    329     va_start(args, fmt);
    330     vsnprintf(sb->items + sb->count, n + 1, fmt, args);
    331     va_end(args);
    332     sb->count += n;
    333 
    334     return n;
    335 }
    336 
    337 void
    338 jrk_sb_append_buf_at(jrk_StringBuilder *sb, char *buf, u64 size, u64 idx)
    339 {
    340     jrk_assertv(idx < sb->count, "jrk_sb_append_buf_at(%p, %p, %ld, %ld): idx is greater than sb->count",
    341                 sb, buf, size, idx);
    342 
    343     u64 new_size = sb->count + size;
    344     char *temp = jrk_emalloc(new_size);
    345 
    346     memcpy(temp, sb->items, idx);
    347     memcpy(temp + idx, buf, size);
    348     memcpy(temp + idx + size, sb->items + idx, sb->count - idx);
    349 
    350     free(sb->items);
    351     sb->items = temp;
    352     sb->count = new_size;
    353 
    354     // NOTE: maybe keep it a proper ^2?
    355     sb->capacity = new_size;
    356 }
    357 
    358 u64
    359 jrk_fd_size(i32 fd)
    360 {
    361     struct stat statbuf = {0};
    362     if (fstat(fd, &statbuf) < 0)
    363         jrk_ediev("jrk_fd_size(%d)", fd);
    364 
    365     return statbuf.st_size;
    366 }
    367 
    368 void
    369 jrk_sb_fd_read_all(jrk_StringBuilder *sb, i32 fd)
    370 {
    371     u64 sz = jrk_fd_size(fd);
    372     jrk_da_reserve(sb, sz);
    373     if (read(fd, sb->items, sz) < 0)
    374         jrk_ediev("jrk_sb_fd_read_all(%p, %d)", (void *)sb, fd);
    375 
    376     sb->count = sz;
    377 }
    378 
    379 u64
    380 jrk_sb_fd_write_all(jrk_StringBuilder *sb, i32 fd)
    381 {
    382     i64 result;
    383     result = write(fd, (void *) sb->items, sb->count);
    384     if (result < 0)
    385         jrk_ediev("jrk_sb_fd_write_all(%p, %d)", (void *)sb, fd);
    386 
    387     return result;
    388 }
    389 
    390 void
    391 jrk_fd_close(i32 fd)
    392 {
    393     close(fd);
    394 }
    395 
    396 void
    397 jrk_sb_write_file(jrk_StringBuilder *sb, char *path)
    398 {
    399     i32 fd = jrk_fd_open_write(path);
    400     jrk_sb_fd_write_all(sb, fd);
    401     jrk_fd_close(fd);
    402 }
    403 
    404 void
    405 jrk_sb_read_entire_file(jrk_StringBuilder *sb, char *path)
    406 {
    407     i32 fd = jrk_fd_open_read(path);
    408     jrk_sb_fd_read_all(sb, fd);
    409     jrk_fd_close(fd);
    410 }
    411 
    412 i32
    413 jrk_fd_open_read(char *path)
    414 {
    415     i32 result = open(path, O_RDONLY);
    416 
    417     if (result < 0)
    418         jrk_ediev("jrk_fd_open_read(%s)", path);
    419 
    420     return result;
    421 }
    422 
    423 i32
    424 jrk_fd_open_write(char *path)
    425 {
    426     i32 result = open(path,
    427                      O_WRONLY | O_CREAT | O_TRUNC,
    428                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    429 
    430     if (result < 0)
    431         jrk_ediev("jrk_fd_open_write(%s)", path);
    432 
    433     return result;
    434 }
    435 
    436 i32
    437 jrk_fd_open_write_append(char *path)
    438 {
    439     i32 result = open(path,
    440                      O_WRONLY | O_CREAT | O_APPEND,
    441                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    442 
    443     if (result < 0)
    444         jrk_ediev("jrk_fd_open_write_append(%s)", path);
    445 
    446     return result;
    447 }
    448 
    449 jrk_StringView
    450 jrk_sv_from_parts(char *data, u64 count)
    451 {
    452     jrk_StringView result = {0};
    453     result.data = data;
    454     result.count = count;
    455     return result;
    456 }
    457 
    458 jrk_StringView
    459 jrk_sv_from_cstr(char *data)
    460 {
    461     jrk_StringView result = {0};
    462     result.data = data;
    463     result.count = strlen(data);
    464     return result;
    465 }
    466 
    467 jrk_StringView
    468 jrk_sv_trim_right(jrk_StringView sv)
    469 {
    470     u64 i = 0;
    471     for (; i < sv.count && isspace(sv.data[sv.count - 1 - i]); ++i);
    472     return jrk_sv_from_parts(sv.data, sv.count - i);
    473 }
    474 
    475 jrk_StringView
    476 jrk_sv_trim_left(jrk_StringView sv)
    477 {
    478     u64 i = 0;
    479     for (; i < sv.count && isspace(sv.data[i]); ++i);
    480     return jrk_sv_from_parts(sv.data + i, sv.count - i);
    481 }
    482 
    483 jrk_StringView
    484 jrk_sv_trim(jrk_StringView sv)
    485 {
    486     return jrk_sv_trim_right(jrk_sv_trim_left(sv));
    487 }
    488 
    489 jrk_StringView
    490 jrk_sv_chop_delim(jrk_StringView *sv, char delim)
    491 {
    492     u64 i = 0;
    493     while (i < sv->count && sv->data[i] != delim)
    494         ++i;
    495 
    496     jrk_StringView result = jrk_sv_from_parts(sv->data, i);
    497 
    498     if (i < sv->count) {
    499         sv->data += i + 1;
    500         sv->count -= i + 1;
    501     } else {
    502         sv->data += i;
    503         sv->count -= i;
    504     }
    505 
    506     return result;
    507 }
    508 
    509 i32
    510 jrk_rand_num(i32 upbound)
    511 {
    512     return rand() % upbound + 1;
    513 }
    514 
    515 i32
    516 jrk_rand_num_range(i32 min, i32 max)
    517 {
    518     return rand() % (max - min + 1) + min;
    519 }
    520 
    521 #endif // JRK_IMPLEMENTATION