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