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