util.c (10457B)
1 /* See LICENSE for license details. */ 2 #define zero_struct(s) mem_clear(s, 0, sizeof(*s)) 3 function void * 4 mem_clear(void *restrict p_, u8 c, uz size) 5 { 6 u8 *p = p_; 7 while (size) p[--size] = c; 8 return p; 9 } 10 11 function void 12 mem_copy(void *restrict dest, void *restrict src, uz n) 13 { 14 u8 *s = src, *d = dest; 15 for (; n; n--) *d++ = *s++; 16 } 17 18 function u8 * 19 arena_commit(Arena *a, sz size) 20 { 21 assert(a->end - a->beg >= size); 22 u8 *result = a->beg; 23 a->beg += size; 24 return result; 25 } 26 27 function void 28 arena_pop(Arena *a, sz length) 29 { 30 a->beg -= length; 31 } 32 33 #define push_array(a, t, n) (t *)arena_alloc(a, sizeof(t), alignof(t), n) 34 #define push_struct(a, t) (t *)arena_alloc(a, sizeof(t), alignof(t), 1) 35 function void * 36 arena_alloc(Arena *a, sz len, sz align, sz count) 37 { 38 /* NOTE: special case 0 arena */ 39 if (a->beg == 0) 40 return 0; 41 42 sz padding = -(uintptr_t)a->beg & (align - 1); 43 sz available = a->end - a->beg - padding; 44 if (available < 0 || count > available / len) 45 assert(0 && "arena OOM\n"); 46 void *p = a->beg + padding; 47 a->beg += padding + count * len; 48 /* TODO: Performance? */ 49 return mem_clear(p, 0, count * len); 50 } 51 52 enum { DA_INITIAL_CAP = 4 }; 53 #define da_reserve(a, s, n) \ 54 (s)->data = da_reserve_((a), (s)->data, &(s)->capacity, (s)->count + n, \ 55 _Alignof(typeof(*(s)->data)), sizeof(*(s)->data)) 56 57 #define da_push(a, s) \ 58 ((s)->count == (s)->capacity \ 59 ? da_reserve(a, s, 1), \ 60 (s)->data + (s)->count++ \ 61 : (s)->data + (s)->count++) 62 63 function void * 64 da_reserve_(Arena *a, void *data, sz *capacity, sz needed, sz align, sz size) 65 { 66 sz cap = *capacity; 67 68 /* NOTE(rnp): handle both 0 initialized DAs and DAs that need to be moved (they started 69 * on the stack or someone allocated something in the middle of the arena during usage) */ 70 if (!data || a->beg != (u8 *)data + cap * size) { 71 void *copy = arena_alloc(a, size, align, cap); 72 if (data) mem_copy(copy, data, cap * size); 73 data = copy; 74 } 75 76 if (!cap) cap = DA_INITIAL_CAP; 77 while (cap < needed) cap *= 2; 78 arena_alloc(a, size, align, cap - *capacity); 79 *capacity = cap; 80 return data; 81 } 82 83 function sv2 84 sv2_sub(sv2 a, sv2 b) 85 { 86 sv2 result; 87 result.x = a.x - b.x; 88 result.y = a.y - b.y; 89 return result; 90 } 91 92 function v3 93 v3_sub(v3 a, v3 b) 94 { 95 v3 result; 96 result.x = a.x - b.x; 97 result.y = a.y - b.y; 98 result.z = a.z - b.z; 99 return result; 100 } 101 102 function f32 103 v3_dot(v3 a, v3 b) 104 { 105 f32 result = a.x * b.x + a.y * b.y + a.z * b.z; 106 return result; 107 } 108 109 function v3 110 v3_normalize(v3 a) 111 { 112 f32 scale = sqrt_f32(1 / v3_dot(a, a)); 113 v3 result = a; 114 result.x *= scale; 115 result.y *= scale; 116 result.z *= scale; 117 return result; 118 } 119 120 function v3 121 cross(v3 a, v3 b) 122 { 123 v3 result; 124 result.x = a.y * b.z - a.z * b.y; 125 result.y = a.z * b.x - a.x * b.z; 126 result.z = a.x * b.y - a.y * b.x; 127 return result; 128 } 129 130 function f32 131 v4_dot(v4 a, v4 b) 132 { 133 f32 result = 0; 134 result += a.x * b.x; 135 result += a.y * b.y; 136 result += a.z * b.z; 137 result += a.w * b.w; 138 return result; 139 } 140 141 function v4 142 m4_row(m4 a, u32 row) 143 { 144 v4 result; 145 result.E[0] = a.c[0].E[row]; 146 result.E[1] = a.c[1].E[row]; 147 result.E[2] = a.c[2].E[row]; 148 result.E[3] = a.c[3].E[row]; 149 return result; 150 } 151 152 function v4 153 m4_column(m4 a, u32 column) 154 { 155 v4 result = a.c[column]; 156 return result; 157 } 158 159 function m4 160 m4_mul(m4 a, m4 b) 161 { 162 m4 result; 163 for (u32 i = 0; i < countof(result.E); i++) { 164 u32 base = i / 4; 165 u32 sub = i % 4; 166 v4 v1 = m4_row(a, base); 167 v4 v2 = m4_column(b, sub); 168 result.E[i] = v4_dot(v1, v2); 169 } 170 return result; 171 } 172 173 function u32 174 utf8_encode(u8 *out, u32 cp) 175 { 176 u32 result = 1; 177 if (cp <= 0x7F) { 178 out[0] = cp & 0x7F; 179 } else if (cp <= 0x7FF) { 180 result = 2; 181 out[0] = ((cp >> 6) & 0x1F) | 0xC0; 182 out[1] = ((cp >> 0) & 0x3F) | 0x80; 183 } else if (cp <= 0xFFFF) { 184 result = 3; 185 out[0] = ((cp >> 12) & 0x0F) | 0xE0; 186 out[1] = ((cp >> 6) & 0x3F) | 0x80; 187 out[2] = ((cp >> 0) & 0x3F) | 0x80; 188 } else if (cp <= 0x10FFFF) { 189 result = 4; 190 out[0] = ((cp >> 18) & 0x07) | 0xF0; 191 out[1] = ((cp >> 12) & 0x3F) | 0x80; 192 out[2] = ((cp >> 6) & 0x3F) | 0x80; 193 out[3] = ((cp >> 0) & 0x3F) | 0x80; 194 } else { 195 out[0] = '?'; 196 } 197 return result; 198 } 199 200 function UnicodeDecode 201 utf16_decode(u16 *data, sz length) 202 { 203 UnicodeDecode result = {.cp = U32_MAX}; 204 if (length) { 205 result.consumed = 1; 206 result.cp = data[0]; 207 if (length > 1 && BETWEEN(data[0], 0xD800, 0xDBFF) 208 && BETWEEN(data[1], 0xDC00, 0xDFFF)) 209 { 210 result.consumed = 2; 211 result.cp = ((data[0] - 0xD800) << 10) | ((data[1] - 0xDC00) + 0x10000); 212 } 213 } 214 return result; 215 } 216 217 function u32 218 utf16_encode(u16 *out, u32 cp) 219 { 220 u32 result = 1; 221 if (cp == U32_MAX) { 222 out[0] = '?'; 223 } else if (cp < 0x10000) { 224 out[0] = cp; 225 } else { 226 u32 value = cp - 0x10000; 227 out[0] = 0xD800 + (value >> 10u); 228 out[1] = 0xDC00 + (value & 0x3FFu); 229 result = 2; 230 } 231 return result; 232 } 233 234 function Stream 235 stream_alloc(Arena *a, sz cap) 236 { 237 Stream result = {.cap = cap}; 238 result.data = push_array(a, u8, cap); 239 return result; 240 } 241 242 function str8 243 stream_to_str8(Stream *s) 244 { 245 str8 result = str8(""); 246 if (!s->errors) result = (str8){.len = s->widx, .data = s->data}; 247 return result; 248 } 249 250 function void 251 stream_reset(Stream *s, sz index) 252 { 253 s->errors = s->cap <= index; 254 if (!s->errors) 255 s->widx = index; 256 } 257 258 function void 259 stream_commit(Stream *s, sz count) 260 { 261 s->errors |= !BETWEEN(s->widx + count, 0, s->cap); 262 if (!s->errors) 263 s->widx += count; 264 } 265 266 function void 267 stream_append(Stream *s, void *data, sz count) 268 { 269 s->errors |= (s->cap - s->widx) < count; 270 if (!s->errors) { 271 mem_copy(s->data + s->widx, data, count); 272 s->widx += count; 273 } 274 } 275 276 function void 277 stream_append_byte(Stream *s, u8 b) 278 { 279 stream_append(s, &b, 1); 280 } 281 282 function void 283 stream_append_str8(Stream *s, str8 str) 284 { 285 stream_append(s, str.data, str.len); 286 } 287 288 #define stream_append_str8s(s, ...) stream_append_str8s_(s, (str8 []){__VA_ARGS__}, \ 289 sizeof((str8 []){__VA_ARGS__}) / sizeof(str8)) 290 function void 291 stream_append_str8s_(Stream *s, str8 *strs, sz count) 292 { 293 for (sz i = 0; i < count; i++) 294 stream_append(s, strs[i].data, strs[i].len); 295 } 296 297 function void 298 stream_append_u64_width(Stream *s, u64 n, u64 min_width) 299 { 300 u8 tmp[64]; 301 u8 *end = tmp + sizeof(tmp); 302 u8 *beg = end; 303 min_width = MIN(sizeof(tmp), min_width); 304 305 do { *--beg = '0' + (n % 10); } while (n /= 10); 306 while (end - beg > 0 && end - beg < min_width) 307 *--beg = '0'; 308 309 stream_append(s, beg, end - beg); 310 } 311 312 function void 313 stream_append_u64(Stream *s, u64 n) 314 { 315 stream_append_u64_width(s, n, 0); 316 } 317 318 function void 319 stream_append_s64(Stream *s, s64 n) 320 { 321 if (n < 0) { 322 stream_append_byte(s, '-'); 323 n *= -1; 324 } 325 stream_append_u64(s, n); 326 } 327 328 function void 329 stream_append_f64(Stream *s, f64 f, s64 prec) 330 { 331 if (f < 0) { 332 stream_append_byte(s, '-'); 333 f *= -1; 334 } 335 336 /* NOTE: round last digit */ 337 f += 0.5f / prec; 338 339 if (f >= (f64)(-1UL >> 1)) { 340 stream_append_str8(s, str8("inf")); 341 } else { 342 u64 integral = f; 343 u64 fraction = (f - integral) * prec; 344 stream_append_u64(s, integral); 345 stream_append_byte(s, '.'); 346 for (s64 i = prec / 10; i > 1; i /= 10) { 347 if (i > fraction) 348 stream_append_byte(s, '0'); 349 } 350 stream_append_u64(s, fraction); 351 } 352 } 353 354 function Stream 355 arena_stream(Arena a) 356 { 357 Stream result = {0}; 358 result.data = a.beg; 359 result.cap = a.end - a.beg; 360 return result; 361 } 362 363 function str8 364 arena_stream_commit_zero(Arena *a, Stream *s) 365 { 366 b32 error = s->errors || s->widx == s->cap; 367 if (!error) 368 s->data[s->widx] = 0; 369 str8 result = stream_to_str8(s); 370 arena_commit(a, result.len + 1); 371 return result; 372 } 373 374 375 /* NOTE(rnp): FNV-1a hash */ 376 function u64 377 str8_hash(str8 v) 378 { 379 u64 h = 0x3243f6a8885a308d; /* digits of pi */ 380 for (; v.len; v.len--) { 381 h ^= v.data[v.len - 1] & 0xFF; 382 h *= 1111111111111111111; /* random prime */ 383 } 384 return h; 385 } 386 387 function str8 388 c_str_to_str8(char *cstr) 389 { 390 str8 result = {.data = (u8 *)cstr}; 391 if (cstr) while (*cstr) { cstr++; } 392 result.len = (u8 *)cstr - result.data; 393 return result; 394 } 395 396 /* NOTE(rnp): returns < 0 if byte is not found */ 397 function sz 398 str8_scan_backwards(str8 s, u8 byte) 399 { 400 sz result = s.len; 401 while (result && s.data[result - 1] != byte) result--; 402 result--; 403 return result; 404 } 405 406 function str8 407 str8_cut_head(str8 s, sz cut) 408 { 409 str8 result = s; 410 if (cut > 0) { 411 result.data += cut; 412 result.len -= cut; 413 } 414 return result; 415 } 416 417 function str8 418 str8_alloc(Arena *a, sz len) 419 { 420 str8 result = {.data = push_array(a, u8, len), .len = len}; 421 return result; 422 } 423 424 function str8 425 str16_to_str8(Arena *a, str16 in) 426 { 427 str8 result = str8(""); 428 if (in.len) { 429 sz commit = in.len * 4; 430 sz length = 0; 431 u8 *data = arena_commit(a, commit + 1); 432 u16 *beg = in.data; 433 u16 *end = in.data + in.len; 434 while (beg < end) { 435 UnicodeDecode decode = utf16_decode(beg, end - beg); 436 length += utf8_encode(data + length, decode.cp); 437 beg += decode.consumed; 438 } 439 data[length] = 0; 440 result = (str8){.len = length, .data = data}; 441 arena_pop(a, commit - length); 442 } 443 return result; 444 } 445 446 function str16 447 str8_to_str16(Arena *a, str8 in) 448 { 449 str16 result = {0}; 450 if (in.len) { 451 sz required = 2 * in.len + 1; 452 u16 *data = push_array(a, u16, required); 453 sz length = 0; 454 /* TODO(rnp): utf8_decode */ 455 for (sz i = 0; i < in.len; i++) { 456 u32 cp = in.data[i]; 457 length += utf16_encode(data + length, cp); 458 } 459 result = (str16){.len = length, .data = data}; 460 arena_pop(a, required - length); 461 } 462 return result; 463 } 464 465 function str8 466 push_str8(Arena *a, str8 str) 467 { 468 str8 result = str8_alloc(a, str.len); 469 mem_copy(result.data, str.data, result.len); 470 return result; 471 } 472 473 function str8 474 push_str8_zero(Arena *a, str8 str) 475 { 476 str8 result = str8_alloc(a, str.len + 1); 477 result.len -= 1; 478 mem_copy(result.data, str.data, result.len); 479 return result; 480 } 481 482 function f64 483 parse_f64(str8 s) 484 { 485 f64 integral = 0, fractional = 0, sign = 1; 486 487 if (s.len && *s.data == '-') { 488 sign = -1; 489 s.data++; 490 s.len--; 491 } 492 493 while (s.len && *s.data != '.') { 494 integral *= 10; 495 integral += *s.data - '0'; 496 s.data++; 497 s.len--; 498 } 499 500 if (*s.data == '.') { s.data++; s.len--; } 501 502 while (s.len) { 503 assert(s.data[s.len - 1] != '.'); 504 fractional /= 10; 505 fractional += (f64)(s.data[--s.len] - '0') / 10.0; 506 } 507 f64 result = sign * (integral + fractional); 508 return result; 509 } 510 511 function FileWatchDirectory * 512 lookup_file_watch_directory(FileWatchContext *ctx, u64 hash) 513 { 514 FileWatchDirectory *result = 0; 515 for (u32 i = 0; i < ctx->count; i++) { 516 FileWatchDirectory *test = ctx->data + i; 517 if (test->hash == hash) { 518 result = test; 519 break; 520 } 521 } 522 return result; 523 }