util.c (13869B)
1 /* See LICENSE for copyright details */ 2 3 /* NOTE: avoids braindead standards committee UB when n is negative or shift is > 31 */ 4 function u32 5 safe_left_shift(u32 n, u32 shift) 6 { 7 u64 result = (u64)n << (shift & 63); 8 return result & 0xFFFFFFFF; 9 } 10 11 function u32 12 round_down_power_of_2(u32 a) 13 { 14 u32 result = 0x80000000UL >> clz_u32(a); 15 return result; 16 } 17 18 function v2 19 sub_v2(v2 a, v2 b) 20 { 21 v2 result; 22 result.x = a.x - b.x; 23 result.y = a.y - b.y; 24 return result; 25 } 26 27 function f32 28 length_v2(v2 a) 29 { 30 f32 result = a.x * a.x + a.y * a.y; 31 return result; 32 } 33 34 function b32 35 equal_iv2(iv2 a, iv2 b) 36 { 37 b32 result = a.x == b.x && a.y == b.y; 38 return result; 39 } 40 41 function b32 42 equal_uv2(uv2 a, uv2 b) 43 { 44 b32 result = a.x == b.x && a.y == b.y; 45 return result; 46 } 47 48 function v2 49 v2_from_iv2(iv2 a) 50 { 51 v2 result = {.x = a.x, .y = a.y}; 52 return result; 53 } 54 55 function b32 56 is_valid_range(Range r) 57 { 58 b32 result = !equal_iv2(r.end, INVALID_RANGE_END); 59 return result; 60 } 61 62 function b32 63 equal_range(Range a, Range b) 64 { 65 b32 result = equal_iv2(a.start, b.start) && equal_iv2(a.end, b.end); 66 return result; 67 } 68 69 function b32 70 point_in_rect(v2 point, Rect rect) 71 { 72 v2 max = {.x = rect.pos.x + rect.size.w, .y = rect.pos.y + rect.size.h}; 73 b32 result = BETWEEN(point.x, rect.pos.x, max.x) && BETWEEN(point.y, rect.pos.y, max.y); 74 return result; 75 } 76 77 function Range 78 normalize_range(Range r) 79 { 80 Range result; 81 if (!is_valid_range(r) || r.start.y < r.end.y) { 82 result = r; 83 } else if (r.end.y < r.start.y) { 84 result = (Range){.start = r.end, .end = r.start}; 85 } else { 86 result.start.y = result.end.y = r.start.y; 87 result.start.x = MIN(r.start.x, r.end.x); 88 result.end.x = MAX(r.start.x, r.end.x); 89 } 90 return result; 91 } 92 93 function void 94 mem_copy(void *restrict dest, void *restrict src, iz len) 95 { 96 ASSERT(len >= 0); 97 u8 *s = src, *d = dest; 98 for (; len; len--) *d++ = *s++; 99 } 100 101 #define zero_struct(s) mem_clear(s, 0, sizeof(typeof(*s))) 102 function void * 103 mem_clear(void *p_, u8 c, iz len) 104 { 105 u8 *p = p_; 106 while (len) p[--len] = c; 107 return p; 108 } 109 110 /* NOTE(rnp): based on nullprogram's lock-free, concurrent, 111 * generic queue in 32 bits */ 112 function WorkQueueWork * 113 work_queue_push(WorkQueue *q) 114 { 115 WorkQueueWork *result = 0; 116 static_assert(ISPOWEROFTWO(countof(q->items)), "queue capacity must be power of two"); 117 u64 val = atomic_load(&q->queue); 118 u64 mask = countof(q->items) - 1; 119 u32 widx = val & mask; 120 u32 ridx = (val >> 32) & mask; 121 u32 next = (widx + 1) & mask; 122 123 /* NOTE(rnp): prevent an overflow into the tail on commit */ 124 if (val & 0x80000000ULL) 125 atomic_and(&q->queue, ~0x80000000ULL); 126 127 if (next != ridx) { 128 result = q->items + widx; 129 zero_struct(result); 130 } 131 132 return result; 133 } 134 135 function void 136 work_queue_push_commit(WorkQueue *q) 137 { 138 atomic_fetch_add(&q->queue, 1); 139 } 140 141 function WorkQueueWork * 142 work_queue_pop(WorkQueue *q) 143 { 144 WorkQueueWork *result = 0; 145 static_assert(ISPOWEROFTWO(countof(q->items)), "queue capacity must be power of two"); 146 u64 val = atomic_load(&q->queue); 147 u64 mask = countof(q->items) - 1; 148 u32 widx = val & mask; 149 u32 ridx = (val >> 32) & mask; 150 151 if (ridx != widx) 152 result = q->items + ridx; 153 154 return result; 155 } 156 157 function void 158 work_queue_pop_commit(WorkQueue *q) 159 { 160 atomic_fetch_add(&q->queue, 0x100000000ULL); 161 } 162 163 function b32 164 work_queue_empty(WorkQueue *q) 165 { 166 static_assert(ISPOWEROFTWO(countof(q->items)), "queue capacity must be power of two"); 167 u64 r = atomic_load(&q->queue); 168 u32 mask = countof(q->items) - 1; 169 u32 head = r & mask; 170 u32 tail = (r >> 32) & mask; 171 return head == tail; 172 } 173 174 function b32 175 work_queue_insert(WorkQueue *q, WorkQueueWorkKind kind, void *ctx) 176 { 177 WorkQueueWork *work = work_queue_push(q); 178 b32 result = 0; 179 /* NOTE(rnp): if we ever fill this up we need to resize the queue */ 180 if (work) { 181 work->kind = kind; 182 work->generic = ctx; 183 work_queue_push_commit(q); 184 } 185 return result; 186 } 187 188 #define push_struct(a, t) alloc(a, t, 1) 189 #define alloc(a, t, n) (t *)alloc_(a, sizeof(t), _Alignof(t), n) 190 function void * 191 alloc_(Arena *a, iz len, iz align, iz count) 192 { 193 iz padding = -(uintptr_t)a->beg & (align - 1); 194 iz available = a->end - a->beg - padding; 195 if (available <= 0 || available / len < count) { 196 ASSERT(0); 197 } 198 199 void *p = a->beg + padding; 200 a->beg += padding + count * len; 201 return mem_clear(p, 0, count * len); 202 } 203 204 function Arena 205 arena_from_memory_block(OSMemoryBlock memory) 206 { 207 Arena result; 208 result.beg = memory.memory; 209 result.end = memory.memory + memory.size; 210 return result; 211 } 212 213 function OSMemoryBlock 214 memory_block_from_arena(Arena *a, iz requested_size) 215 { 216 OSMemoryBlock result; 217 result.memory = alloc_(a, requested_size, 64, 1); 218 result.size = requested_size; 219 return result; 220 } 221 222 function Arena 223 sub_arena(Arena *a, iz size) 224 { 225 Arena result = {0}; 226 result.beg = alloc_(a, size, 64, 1); 227 result.end = result.beg + size; 228 return result; 229 } 230 231 function TempArena 232 begin_temp_arena(Arena *a) 233 { 234 TempArena result; 235 result.arena = a; 236 result.old_beg = a->beg; 237 return result; 238 } 239 240 function void 241 end_temp_arena(TempArena ta) 242 { 243 Arena *a = ta.arena; 244 ASSERT(a->beg >= ta.old_beg); 245 a->beg = ta.old_beg; 246 } 247 248 /* NOTE: This performs wrapping of the ring buffer as needed; since a line could be in 249 * progress this must also adjust the start and end of the current line */ 250 function void 251 commit_to_rb(TermView *tv, iz len) 252 { 253 ASSERT(ABS(len) <= tv->log.capacity); 254 255 tv->log.write_index += len; 256 tv->log.filled += len; 257 258 CLAMP(tv->log.filled, 0, tv->log.capacity); 259 if (tv->log.write_index >= tv->log.capacity) { 260 tv->log.write_index -= tv->log.capacity; 261 262 iz line = tv->lines.count; 263 tv->lines.data[line].start -= tv->log.capacity; 264 tv->lines.data[line].end -= tv->log.capacity; 265 } 266 267 ASSERT(tv->log.filled >= 0); 268 ASSERT(tv->log.write_index >= 0 && tv->log.write_index < tv->log.capacity); 269 } 270 271 function LineBuffer 272 line_buffer_alloc(Arena *a, u8 *start_position, CellStyle state, iz capacity) 273 { 274 LineBuffer result = {0}; 275 result.capacity = capacity; 276 result.data = alloc(a, Line, capacity); 277 result.data[0].start = start_position; 278 result.data[0].end = start_position; 279 result.data[0].cursor_state = state; 280 return result; 281 } 282 283 function s8 284 s8alloc(Arena *a, iz len) 285 { 286 return (s8){.len = len, .data = alloc(a, u8, len)}; 287 } 288 289 function s8 290 c_str_to_s8(char *s) 291 { 292 s8 result = {.data = (u8 *)s}; 293 if (s) { 294 char *end = s; 295 while (*end) end++; 296 result.len = end - s; 297 } 298 return result; 299 } 300 301 function b32 302 s8_equal(s8 a, s8 b) 303 { 304 b32 result = a.len == b.len; 305 for (iz i = 0; result && i < a.len; i++) 306 result = a.data[i] == b.data[i]; 307 return result; 308 } 309 310 function b32 311 s8_prefix_of(s8 s, s8 match) 312 { 313 b32 result = 0; 314 if (s.len <= match.len) { 315 s8 head = {.data = match.data, .len = s.len}; 316 result = s8_equal(s, head); 317 } 318 return result; 319 } 320 321 function s8 322 s8_chop_at(s8 raw, u8 delim) 323 { 324 iz i; 325 for (i = 0; i < raw.len; i++) { 326 if (raw.data[i] == delim) 327 break; 328 } 329 s8 result = {.len = i, .data = raw.data}; 330 return result; 331 } 332 333 function void 334 s8_parse_i32_accum(struct conversion_result *result, s8 raw) 335 { 336 result->status = CR_SUCCESS; 337 338 iz i = 0; 339 i32 scale = 1; 340 if (raw.len && raw.data[0] == '-') { 341 scale = -1; 342 i = 1; 343 } 344 345 for (; i < raw.len; i++) { 346 i32 digit = (i32)raw.data[i] - '0'; 347 if (BETWEEN(digit, 0, 9)) { 348 if (result->i > (I32_MAX - digit) / 10) { 349 result->status = CR_OUT_OF_RANGE; 350 result->i = I32_MAX; 351 } else { 352 result->i = 10 * result->i + digit; 353 } 354 } else { 355 break; 356 } 357 } 358 359 if (i == 0 || (i == 1 && raw.data[0] == '-')) 360 result->status = CR_FAILURE; 361 362 result->unparsed = (s8){.len = raw.len - i, .data = raw.data + i}; 363 result->i *= scale; 364 } 365 366 function struct conversion_result 367 s8_parse_i32(s8 raw) 368 { 369 struct conversion_result result = {0}; 370 s8_parse_i32_accum(&result, raw); 371 return result; 372 } 373 374 function struct conversion_result 375 s8_parse_i32_until(s8 raw, u8 delim) 376 { 377 s8 chopped = s8_chop_at(raw, delim); 378 struct conversion_result result = s8_parse_i32(chopped); 379 result.unparsed = (s8){.data = raw.data + chopped.len, .len = raw.len - chopped.len}; 380 return result; 381 } 382 383 function Stream 384 arena_stream(Arena a) 385 { 386 Stream result = {0}; 387 result.capacity = a.end - a.beg; 388 result.data = a.beg; 389 return result; 390 } 391 392 function void 393 stream_reset(Stream *s, iz index) 394 { 395 s->errors = index < 0 || index > s->capacity; 396 if (!s->errors) s->count = index; 397 } 398 399 function void 400 stream_commit(Stream *s, iz count) 401 { 402 s->errors |= !BETWEEN(s->count + count, 0, s->capacity); 403 if (!s->errors) 404 s->count += count; 405 } 406 407 function Stream 408 stream_alloc(Arena *a, i32 capacity) 409 { 410 Stream result = {0}; 411 result.capacity = capacity; 412 result.data = alloc(a, u8, capacity); 413 return result; 414 } 415 416 function s8 417 stream_to_s8(Stream *s) 418 { 419 s8 result = {.len = s->count, .data = s->data}; 420 return result; 421 } 422 423 function void 424 stream_push_byte(Stream *s, u8 cp) 425 { 426 s->errors |= !(s->capacity - s->count); 427 if (!s->errors) 428 s->data[s->count++] = cp; 429 } 430 431 function void 432 stream_push_s8(Stream *s, s8 str) 433 { 434 s->errors |= (s->capacity - s->count) < str.len; 435 if (!s->errors) { 436 mem_copy(s->data + s->count, str.data, str.len); 437 s->count += str.len; 438 } 439 } 440 441 /* NOTE: how can he get away with not using a library for this */ 442 function void 443 stream_push_s8_left_padded(Stream *s, s8 str, u32 width) 444 { 445 for (u32 i = str.len; i < width; i++) 446 stream_push_byte(s, ' '); 447 stream_push_s8(s, str); 448 } 449 450 function void 451 stream_push_s8s(Stream *s, u32 count, s8 *strs) 452 { 453 while (count) { stream_push_s8(s, *strs++); count--; } 454 } 455 456 function void 457 stream_push_hex_u64(Stream *s, u64 n) 458 { 459 if (!s->errors) { 460 static u8 hex[16] = {"0123456789abcdef"}; 461 u8 buf[16]; 462 u8 *end = buf + sizeof(buf); 463 u8 *beg = end; 464 while (n) { 465 *--beg = hex[n & 0x0F]; 466 n >>= 4; 467 } 468 while (end - beg < 2) 469 *--beg = '0'; 470 stream_push_s8(s, (s8){.len = end - beg, .data = beg}); 471 } 472 } 473 474 function void 475 stream_push_u64_padded(Stream *s, u64 n, u32 width) 476 { 477 if (!s->errors) { 478 u8 tmp[64]; 479 u8 *end = tmp + sizeof(tmp); 480 u8 *beg = end; 481 do { *--beg = '0' + (n % 10); } while (n /= 10); 482 483 s8 str = {.len = end - beg, .data = beg}; 484 for (u32 i = str.len; i < width; i++) 485 stream_push_byte(s, ' '); 486 stream_push_s8(s, str); 487 } 488 } 489 490 function void 491 stream_push_u64(Stream *s, u64 n) 492 { 493 stream_push_u64_padded(s, n, 0); 494 } 495 496 function void 497 stream_push_i64(Stream *s, i64 n) 498 { 499 s->errors |= n == I64_MIN; 500 if (!s->errors) { 501 if (n < 0) { 502 stream_push_byte(s, '-'); 503 n = -n; 504 } 505 stream_push_u64_padded(s, n, 0); 506 } 507 } 508 509 function void 510 stream_push_iv2(Stream *s, iv2 v) 511 { 512 stream_push_byte(s, '{'); 513 stream_push_i64(s, v.x); 514 stream_push_byte(s, ','); 515 stream_push_i64(s, v.y); 516 stream_push_byte(s, '}'); 517 } 518 519 function void 520 stream_push_f64(Stream *s, f64 f, i64 prec) 521 { 522 if (f < 0) { 523 stream_push_byte(s, '-'); 524 f *= -1; 525 } 526 527 /* NOTE: round last digit */ 528 f += 0.5f / prec; 529 530 if (f >= (f64)(-1UL >> 1)) { 531 stream_push_s8(s, s8("inf")); 532 } else { 533 u64 integral = f; 534 u64 fraction = (f - integral) * prec; 535 stream_push_u64(s, integral); 536 stream_push_byte(s, '.'); 537 for (u64 i = prec / 10; i > 1; i /= 10) { 538 if (i > fraction) 539 stream_push_byte(s, '0'); 540 } 541 stream_push_u64(s, fraction); 542 } 543 } 544 545 function void 546 selection_clear(Selection *s) 547 { 548 s->range.end = INVALID_RANGE_END; 549 s->state = SS_NONE; 550 } 551 552 function SelectionIterator 553 selection_iterator(Range s, Row *rows, u32 term_width) 554 { 555 SelectionIterator result; 556 result.rows = rows; 557 result.cursor = (iv2){.x = -1, .y = -1}; 558 result.next = s.start; 559 result.end = s.end; 560 result.term_width = term_width; 561 return result; 562 } 563 564 function Cell * 565 selection_next(SelectionIterator *s) 566 { 567 Cell *result = 0; 568 569 if (!equal_iv2(s->cursor, s->end)) { 570 s->cursor = s->next; 571 result = s->rows[s->next.y] + s->next.x++; 572 if (s->next.x == s->term_width) { 573 s->next.x = 0; 574 s->next.y++; 575 } 576 } 577 578 return result; 579 } 580 581 function s8 582 envp_lookup(s8 name, char **e) 583 { 584 ASSERT(name.data[name.len - 1] == '='); 585 586 s8 s, result = {0}; 587 for (; *e; e++) { 588 s = c_str_to_s8(*e); 589 if (s8_prefix_of(name, s)) 590 break; 591 } 592 593 if (*e) { 594 result = s; 595 result.len -= name.len; 596 result.data += name.len; 597 } 598 599 return result; 600 } 601 602 function c8 ** 603 construct_c_str_array(Arena *a, SLLVariableVector vars) 604 { 605 c8 **result = alloc(a, c8 *, vars.count + 1); 606 607 VariableLink *chain = vars.next; 608 for (u32 i = 0; i < vars.count; i++) { 609 ASSERT(chain->var->type == VT_S8); 610 result[i] = (c8 *)chain->var->s8.data; 611 chain = chain->next; 612 } 613 614 return result; 615 } 616 617 function b32 618 any_mouse_down(TerminalInput *input) 619 { 620 b32 result = input->keys[MOUSE_LEFT].ended_down || 621 input->keys[MOUSE_RIGHT].ended_down || 622 input->keys[MOUSE_MIDDLE].ended_down; 623 return result; 624 } 625 626 function b32 627 all_mouse_up(TerminalInput *input) 628 { 629 b32 result = !input->keys[MOUSE_LEFT].ended_down && 630 !input->keys[MOUSE_RIGHT].ended_down && 631 !input->keys[MOUSE_MIDDLE].ended_down; 632 return result; 633 } 634 635 function void 636 button_action(ButtonState *button, b32 pressed) 637 { 638 if (pressed != button->ended_down) 639 button->transitions++; 640 button->ended_down = pressed; 641 } 642 643 function b32 644 pressed_last_frame(ButtonState *button) 645 { 646 b32 result = (button->transitions > 1) || (button->ended_down && button->transitions == 1); 647 return result; 648 } 649 650 function s8 651 utf8_encode(u32 cp) 652 { 653 static u8 buf[4]; 654 s8 result = {.data = buf}; 655 if (cp <= 0x7F) { 656 result.len = 1; 657 buf[0] = cp & 0x7F; 658 } else if (cp <= 0x7FF) { 659 result.len = 2; 660 buf[0] = ((cp >> 6) & 0x1F) | 0xC0; 661 buf[1] = ((cp >> 0) & 0x3F) | 0x80; 662 } else if (cp <= 0xFFFF) { 663 result.len = 3; 664 buf[0] = ((cp >> 12) & 0x0F) | 0xE0; 665 buf[1] = ((cp >> 6) & 0x3F) | 0x80; 666 buf[2] = ((cp >> 0) & 0x3F) | 0x80; 667 } else if (cp <= 0x10FFFF) { 668 result.len = 4; 669 buf[0] = ((cp >> 18) & 0x07) | 0xF0; 670 buf[1] = ((cp >> 12) & 0x3F) | 0x80; 671 buf[2] = ((cp >> 6) & 0x3F) | 0x80; 672 buf[3] = ((cp >> 0) & 0x3F) | 0x80; 673 } else { 674 buf[0] = '?'; 675 result.len = 1; 676 } 677 return result; 678 } 679 680 #include "extern/utf8_decode.c"