@scriptc/cli-darwin-arm64 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/dist/THIRD_PARTY_NOTICES +1 -1
  2. package/dist/bin/scriptc +0 -0
  3. package/dist/bin/scriptc.json +1 -1
  4. package/dist/lib/declarations/scriptc-node-fallback.d.ts +915 -215
  5. package/dist/lib/declarations/scriptc-overrides.d.ts +5 -1
  6. package/dist/lib/declarations/scriptc.d.ts +22 -2
  7. package/dist/lib/llvm/bin/scriptc-llvm-codegen +0 -0
  8. package/dist/lib/llvm/package.json +1 -1
  9. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_array.o +0 -0
  10. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_bigint.o +0 -0
  11. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_bytes.o +0 -0
  12. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_bytes_io.o +0 -0
  13. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_copying.o +0 -0
  14. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_cycle.o +0 -0
  15. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_json.o +0 -0
  16. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_lib.o +0 -0
  17. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_map.o +0 -0
  18. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_number.o +0 -0
  19. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_regex.o +0 -0
  20. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_string.o +0 -0
  21. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_array.o +0 -0
  22. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_bigint.o +0 -0
  23. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_bytes.o +0 -0
  24. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_bytes_io.o +0 -0
  25. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_copying.o +0 -0
  26. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_cycle.o +0 -0
  27. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_json.o +0 -0
  28. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_lib.o +0 -0
  29. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_map.o +0 -0
  30. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_number.o +0 -0
  31. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_regex.o +0 -0
  32. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_string.o +0 -0
  33. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
  34. package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
  35. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_array.o +0 -0
  36. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_bigint.o +0 -0
  37. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_bytes.o +0 -0
  38. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_bytes_io.o +0 -0
  39. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_copying.o +0 -0
  40. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_cycle.o +0 -0
  41. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_json.o +0 -0
  42. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_lib.o +0 -0
  43. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_map.o +0 -0
  44. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_number.o +0 -0
  45. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_regex.o +0 -0
  46. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_string.o +0 -0
  47. package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
  48. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_array.o +0 -0
  49. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_bigint.o +0 -0
  50. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_bytes.o +0 -0
  51. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_bytes_io.o +0 -0
  52. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_copying.o +0 -0
  53. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_cycle.o +0 -0
  54. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_json.o +0 -0
  55. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_lib.o +0 -0
  56. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_map.o +0 -0
  57. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_number.o +0 -0
  58. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_regex.o +0 -0
  59. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_string.o +0 -0
  60. package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
  61. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_array.o +0 -0
  62. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_bigint.o +0 -0
  63. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_bytes.o +0 -0
  64. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_bytes_io.o +0 -0
  65. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_copying.o +0 -0
  66. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_cycle.o +0 -0
  67. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_json.o +0 -0
  68. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_lib.o +0 -0
  69. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_map.o +0 -0
  70. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_number.o +0 -0
  71. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_regex.o +0 -0
  72. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_string.o +0 -0
  73. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
  74. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_array.o +0 -0
  75. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_bigint.o +0 -0
  76. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_bytes.o +0 -0
  77. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_bytes_io.o +0 -0
  78. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_copying.o +0 -0
  79. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_cycle.o +0 -0
  80. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_json.o +0 -0
  81. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_lib.o +0 -0
  82. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_map.o +0 -0
  83. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_number.o +0 -0
  84. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_regex.o +0 -0
  85. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_string.o +0 -0
  86. package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
  87. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_array.o +0 -0
  88. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_bigint.o +0 -0
  89. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_bytes.o +0 -0
  90. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_bytes_io.o +0 -0
  91. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_copying.o +0 -0
  92. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_cycle.o +0 -0
  93. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_json.o +0 -0
  94. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_lib.o +0 -0
  95. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_map.o +0 -0
  96. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_number.o +0 -0
  97. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_regex.o +0 -0
  98. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_string.o +0 -0
  99. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_util_compare.o +0 -0
  100. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_array.o +0 -0
  101. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_bigint.o +0 -0
  102. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_bytes.o +0 -0
  103. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_bytes_io.o +0 -0
  104. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_copying.o +0 -0
  105. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_cycle.o +0 -0
  106. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_json.o +0 -0
  107. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_lib.o +0 -0
  108. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_map.o +0 -0
  109. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_number.o +0 -0
  110. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_regex.o +0 -0
  111. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_string.o +0 -0
  112. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_util_compare.o +0 -0
  113. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
  114. package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
  115. package/dist/lib/runtime-darwin-arm64/package.json +1 -1
  116. package/dist/lib/runtime-darwin-arm64/runtime-pack.json +213 -213
  117. package/dist/lib/runtime-sources/package.json +1 -1
  118. package/dist/lib/runtime-sources/src/scr_array.c +317 -40
  119. package/dist/lib/runtime-sources/src/scr_async.test.ts +16 -6
  120. package/dist/lib/runtime-sources/src/scr_bigint.c +15 -0
  121. package/dist/lib/runtime-sources/src/scr_bytes.c +437 -216
  122. package/dist/lib/runtime-sources/src/scr_bytes.test.c +85 -0
  123. package/dist/lib/runtime-sources/src/scr_bytes_io.c +0 -34
  124. package/dist/lib/runtime-sources/src/scr_copying.c +12 -2
  125. package/dist/lib/runtime-sources/src/scr_cycle.c +84 -60
  126. package/dist/lib/runtime-sources/src/scr_json.c +494 -161
  127. package/dist/lib/runtime-sources/src/scr_json.test.c +323 -1
  128. package/dist/lib/runtime-sources/src/scr_json.test.ts +58 -25
  129. package/dist/lib/runtime-sources/src/scr_key.h +68 -0
  130. package/dist/lib/runtime-sources/src/scr_lib.c +177 -89
  131. package/dist/lib/runtime-sources/src/scr_map.c +268 -96
  132. package/dist/lib/runtime-sources/src/scr_number.c +2 -4
  133. package/dist/lib/runtime-sources/src/scr_numeric.h +25 -0
  134. package/dist/lib/runtime-sources/src/scr_numeric.test.c +37 -0
  135. package/dist/lib/runtime-sources/src/scr_numeric.test.ts +33 -0
  136. package/dist/lib/runtime-sources/src/scr_regex.c +255 -145
  137. package/dist/lib/runtime-sources/src/scr_runtime.h +76 -19
  138. package/dist/lib/runtime-sources/src/scr_string.c +184 -42
  139. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scriptc/runtime",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "scriptc native runtime sources and vendored dependencies",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://scriptc.dev",
@@ -147,10 +147,14 @@ static void scr_arr_grow_dense(ScrArr *a, size_t need) {
147
147
  cap *= 2;
148
148
  }
149
149
  if (cap > SCR_ARR_DENSE_LIMIT) cap = SCR_ARR_DENSE_LIMIT;
150
- uint64_t *data = realloc(a->data, cap * sizeof(uint64_t));
150
+ /* Values and states share one allocation. Move the old states before
151
+ * publishing the larger capacity: their previous location is now part
152
+ * of the value area. Existing data and state pointers keep their ABI. */
153
+ if (cap > SIZE_MAX / (sizeof(uint64_t) + sizeof(uint8_t))) scr_arr_oom();
154
+ uint64_t *data = realloc(a->data, cap * (sizeof(uint64_t) + sizeof(uint8_t)));
151
155
  if (!data) scr_arr_oom();
152
- uint8_t *present = realloc(a->present, cap);
153
- if (!present) scr_arr_oom();
156
+ uint8_t *present = (uint8_t *)(data + cap);
157
+ if (a->cap) memmove(present, (uint8_t *)(data + a->cap), a->cap);
154
158
  memset(present + a->cap, 0, cap - a->cap);
155
159
  a->data = data;
156
160
  a->present = present;
@@ -397,11 +401,58 @@ static ScrArrStorage scr_arr_take_storage(ScrArr *a) {
397
401
 
398
402
  static void scr_arr_free_storage(ScrArrStorage *s) {
399
403
  free(s->data);
400
- free(s->present);
401
404
  free(s->sparse);
402
405
  memset(s, 0, sizeof(*s));
403
406
  }
404
407
 
408
+ /* Dense storage may still contain holes and explicit undefined. These
409
+ * operations move ownership with the slots and move the states alongside
410
+ * them; they never inspect an uninitialized hole payload. */
411
+ static bool scr_arr_is_dense(const ScrArr *a) {
412
+ return a->len <= a->cap && a->sparse_len == 0;
413
+ }
414
+
415
+ static void scr_arr_move_dense(ScrArr *a, size_t to, size_t from, size_t count) {
416
+ if (count == 0) return;
417
+ memmove(a->data + to, a->data + from, count * sizeof(*a->data));
418
+ memmove(a->present + to, a->present + from, count);
419
+ }
420
+
421
+ static void scr_arr_clear_dense(ScrArr *a, size_t from, size_t count) {
422
+ if (count == 0) return;
423
+ memset(a->present + from, SCR_ARR_HOLE, count);
424
+ memset(a->data + from, 0, count * sizeof(*a->data));
425
+ }
426
+
427
+ /* The destination owns no values in this range. Only retain adapters run
428
+ * while copying references: no release can collect an intermediate copy.
429
+ * Self-appends use disjoint ranges after reserving capacity. */
430
+ static void scr_arr_copy_dense(ScrArr *dst, size_t to, const ScrArr *src,
431
+ size_t from, size_t count, bool reverse,
432
+ bool materialize_holes) {
433
+ if (count == 0) return;
434
+ if (!reverse) {
435
+ memcpy(dst->data + to, src->data + from, count * sizeof(*dst->data));
436
+ memcpy(dst->present + to, src->present + from, count);
437
+ } else {
438
+ for (size_t i = 0; i < count; i++) {
439
+ size_t source = from + count - i - 1;
440
+ memcpy(dst->data + to + i, src->data + source, sizeof(*dst->data));
441
+ dst->present[to + i] = src->present[source];
442
+ }
443
+ }
444
+ bool refs = scr_elem_is_ref(src->elem);
445
+ if (!refs && !materialize_holes) return;
446
+ for (size_t i = to; i < to + count; i++) {
447
+ if (dst->present[i] == SCR_ARR_VALUE) {
448
+ if (refs) dst->data[i] = scr_elem_retain_slot(src, dst->data[i]);
449
+ } else if (materialize_holes && dst->present[i] == SCR_ARR_HOLE) {
450
+ dst->data[i] = 0;
451
+ dst->present[i] = SCR_ARR_UNDEFINED;
452
+ }
453
+ }
454
+ }
455
+
405
456
  ScrArr *scr_arr_new(ScrElemKind elem, size_t initial_cap) {
406
457
  ScrArr *a = malloc(sizeof(ScrArr));
407
458
  if (!a) scr_arr_oom();
@@ -434,8 +485,10 @@ ScrArr *scr_arr_new(ScrElemKind elem, size_t initial_cap) {
434
485
  * below releases none — the complement contract in scr_runtime.h. */
435
486
  void scr_arr_trace_v(void *a0, ScrTraceVisit visit, void *ctx) {
436
487
  ScrArr *a = (ScrArr *)a0;
437
- visit(a->metadata, ctx);
438
- for (size_t i = 0; i < a->cap; i++) {
488
+ if (a->metadata) visit(a->metadata, ctx);
489
+ /* Growth and truncation leave spare capacity empty. Sparse slots and
490
+ * named properties are separate edges, independent of dense length. */
491
+ for (size_t i = 0, end = a->len < a->cap ? a->len : a->cap; i < end; i++) {
439
492
  if (a->present[i] == SCR_ARR_VALUE) visit(scr_slot_to_ptr(a->data[i]), ctx);
440
493
  }
441
494
  for (size_t i = 0; i < a->sparse_len; i++) {
@@ -453,7 +506,6 @@ void scr_arr_trace_v(void *a0, ScrTraceVisit visit, void *ctx) {
453
506
  static void scr_arr_gc_free(void *a0) {
454
507
  ScrArr *a = (ScrArr *)a0;
455
508
  free(a->data);
456
- free(a->present);
457
509
  free(a->sparse);
458
510
  for (size_t i = 0; i < a->prop_len; i++) free(a->props[i].key);
459
511
  free(a->props);
@@ -503,7 +555,7 @@ void scr_arr_release(ScrArr *a) {
503
555
  scr_dyn_release(a->metadata);
504
556
  a->metadata = NULL;
505
557
  if (scr_elem_is_ref(a->elem)) {
506
- for (size_t i = 0; i < a->cap; i++) {
558
+ for (size_t i = 0, end = a->len < a->cap ? a->len : a->cap; i < end; i++) {
507
559
  if (a->present[i] != SCR_ARR_HOLE) {
508
560
  uint64_t old = a->data[i];
509
561
  uint8_t state = a->present[i];
@@ -532,7 +584,6 @@ void scr_arr_release(ScrArr *a) {
532
584
  scr_arr_gc_free(a);
533
585
  } else {
534
586
  free(a->data);
535
- free(a->present);
536
587
  free(a->sparse);
537
588
  for (size_t i = 0; i < a->prop_len; i++) free(a->props[i].key);
538
589
  free(a->props);
@@ -647,6 +698,16 @@ void scr_arr_copy_range_ex(ScrArr *dst, size_t dst_start, const ScrArr *src,
647
698
  size_t src_start, size_t count, bool reverse,
648
699
  bool materialize_holes) {
649
700
  if (count == 0) return;
701
+ if (src != dst && src_start <= src->cap && count <= src->cap - src_start &&
702
+ dst_start <= dst->cap && count <= dst->cap - dst_start) {
703
+ size_t empty = 0;
704
+ while (empty < count && dst->present[dst_start + empty] == SCR_ARR_HOLE) empty++;
705
+ if (empty == count) {
706
+ scr_arr_copy_dense(dst, dst_start, src, src_start, count, reverse,
707
+ materialize_holes);
708
+ return;
709
+ }
710
+ }
650
711
  size_t end = src_start + count;
651
712
  size_t dense_start = src_start < src->cap ? src_start : src->cap;
652
713
  size_t dense_end = end < src->cap ? end : src->cap;
@@ -676,6 +737,76 @@ void scr_arr_copy_range_ex(ScrArr *dst, size_t dst_start, const ScrArr *src,
676
737
  }
677
738
  }
678
739
 
740
+ static size_t scr_arr_relative_index(double value, size_t length) {
741
+ double integer = isnan(value) ? 0 : trunc(value);
742
+ if (integer < 0) integer += (double)length;
743
+ return integer <= 0 ? 0 : integer >= (double)length ? length : (size_t)integer;
744
+ }
745
+
746
+ ScrArr *scr_arr_copy_within(ScrArr *a, double target, double start, double end) {
747
+ size_t to = scr_arr_relative_index(target, a->len);
748
+ size_t from = scr_arr_relative_index(start, a->len);
749
+ size_t last = scr_arr_relative_index(end, a->len);
750
+ size_t count = last > from ? last - from : 0;
751
+ if (count > a->len - to) count = a->len - to;
752
+ if (count == 0 || from == to) return scr_arr_retain(a);
753
+ if (!scr_elem_is_ref(a->elem) && from < a->cap && count <= a->cap - from &&
754
+ to < a->cap && count <= a->cap - to) {
755
+ scr_arr_move_dense(a, to, from, count);
756
+ return scr_arr_retain(a);
757
+ }
758
+ bool backwards = from < to && to - from < count;
759
+ for (size_t i = 0; i < count; i++) {
760
+ size_t offset = backwards ? count - i - 1 : i;
761
+ uint64_t slot = 0;
762
+ uint8_t state = scr_arr_state_at(a, from + offset, &slot);
763
+ if (state == SCR_ARR_HOLE) {
764
+ scr_arr_delete(a, (double)(to + offset));
765
+ } else {
766
+ if (state == SCR_ARR_VALUE) slot = scr_elem_retain_slot(a, slot);
767
+ /* Each replacement publishes its edge before releasing the previous
768
+ * owner; cycle collection can run between successive positions. */
769
+ scr_arr_replace_state_owned(a, to + offset, slot, state);
770
+ }
771
+ }
772
+ return scr_arr_retain(a);
773
+ }
774
+
775
+ static ScrArr *scr_arr_fill_slot(ScrArr *a, uint64_t slot, uint8_t state,
776
+ double start, double end) {
777
+ size_t from = scr_arr_relative_index(start, a->len);
778
+ size_t until = scr_arr_relative_index(end, a->len);
779
+ if (from >= until) return scr_arr_retain(a);
780
+ bool refs = scr_elem_is_ref(a->elem);
781
+ if (!refs && until <= SCR_ARR_DENSE_LIMIT) {
782
+ scr_arr_grow_dense(a, until);
783
+ for (size_t i = from; i < until; i++) a->data[i] = slot;
784
+ memset(a->present + from, state, until - from);
785
+ } else {
786
+ for (size_t i = from; i < until; i++) {
787
+ uint64_t value = refs && state == SCR_ARR_VALUE ? scr_elem_retain_slot(a, slot) : slot;
788
+ scr_arr_replace_state_owned(a, i, value, state);
789
+ }
790
+ }
791
+ return scr_arr_retain(a);
792
+ }
793
+
794
+ ScrArr *scr_arr_fill_f64(ScrArr *a, double value, double start, double end) {
795
+ return scr_arr_fill_slot(a, scr_slot_from_f64(value), SCR_ARR_VALUE, start, end);
796
+ }
797
+
798
+ ScrArr *scr_arr_fill_bool(ScrArr *a, bool value, double start, double end) {
799
+ return scr_arr_fill_slot(a, value ? 1 : 0, SCR_ARR_VALUE, start, end);
800
+ }
801
+
802
+ ScrArr *scr_arr_fill_ref(ScrArr *a, void *value, double start, double end) {
803
+ return scr_arr_fill_slot(a, scr_slot_from_ptr(value), SCR_ARR_VALUE, start, end);
804
+ }
805
+
806
+ ScrArr *scr_arr_fill_undefined(ScrArr *a, double start, double end) {
807
+ return scr_arr_fill_slot(a, 0, SCR_ARR_UNDEFINED, start, end);
808
+ }
809
+
679
810
  /* ── Math.max/min over one spread number[] ─────────────────────────────
680
811
  * The JS fold exactly (ECMA Math.max/min applied to the elements): any
681
812
  * NaN poisons the result, +0 beats -0 for max (the reverse for min), and
@@ -922,10 +1053,33 @@ double scr_arr_push_ref(ScrArr *a, void *v) {
922
1053
  return scr_arr_push_slot(a, scr_slot_from_ptr(v));
923
1054
  }
924
1055
 
1056
+ double scr_arr_push_many(ScrArr *a, size_t count, const uint64_t *slots) {
1057
+ if (count > SCR_ARR_MAX_LENGTH - a->len) scr_arr_oom();
1058
+ size_t from = a->len, next = from + count;
1059
+ if (next <= SCR_ARR_DENSE_LIMIT) {
1060
+ scr_arr_grow_dense(a, next);
1061
+ if (count) {
1062
+ memcpy(a->data + from, slots, count * sizeof(*slots));
1063
+ memset(a->present + from, SCR_ARR_VALUE, count);
1064
+ }
1065
+ } else {
1066
+ for (size_t i = 0; i < count; i++) scr_arr_store_owned(a, from + i, slots[i]);
1067
+ }
1068
+ a->len = next;
1069
+ return (double)next;
1070
+ }
1071
+
925
1072
  double scr_arr_push_spread(ScrArr *a, const ScrArr *src) {
926
1073
  size_t old_len = a->len;
927
1074
  size_t add = src->len;
928
1075
  if (add > SCR_ARR_MAX_LENGTH - old_len) scr_arr_oom();
1076
+ if (scr_arr_is_dense(a) && scr_arr_is_dense(src) &&
1077
+ old_len + add <= SCR_ARR_DENSE_LIMIT) {
1078
+ scr_arr_grow_dense(a, old_len + add);
1079
+ scr_arr_copy_dense(a, old_len, src, 0, add, false, true);
1080
+ a->len += add;
1081
+ return (double)a->len;
1082
+ }
929
1083
  if (src == a) {
930
1084
  ScrArrStorage old = scr_arr_take_storage(a);
931
1085
  a->len = 0;
@@ -960,6 +1114,13 @@ double scr_arr_concat_copy(ScrArr *a, const ScrArr *src) {
960
1114
  size_t old_len = a->len;
961
1115
  size_t add = src->len;
962
1116
  if (add > SCR_ARR_MAX_LENGTH - old_len) scr_arr_oom();
1117
+ if (scr_arr_is_dense(a) && scr_arr_is_dense(src) &&
1118
+ old_len + add <= SCR_ARR_DENSE_LIMIT) {
1119
+ scr_arr_grow_dense(a, old_len + add);
1120
+ scr_arr_copy_dense(a, old_len, src, 0, add, false, false);
1121
+ a->len += add;
1122
+ return (double)a->len;
1123
+ }
963
1124
  if (src == a) {
964
1125
  ScrArrStorage old = scr_arr_take_storage(a);
965
1126
  a->len = 0;
@@ -1001,6 +1162,14 @@ static double scr_arr_unshift_slot(ScrArr *a, uint64_t slot) {
1001
1162
  scr_arr_trap_oob((double)a->len, a->len);
1002
1163
  }
1003
1164
  size_t old_len = a->len;
1165
+ if (scr_arr_is_dense(a) && old_len < SCR_ARR_DENSE_LIMIT) {
1166
+ scr_arr_grow_dense(a, old_len + 1);
1167
+ scr_arr_move_dense(a, 1, 0, old_len);
1168
+ a->data[0] = slot;
1169
+ a->present[0] = SCR_ARR_VALUE;
1170
+ a->len++;
1171
+ return (double)a->len;
1172
+ }
1004
1173
  ScrArrStorage old = scr_arr_take_storage(a);
1005
1174
  a->len = 0;
1006
1175
  scr_arr_store_owned(a, 0, slot);
@@ -1028,11 +1197,46 @@ double scr_arr_unshift_ref(ScrArr *a, void *v) {
1028
1197
  return scr_arr_unshift_slot(a, scr_slot_from_ptr(v));
1029
1198
  }
1030
1199
 
1200
+ double scr_arr_unshift_many(ScrArr *a, size_t count, const uint64_t *slots) {
1201
+ size_t old_len = a->len;
1202
+ if (count == 0) return (double)old_len;
1203
+ if (count > SCR_ARR_MAX_LENGTH - old_len) scr_arr_oom();
1204
+ if (scr_arr_is_dense(a) && old_len + count <= SCR_ARR_DENSE_LIMIT) {
1205
+ scr_arr_grow_dense(a, old_len + count);
1206
+ scr_arr_move_dense(a, count, 0, old_len);
1207
+ memcpy(a->data, slots, count * sizeof(*slots));
1208
+ memset(a->present, SCR_ARR_VALUE, count);
1209
+ } else {
1210
+ ScrArrStorage old = scr_arr_take_storage(a);
1211
+ for (size_t i = 0; i < count; i++) scr_arr_store_owned(a, i, slots[i]);
1212
+ for (size_t i = 0; i < old.cap; i++) {
1213
+ if (old.present[i] != SCR_ARR_HOLE)
1214
+ scr_arr_store_state_owned(a, i + count, old.data[i], old.present[i]);
1215
+ }
1216
+ for (size_t i = 0; i < old.sparse_len; i++) {
1217
+ scr_arr_store_state_owned(a, old.sparse[i].index + count,
1218
+ old.sparse[i].slot, old.sparse[i].state);
1219
+ }
1220
+ scr_arr_free_storage(&old);
1221
+ }
1222
+ a->len = old_len + count;
1223
+ return (double)a->len;
1224
+ }
1225
+
1031
1226
  double scr_arr_unshift_spread(ScrArr *a, const ScrArr *src) {
1032
1227
  size_t old_len = a->len;
1033
1228
  size_t add = src->len;
1034
1229
  if (add == 0) return (double)old_len;
1035
1230
  if (add > SCR_ARR_MAX_LENGTH - old_len) scr_arr_oom();
1231
+ if (scr_arr_is_dense(a) && scr_arr_is_dense(src) &&
1232
+ old_len + add <= SCR_ARR_DENSE_LIMIT) {
1233
+ scr_arr_grow_dense(a, old_len + add);
1234
+ scr_arr_move_dense(a, add, 0, old_len);
1235
+ /* A self-spread reads the original values at their moved location. */
1236
+ scr_arr_copy_dense(a, 0, src, src == a ? add : 0, add, false, true);
1237
+ a->len += add;
1238
+ return (double)a->len;
1239
+ }
1036
1240
  ScrArrStorage old = scr_arr_take_storage(a);
1037
1241
  a->len = 0;
1038
1242
  for (size_t i = 0; i < add; i++) {
@@ -1062,6 +1266,19 @@ double scr_arr_unshift_spread(ScrArr *a, const ScrArr *src) {
1062
1266
 
1063
1267
  ScrArr *scr_arr_reverse(ScrArr *a) {
1064
1268
  size_t len = a->len;
1269
+ if (scr_arr_is_dense(a)) {
1270
+ for (size_t i = 0; i < len / 2; i++) {
1271
+ size_t j = len - i - 1;
1272
+ uint64_t slot;
1273
+ memcpy(&slot, a->data + i, sizeof slot);
1274
+ memcpy(a->data + i, a->data + j, sizeof slot);
1275
+ memcpy(a->data + j, &slot, sizeof slot);
1276
+ uint8_t state = a->present[i];
1277
+ a->present[i] = a->present[j];
1278
+ a->present[j] = state;
1279
+ }
1280
+ return scr_arr_retain(a);
1281
+ }
1065
1282
  ScrArrStorage old = scr_arr_take_storage(a);
1066
1283
  a->len = len;
1067
1284
  for (size_t i = 0; i < old.cap; i++) {
@@ -1111,6 +1328,14 @@ uint8_t scr_arr_shift_state(ScrArr *a, uint64_t *slot_out) {
1111
1328
  if (slot_out) *slot_out = 0;
1112
1329
  if (a->len == 0) return SCR_ARR_HOLE;
1113
1330
  size_t old_len = a->len;
1331
+ if (scr_arr_is_dense(a)) {
1332
+ uint8_t state = a->present[0];
1333
+ if (slot_out && state == SCR_ARR_VALUE) *slot_out = a->data[0];
1334
+ scr_arr_move_dense(a, 0, 1, old_len - 1);
1335
+ scr_arr_clear_dense(a, old_len - 1, 1);
1336
+ a->len--;
1337
+ return state;
1338
+ }
1114
1339
  ScrArrStorage old = scr_arr_take_storage(a);
1115
1340
  uint64_t s = 0;
1116
1341
  uint8_t state = scr_arr_state_at_storage(&old, 0, &s);
@@ -1167,6 +1392,16 @@ ScrArr *scr_arr_splice(ScrArr *a, double start, double deleteCount) {
1167
1392
  : scr_arr_new(a->elem, n ? n : 1);
1168
1393
  out->len = n;
1169
1394
  size_t old_len = a->len;
1395
+ if (scr_arr_is_dense(a)) {
1396
+ if (n) {
1397
+ memcpy(out->data, a->data + from, n * sizeof(*a->data));
1398
+ memcpy(out->present, a->present + from, n);
1399
+ }
1400
+ scr_arr_move_dense(a, from, from + n, old_len - from - n);
1401
+ scr_arr_clear_dense(a, old_len - n, n);
1402
+ a->len -= n;
1403
+ return out;
1404
+ }
1170
1405
  ScrArrStorage old = scr_arr_take_storage(a);
1171
1406
  a->len = 0;
1172
1407
  for (size_t i = 0; i < old.cap; i++) {
@@ -1213,6 +1448,30 @@ ScrArr *scr_arr_splice_insert(ScrArr *a, double start, double deleteCount,
1213
1448
  double d0 = isnan(deleteCount) ? 0 : trunc(deleteCount);
1214
1449
  size_t n = d0 <= 0 ? 0 : d0 >= avail ? (size_t)avail : (size_t)d0;
1215
1450
  if (items->len > SCR_ARR_MAX_LENGTH - (a->len - n)) scr_arr_oom();
1451
+ size_t add = items->len, next_len = a->len - n + add;
1452
+ if (scr_arr_is_dense(a) && scr_arr_is_dense(items) &&
1453
+ next_len <= SCR_ARR_DENSE_LIMIT) {
1454
+ /* Snapshot an aliased argument before changing the receiver. Ordinary
1455
+ * callers have already materialized variadic arguments, so this copy
1456
+ * is needed only by direct self-spread runtime callers. */
1457
+ ScrArr *snapshot = items == a ? scr_arr_slice(a, 0, INFINITY) : NULL;
1458
+ if (snapshot) items = snapshot;
1459
+ ScrArr *removed = a->elem == SCR_ELEM_REF
1460
+ ? scr_arr_new_ref(a->elem_retain, a->elem_release, a->elem_trace, n)
1461
+ : scr_arr_new(a->elem, n);
1462
+ if (n) {
1463
+ memcpy(removed->data, a->data + from, n * sizeof(*a->data));
1464
+ memcpy(removed->present, a->present + from, n);
1465
+ }
1466
+ removed->len = n;
1467
+ scr_arr_grow_dense(a, next_len);
1468
+ scr_arr_move_dense(a, from + add, from + n, a->len - from - n);
1469
+ scr_arr_copy_dense(a, from, items, 0, add, false, true);
1470
+ if (next_len < a->len) scr_arr_clear_dense(a, next_len, a->len - next_len);
1471
+ a->len = next_len;
1472
+ scr_arr_release(snapshot);
1473
+ return removed;
1474
+ }
1216
1475
  ScrArr *removed = scr_arr_splice(a, start, deleteCount);
1217
1476
  ScrArr *tail = scr_arr_splice(a, (double)from, INFINITY);
1218
1477
  scr_arr_push_spread(a, items);
@@ -1333,21 +1592,26 @@ bool scr_arr_includes_ref(ScrArr *a, void *v) {
1333
1592
 
1334
1593
  /* ── join ──────────────────────────────────────────────────────────────── */
1335
1594
 
1336
- static void scr_join_append(char **buf, size_t *len, size_t *cap,
1337
- const char *bytes, size_t n) {
1338
- if (*len + n > *cap) {
1339
- size_t cap2 = *cap;
1340
- while (*len + n > cap2) {
1341
- if (cap2 > SIZE_MAX / 2) scr_arr_oom();
1342
- cap2 *= 2;
1343
- }
1344
- char *grown = realloc(*buf, cap2);
1345
- if (!grown) scr_arr_oom();
1346
- *buf = grown;
1347
- *cap = cap2;
1595
+ static size_t scr_join_size(size_t len, size_t extra) {
1596
+ if (extra > SIZE_MAX - sizeof(ScrStr) - 1 - len) scr_arr_oom();
1597
+ return len + extra;
1598
+ }
1599
+
1600
+ /* The builder owns the final string allocation throughout construction.
1601
+ * It has no aliases or index-cache entries, and no user callbacks run while
1602
+ * appending primitive array values. Finish by publishing the terminator. */
1603
+ static void scr_join_append(ScrStr **out, const char *bytes, size_t n) {
1604
+ ScrStr *s = *out;
1605
+ size_t need = scr_join_size(s->len, n);
1606
+ if (need > s->cap) {
1607
+ const size_t limit = SIZE_MAX - sizeof(ScrStr) - 1;
1608
+ size_t cap = s->cap;
1609
+ while (cap < need) cap = cap > limit / 2 ? need : cap * 2;
1610
+ s = scr_str_regrow(s, cap);
1611
+ *out = s;
1348
1612
  }
1349
- memcpy(*buf + *len, bytes, n);
1350
- *len += n;
1613
+ memcpy(s->data + s->len, bytes, n);
1614
+ s->len = need;
1351
1615
  }
1352
1616
 
1353
1617
  /* `a.slice(start?, end?)` — a fresh shallow copy of the index range,
@@ -1370,6 +1634,10 @@ ScrArr *scr_arr_slice(ScrArr *a, double start, double end) {
1370
1634
  ? scr_arr_new_ref(a->elem_retain, a->elem_release, a->elem_trace, n ? n : 1)
1371
1635
  : scr_arr_new(a->elem, n ? n : 1);
1372
1636
  out->len = n;
1637
+ if (to <= a->cap) {
1638
+ scr_arr_copy_dense(out, 0, a, from, n, false, false);
1639
+ return out;
1640
+ }
1373
1641
  for (size_t i = 0; i < a->cap && i < to; i++) {
1374
1642
  if (i < from || a->present[i] == SCR_ARR_HOLE) continue;
1375
1643
  uint8_t state = a->present[i];
@@ -1390,11 +1658,24 @@ ScrArr *scr_arr_slice(ScrArr *a, double start, double end) {
1390
1658
  }
1391
1659
 
1392
1660
  ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep) {
1393
- size_t cap = 64, len = 0;
1394
- char *buf = malloc(cap);
1395
- if (!buf) scr_arr_oom();
1661
+ size_t cap = 64;
1662
+ /* String widths are already known. Size once to avoid growth and copying
1663
+ * even when the array holds holes, explicit undefined or sparse slots.
1664
+ * Numeric formatting stays single-pass rather than formatting twice. */
1665
+ if (a->elem == SCR_ELEM_STR) {
1666
+ const size_t limit = SIZE_MAX - sizeof(ScrStr) - 1;
1667
+ if (a->len > 1 && sep->len > limit / (a->len - 1)) scr_arr_oom();
1668
+ cap = a->len > 1 ? (a->len - 1) * sep->len : 0;
1669
+ for (size_t i = 0; i < a->len; i++) {
1670
+ uint64_t slot;
1671
+ if (scr_arr_state_at(a, i, &slot) != SCR_ARR_VALUE) continue;
1672
+ const ScrStr *s = (const ScrStr *)scr_slot_to_ptr(slot);
1673
+ if (s) cap = scr_join_size(cap, s->len);
1674
+ }
1675
+ }
1676
+ ScrStr *out = scr_str_alloc_raw(0, cap);
1396
1677
  for (size_t i = 0; i < a->len; i++) {
1397
- if (i > 0) scr_join_append(&buf, &len, &cap, sep->data, sep->len);
1678
+ if (i > 0) scr_join_append(&out, sep->data, sep->len);
1398
1679
  uint64_t slot;
1399
1680
  uint8_t state = scr_arr_state_at(a, i, &slot);
1400
1681
  if (state != SCR_ARR_VALUE) continue;
@@ -1402,16 +1683,16 @@ ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep) {
1402
1683
  case SCR_ELEM_F64: {
1403
1684
  char nb[32];
1404
1685
  size_t n = scr_f64_to_str(scr_slot_to_f64(slot), nb);
1405
- scr_join_append(&buf, &len, &cap, nb, n);
1686
+ scr_join_append(&out, nb, n);
1406
1687
  break;
1407
1688
  }
1408
1689
  case SCR_ELEM_BOOL:
1409
- if (slot != 0) scr_join_append(&buf, &len, &cap, "true", 4);
1410
- else scr_join_append(&buf, &len, &cap, "false", 5);
1690
+ if (slot != 0) scr_join_append(&out, "true", 4);
1691
+ else scr_join_append(&out, "false", 5);
1411
1692
  break;
1412
1693
  case SCR_ELEM_STR: {
1413
1694
  const ScrStr *s = (const ScrStr *)scr_slot_to_ptr(slot);
1414
- if (s) scr_join_append(&buf, &len, &cap, s->data, s->len);
1695
+ if (s) scr_join_append(&out, s->data, s->len);
1415
1696
  break;
1416
1697
  }
1417
1698
  case SCR_ELEM_ARR:
@@ -1421,8 +1702,7 @@ ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep) {
1421
1702
  scr_trap("scriptc: internal error: join on a ref-element array\n");
1422
1703
  }
1423
1704
  }
1424
- ScrStr *out = scr_str_new(buf, len);
1425
- free(buf);
1705
+ out->data[out->len] = '\0';
1426
1706
  return out;
1427
1707
  }
1428
1708
 
@@ -1432,25 +1712,22 @@ ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep) {
1432
1712
  * missing ones skip, exactly the spec's loop. Both arrays are
1433
1713
  * SCR_ELEM_STR; borrows both; +1 result. Never throws. */
1434
1714
  ScrStr *scr_str_raw(ScrArr *raw, ScrArr *subs) {
1435
- size_t cap = 64, len = 0;
1436
- char *buf = malloc(cap);
1437
- if (!buf) scr_arr_oom();
1715
+ ScrStr *out = scr_str_alloc_raw(0, 64);
1438
1716
  for (size_t i = 0; i < raw->len; i++) {
1439
1717
  uint64_t raw_slot;
1440
1718
  if (scr_arr_slot_at(raw, i, &raw_slot)) {
1441
1719
  const ScrStr *s = (const ScrStr *)scr_slot_to_ptr(raw_slot);
1442
- if (s) scr_join_append(&buf, &len, &cap, s->data, s->len);
1720
+ if (s) scr_join_append(&out, s->data, s->len);
1443
1721
  }
1444
1722
  if (i + 1 < raw->len && i < subs->len) {
1445
1723
  uint64_t sub_slot;
1446
1724
  if (scr_arr_slot_at(subs, i, &sub_slot)) {
1447
1725
  const ScrStr *v = (const ScrStr *)scr_slot_to_ptr(sub_slot);
1448
- if (v) scr_join_append(&buf, &len, &cap, v->data, v->len);
1726
+ if (v) scr_join_append(&out, v->data, v->len);
1449
1727
  }
1450
1728
  }
1451
1729
  }
1452
- ScrStr *out = scr_str_new(buf, len);
1453
- free(buf);
1730
+ out->data[out->len] = '\0';
1454
1731
  return out;
1455
1732
  }
1456
1733
 
@@ -14,20 +14,30 @@ test("fiber stacks commit on demand and preserve large frames across suspension"
14
14
  try {
15
15
  const bin = join(dir, "fiber-stacks");
16
16
  await execFileAsync("clang", [
17
- "-std=c11", "-O1", "-Wall", "-Wextra", "-Wno-deprecated-declarations",
17
+ "-std=c11",
18
+ "-O1",
19
+ "-Wall",
20
+ "-Wextra",
21
+ "-Wno-deprecated-declarations",
18
22
  "-pthread",
19
23
  ...(sanitize ? ["-fsanitize=address,undefined", "-DSCR_RC_AUDIT"] : []),
20
24
  ...(process.platform === "linux" ? ["-D_GNU_SOURCE"] : []),
21
25
  join(import.meta.dirname, "scr_async.test.c"),
22
- ...EXECUTABLE_RUNTIME_SOURCES
23
- .filter((name) => name !== "scr_async.c")
24
- .map((name) => join(import.meta.dirname, name)),
26
+ ...EXECUTABLE_RUNTIME_SOURCES.filter((name) => name !== "scr_async.c").map((name) =>
27
+ join(import.meta.dirname, name),
28
+ ),
25
29
  ...(process.platform === "linux" ? ["-lm"] : []),
26
- "-o", bin,
30
+ "-o",
31
+ bin,
27
32
  ]);
28
33
  const result = await execFileAsync(bin);
29
34
  expect(result.stdout).toBe("fiber stacks stay lazy and preserve large suspended frames\n");
30
- expect(result.stderr.replace(/^==\d+==WARNING: ASan doesn't fully support makecontext\/swapcontext.*\n/gm, "")).toBe("");
35
+ expect(
36
+ result.stderr.replace(
37
+ /^==\d+==WARNING: ASan doesn't fully support makecontext\/swapcontext.*\n/gm,
38
+ "",
39
+ ),
40
+ ).toBe("");
31
41
  } finally {
32
42
  await rm(dir, { recursive: true, force: true });
33
43
  }
@@ -132,6 +132,21 @@ static int bi_cmp(const ScrBigInt *a, const ScrBigInt *b) {
132
132
  }
133
133
 
134
134
  bool scr_bigint_eq(ScrBigInt *a, ScrBigInt *b) { return bi_cmp(a, b) == 0; }
135
+
136
+ uint64_t scr_bigint_hash(const ScrBigInt *value) {
137
+ /* BigInts are immutable and normalized. Ignore capacity and ownership;
138
+ * equal values made by parsing, arithmetic or conversion hash alike. */
139
+ uint64_t hash = UINT64_C(0xcbf29ce484222325) ^ (uint64_t)(value->sign + 1);
140
+ for (size_t i = 0; i < value->len; i++) {
141
+ hash ^= value->limb[i];
142
+ hash *= UINT64_C(0x100000001b3);
143
+ }
144
+ hash ^= hash >> 30;
145
+ hash *= UINT64_C(0xbf58476d1ce4e5b9);
146
+ hash ^= hash >> 27;
147
+ hash *= UINT64_C(0x94d049bb133111eb);
148
+ return hash ^ (hash >> 31);
149
+ }
135
150
  double scr_bigint_cmp_f64(ScrBigInt *a, ScrBigInt *b) { return (double)bi_cmp(a, b); }
136
151
  bool scr_bigint_truthy(ScrBigInt *v) { return v->sign != 0; }
137
152