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
