@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.
- package/dist/THIRD_PARTY_NOTICES +1 -1
- package/dist/bin/scriptc +0 -0
- package/dist/bin/scriptc.json +1 -1
- package/dist/lib/declarations/scriptc-node-fallback.d.ts +915 -215
- package/dist/lib/declarations/scriptc-overrides.d.ts +5 -1
- package/dist/lib/declarations/scriptc.d.ts +22 -2
- package/dist/lib/llvm/bin/scriptc-llvm-codegen +0 -0
- package/dist/lib/llvm/package.json +1 -1
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-arm64/package.json +1 -1
- package/dist/lib/runtime-darwin-arm64/runtime-pack.json +213 -213
- package/dist/lib/runtime-sources/package.json +1 -1
- package/dist/lib/runtime-sources/src/scr_array.c +317 -40
- package/dist/lib/runtime-sources/src/scr_async.test.ts +16 -6
- package/dist/lib/runtime-sources/src/scr_bigint.c +15 -0
- package/dist/lib/runtime-sources/src/scr_bytes.c +437 -216
- package/dist/lib/runtime-sources/src/scr_bytes.test.c +85 -0
- package/dist/lib/runtime-sources/src/scr_bytes_io.c +0 -34
- package/dist/lib/runtime-sources/src/scr_copying.c +12 -2
- package/dist/lib/runtime-sources/src/scr_cycle.c +84 -60
- package/dist/lib/runtime-sources/src/scr_json.c +494 -161
- package/dist/lib/runtime-sources/src/scr_json.test.c +323 -1
- package/dist/lib/runtime-sources/src/scr_json.test.ts +58 -25
- package/dist/lib/runtime-sources/src/scr_key.h +68 -0
- package/dist/lib/runtime-sources/src/scr_lib.c +177 -89
- package/dist/lib/runtime-sources/src/scr_map.c +268 -96
- package/dist/lib/runtime-sources/src/scr_number.c +2 -4
- package/dist/lib/runtime-sources/src/scr_numeric.h +25 -0
- package/dist/lib/runtime-sources/src/scr_numeric.test.c +37 -0
- package/dist/lib/runtime-sources/src/scr_numeric.test.ts +33 -0
- package/dist/lib/runtime-sources/src/scr_regex.c +255 -145
- package/dist/lib/runtime-sources/src/scr_runtime.h +76 -19
- package/dist/lib/runtime-sources/src/scr_string.c +184 -42
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* keep the lean 1-word header and never touch the collector.
|
|
16
16
|
*/
|
|
17
17
|
#include "scr_runtime.h"
|
|
18
|
+
#include "scr_key.h"
|
|
18
19
|
|
|
19
20
|
#include <stdio.h>
|
|
20
21
|
#include <stdlib.h>
|
|
@@ -46,17 +47,14 @@ static uint64_t scr_map_f64_bits(double k) {
|
|
|
46
47
|
return bits;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
static uint64_t
|
|
50
|
-
|
|
51
|
-
for (size_t i = 0; i < n; i++) {
|
|
52
|
-
h ^= bytes[i];
|
|
53
|
-
h *= UINT64_C(0x100000001b3);
|
|
54
|
-
}
|
|
55
|
-
return h;
|
|
50
|
+
static uint64_t scr_map_hash_str(const ScrStr *k) {
|
|
51
|
+
return scr_key_hash(k->data, k->len);
|
|
56
52
|
}
|
|
57
53
|
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
/* Mix the complete normalized number or identity word. Float exponents
|
|
55
|
+
* and aligned pointers need high bits to reach the low bucket-index bits. */
|
|
56
|
+
static uint64_t scr_map_hash_word(uint64_t value) {
|
|
57
|
+
return scr_key_mix(value);
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
/* ── slot packing (8-byte slots, like ScrArr) ──────────────────────────── */
|
|
@@ -98,12 +96,7 @@ static uint64_t scr_map_hash_dyn(const ScrDyn *d) {
|
|
|
98
96
|
case SCR_DYN_NULL: value = 0; break;
|
|
99
97
|
case SCR_DYN_BOOL: value = d->v.b; break;
|
|
100
98
|
case SCR_DYN_NUM: value = scr_map_f64_bits(d->v.num); break;
|
|
101
|
-
case SCR_DYN_BIGINT:
|
|
102
|
-
ScrStr *text = scr_bigint_to_string(d->v.bigint, 10);
|
|
103
|
-
uint64_t hash = scr_map_hash_str(text);
|
|
104
|
-
scr_str_release(text);
|
|
105
|
-
return hash;
|
|
106
|
-
}
|
|
99
|
+
case SCR_DYN_BIGINT: return scr_bigint_hash(d->v.bigint);
|
|
107
100
|
case SCR_DYN_STR: return scr_map_hash_str(d->v.str);
|
|
108
101
|
case SCR_DYN_SYMBOL: value = scr_map_slot_from_ptr(d->v.symbol.value); break;
|
|
109
102
|
case SCR_DYN_FUNC: value = scr_map_slot_from_ptr(d->v.fn.class_obj ? (void *)d->v.fn.class_obj : (void *)d->v.fn.clo); break;
|
|
@@ -122,7 +115,7 @@ static uint64_t scr_map_hash_dyn(const ScrDyn *d) {
|
|
|
122
115
|
case SCR_DYN_JSVAL: value = 0; break;
|
|
123
116
|
default: value = scr_map_slot_from_ptr((void *)d); break;
|
|
124
117
|
}
|
|
125
|
-
return
|
|
118
|
+
return scr_map_hash_word(value) ^ kind;
|
|
126
119
|
}
|
|
127
120
|
|
|
128
121
|
static bool scr_map_dyn_eq(const ScrDyn *a, const ScrDyn *b) {
|
|
@@ -135,16 +128,50 @@ static bool scr_map_dyn_eq(const ScrDyn *a, const ScrDyn *b) {
|
|
|
135
128
|
return scr_dyn_strict_eq(a, b);
|
|
136
129
|
}
|
|
137
130
|
|
|
131
|
+
static uint64_t scr_map_hash_union(const ScrMap *m, const ScrUnion *key) {
|
|
132
|
+
ScrMapKeyKind kind = (ScrMapKeyKind)m->union_keys[key->tag];
|
|
133
|
+
switch (kind) {
|
|
134
|
+
case SCR_MAP_KEY_STR: return scr_map_hash_str(scr_union_peek(key));
|
|
135
|
+
case SCR_MAP_KEY_BIGINT: return scr_bigint_hash(scr_union_peek(key));
|
|
136
|
+
case SCR_MAP_KEY_F64: return scr_map_hash_word(scr_map_f64_bits(scr_map_slot_to_f64(key->slot)));
|
|
137
|
+
case SCR_MAP_KEY_NULL:
|
|
138
|
+
case SCR_MAP_KEY_UNDEFINED: return scr_map_hash_word((uint64_t)kind);
|
|
139
|
+
default: return scr_map_hash_word(key->slot);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
static bool scr_map_union_eq(const ScrMap *m, const ScrUnion *a, const ScrUnion *b) {
|
|
144
|
+
ScrMapKeyKind kind = (ScrMapKeyKind)m->union_keys[a->tag];
|
|
145
|
+
if (kind != (ScrMapKeyKind)m->union_keys[b->tag]) return false;
|
|
146
|
+
switch (kind) {
|
|
147
|
+
case SCR_MAP_KEY_STR: return scr_str_eq(scr_union_peek(a), scr_union_peek(b));
|
|
148
|
+
case SCR_MAP_KEY_BIGINT: return scr_bigint_eq(scr_union_peek(a), scr_union_peek(b));
|
|
149
|
+
case SCR_MAP_KEY_F64:
|
|
150
|
+
return scr_map_f64_bits(scr_map_slot_to_f64(a->slot)) == scr_map_f64_bits(scr_map_slot_to_f64(b->slot));
|
|
151
|
+
case SCR_MAP_KEY_NULL:
|
|
152
|
+
case SCR_MAP_KEY_UNDEFINED: return true;
|
|
153
|
+
default: return a->slot == b->slot;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
138
157
|
static uint64_t scr_map_hash_key(const ScrMap *m, uint64_t key) {
|
|
139
158
|
if (m->key_kind == SCR_MAP_KEY_STR) return scr_map_hash_str((ScrStr *)scr_map_slot_to_ptr(key));
|
|
140
159
|
if (m->key_kind == SCR_MAP_KEY_DYN) return scr_map_hash_dyn((ScrDyn *)scr_map_slot_to_ptr(key));
|
|
160
|
+
if (m->key_kind == SCR_MAP_KEY_BIGINT) return scr_bigint_hash(scr_map_slot_to_ptr(key));
|
|
161
|
+
if (m->key_kind == SCR_MAP_KEY_UNION_VALUE) return scr_map_hash_union(m, scr_map_slot_to_ptr(key));
|
|
141
162
|
uint64_t identity = scr_map_identity(m, key);
|
|
142
|
-
return
|
|
163
|
+
return scr_map_hash_word(identity);
|
|
143
164
|
}
|
|
144
165
|
|
|
145
166
|
/* Stored keys are pre-normalized, so bit equality IS SameValueZero for f64
|
|
146
167
|
* keys (probe keys normalize through the same function). */
|
|
147
168
|
static bool scr_map_key_eq(const ScrMap *m, uint64_t stored, uint64_t probe) {
|
|
169
|
+
if (m->key_kind == SCR_MAP_KEY_UNION_VALUE) {
|
|
170
|
+
return scr_map_union_eq(m, scr_map_slot_to_ptr(stored), scr_map_slot_to_ptr(probe));
|
|
171
|
+
}
|
|
172
|
+
if (m->key_kind == SCR_MAP_KEY_BIGINT) {
|
|
173
|
+
return scr_bigint_eq(scr_map_slot_to_ptr(stored), scr_map_slot_to_ptr(probe));
|
|
174
|
+
}
|
|
148
175
|
if (m->key_kind == SCR_MAP_KEY_DYN) {
|
|
149
176
|
return scr_map_dyn_eq((ScrDyn *)scr_map_slot_to_ptr(stored), (ScrDyn *)scr_map_slot_to_ptr(probe));
|
|
150
177
|
}
|
|
@@ -156,16 +183,34 @@ static bool scr_map_key_eq(const ScrMap *m, uint64_t stored, uint64_t probe) {
|
|
|
156
183
|
}
|
|
157
184
|
|
|
158
185
|
/* ── lookup ────────────────────────────────────────────────────────────
|
|
159
|
-
* Returns the
|
|
160
|
-
*
|
|
161
|
-
|
|
186
|
+
* Returns the matching bucket, or the empty bucket where a new key belongs.
|
|
187
|
+
* A zero entry hash marks a tombstone; cached hashes reject unrelated keys
|
|
188
|
+
* before equality and survive table growth without hashing the keys again.
|
|
189
|
+
* Remap zero to one so every live entry has a nonzero hash. */
|
|
190
|
+
static size_t scr_map_probe(const ScrMap *m, uint64_t hash, uint64_t key) {
|
|
162
191
|
if (m->nbuckets == 0) return SCR_MAP_EMPTY;
|
|
163
192
|
size_t mask = m->nbuckets - 1;
|
|
164
193
|
for (size_t i = hash & mask;; i = (i + 1) & mask) {
|
|
165
194
|
size_t b = m->buckets[i];
|
|
166
|
-
if (b == SCR_MAP_EMPTY) return
|
|
167
|
-
if (m->entries[b].
|
|
195
|
+
if (b == SCR_MAP_EMPTY) return i;
|
|
196
|
+
if (m->entries[b].hash == hash && scr_map_key_eq(m, m->entries[b].key, key)) return i;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
#define SCR_MAP_LINEAR_LIMIT 4
|
|
201
|
+
|
|
202
|
+
/* Small collections keep only their ordered entries. Cached hashes make
|
|
203
|
+
* the bounded scan cheap without allocating a separate bucket table. */
|
|
204
|
+
static size_t scr_map_find(const ScrMap *m, uint64_t hash, uint64_t key) {
|
|
205
|
+
hash = hash ? hash : 1;
|
|
206
|
+
if (m->nbuckets == 0) {
|
|
207
|
+
for (size_t e = 0; e < m->nentries; e++) {
|
|
208
|
+
if (m->entries[e].hash == hash && scr_map_key_eq(m, m->entries[e].key, key)) return e;
|
|
209
|
+
}
|
|
210
|
+
return SCR_MAP_EMPTY;
|
|
168
211
|
}
|
|
212
|
+
size_t slot = scr_map_probe(m, hash, key);
|
|
213
|
+
return slot == SCR_MAP_EMPTY ? SCR_MAP_EMPTY : m->buckets[slot];
|
|
169
214
|
}
|
|
170
215
|
|
|
171
216
|
/* Rebuild the bucket table (size must be a power of two >= 2 * nentries):
|
|
@@ -179,8 +224,8 @@ static void scr_map_rebuild_buckets(ScrMap *m, size_t nbuckets) {
|
|
|
179
224
|
m->nbuckets = nbuckets;
|
|
180
225
|
size_t mask = nbuckets - 1;
|
|
181
226
|
for (size_t e = 0; e < m->nentries; e++) {
|
|
182
|
-
|
|
183
|
-
|
|
227
|
+
uint64_t hash = m->entries[e].hash;
|
|
228
|
+
if (!hash) continue;
|
|
184
229
|
size_t i = hash & mask;
|
|
185
230
|
while (buckets[i] != SCR_MAP_EMPTY) i = (i + 1) & mask;
|
|
186
231
|
buckets[i] = e;
|
|
@@ -192,7 +237,7 @@ static void scr_map_rebuild_buckets(ScrMap *m, size_t nbuckets) {
|
|
|
192
237
|
static void scr_map_compact(ScrMap *m) {
|
|
193
238
|
size_t w = 0;
|
|
194
239
|
for (size_t r = 0; r < m->nentries; r++) {
|
|
195
|
-
if (m->entries[r].
|
|
240
|
+
if (m->entries[r].hash) m->entries[w++] = m->entries[r];
|
|
196
241
|
}
|
|
197
242
|
m->nentries = w;
|
|
198
243
|
if (m->nbuckets > 0) scr_map_rebuild_buckets(m, m->nbuckets);
|
|
@@ -202,12 +247,15 @@ static void scr_map_compact(ScrMap *m) {
|
|
|
202
247
|
* reuse their storage) and grows otherwise; while an iteration is active it
|
|
203
248
|
* ONLY grows — indices must stay stable under callback mutation. */
|
|
204
249
|
static void scr_map_reserve_append(ScrMap *m) {
|
|
205
|
-
if (m->nentries < m->ecap &&
|
|
206
|
-
|
|
250
|
+
if (m->nentries < m->ecap &&
|
|
251
|
+
((m->nbuckets == 0 && m->nentries < SCR_MAP_LINEAR_LIMIT) ||
|
|
252
|
+
m->nbuckets >= 2 * (m->nentries + 1))) return;
|
|
253
|
+
if (m->iter_depth == 0 && m->nentries > 0 &&
|
|
254
|
+
(m->nbuckets == 0 ? m->nlive < m->nentries : m->nlive <= m->nentries / 2)) {
|
|
207
255
|
scr_map_compact(m);
|
|
208
256
|
}
|
|
209
257
|
if (m->nentries == m->ecap) {
|
|
210
|
-
size_t cap = m->ecap ? m->ecap :
|
|
258
|
+
size_t cap = m->ecap ? m->ecap : 4;
|
|
211
259
|
while (cap < m->nentries + 1) {
|
|
212
260
|
if (cap > SIZE_MAX / 2 / sizeof(ScrMapEntry)) scr_map_oom();
|
|
213
261
|
cap *= 2;
|
|
@@ -217,6 +265,7 @@ static void scr_map_reserve_append(ScrMap *m) {
|
|
|
217
265
|
m->entries = entries;
|
|
218
266
|
m->ecap = cap;
|
|
219
267
|
}
|
|
268
|
+
if (m->nbuckets == 0 && m->nentries < SCR_MAP_LINEAR_LIMIT) return;
|
|
220
269
|
if (m->nbuckets < 2 * (m->nentries + 1)) {
|
|
221
270
|
size_t nbuckets = m->nbuckets ? m->nbuckets : 16;
|
|
222
271
|
while (nbuckets < 2 * (m->nentries + 1)) {
|
|
@@ -229,10 +278,15 @@ static void scr_map_reserve_append(ScrMap *m) {
|
|
|
229
278
|
|
|
230
279
|
/* ── entry release helpers ─────────────────────────────────────────────── */
|
|
231
280
|
|
|
281
|
+
static bool scr_map_ref_key(ScrMapKeyKind kind) {
|
|
282
|
+
return kind == SCR_MAP_KEY_REF || kind == SCR_MAP_KEY_UNION_REF || kind == SCR_MAP_KEY_DYN ||
|
|
283
|
+
kind == SCR_MAP_KEY_BIGINT || kind == SCR_MAP_KEY_UNION_VALUE;
|
|
284
|
+
}
|
|
285
|
+
|
|
232
286
|
static void scr_map_release_key(ScrMap *m, uint64_t key) {
|
|
233
287
|
if (m->key_kind == SCR_MAP_KEY_STR) {
|
|
234
288
|
scr_str_release((ScrStr *)scr_map_slot_to_ptr(key));
|
|
235
|
-
} else if (m->key_kind
|
|
289
|
+
} else if (scr_map_ref_key(m->key_kind)) {
|
|
236
290
|
m->key_release(scr_map_slot_to_ptr(key));
|
|
237
291
|
}
|
|
238
292
|
}
|
|
@@ -243,10 +297,14 @@ static void scr_map_release_val(ScrMap *m, uint64_t val) {
|
|
|
243
297
|
|
|
244
298
|
/* ── lifecycle ─────────────────────────────────────────────────────────── */
|
|
245
299
|
|
|
300
|
+
void scr_map_union_keys(ScrMap *map, const uint8_t *kinds) {
|
|
301
|
+
map->union_keys = kinds;
|
|
302
|
+
}
|
|
303
|
+
|
|
246
304
|
static void scr_map_trace(void *o, ScrTraceVisit visit, void *ctx) {
|
|
247
305
|
ScrMap *m = (ScrMap *)o;
|
|
248
306
|
for (size_t e = 0; e < m->nentries; e++) {
|
|
249
|
-
if (!m->entries[e].
|
|
307
|
+
if (!m->entries[e].hash) continue;
|
|
250
308
|
if (m->key_trace) visit(scr_map_slot_to_ptr(m->entries[e].key), ctx);
|
|
251
309
|
if (m->val_trace) visit(scr_map_slot_to_ptr(m->entries[e].val), ctx);
|
|
252
310
|
}
|
|
@@ -258,7 +316,7 @@ static void scr_map_gcfree(void *o) {
|
|
|
258
316
|
ScrMap *m = (ScrMap *)o;
|
|
259
317
|
scr_weak_dispose(m);
|
|
260
318
|
for (size_t e = 0; e < m->nentries; e++) {
|
|
261
|
-
if (!m->entries[e].
|
|
319
|
+
if (!m->entries[e].hash) continue;
|
|
262
320
|
if (!m->key_trace) scr_map_release_key(m, m->entries[e].key);
|
|
263
321
|
if (!m->val_trace) scr_map_release_val(m, m->entries[e].val);
|
|
264
322
|
}
|
|
@@ -318,7 +376,7 @@ void scr_map_release(ScrMap *m) {
|
|
|
318
376
|
scr_weak_dispose(m);
|
|
319
377
|
if (m->key_trace || m->val_trace) scr_cyc_on_dead(m);
|
|
320
378
|
for (size_t e = 0; e < m->nentries; e++) {
|
|
321
|
-
if (!m->entries[e].
|
|
379
|
+
if (!m->entries[e].hash) continue;
|
|
322
380
|
scr_map_release_key(m, m->entries[e].key);
|
|
323
381
|
scr_map_release_val(m, m->entries[e].val);
|
|
324
382
|
}
|
|
@@ -344,8 +402,8 @@ double scr_map_size(const ScrMap *m) { return (double)m->nlive; }
|
|
|
344
402
|
|
|
345
403
|
void scr_map_clear(ScrMap *m) {
|
|
346
404
|
for (size_t e = 0; e < m->nentries; e++) {
|
|
347
|
-
if (!m->entries[e].
|
|
348
|
-
m->entries[e].
|
|
405
|
+
if (!m->entries[e].hash) continue;
|
|
406
|
+
m->entries[e].hash = 0;
|
|
349
407
|
scr_map_release_key(m, m->entries[e].key);
|
|
350
408
|
scr_map_release_val(m, m->entries[e].val);
|
|
351
409
|
}
|
|
@@ -363,7 +421,7 @@ void scr_map_clear(ScrMap *m) {
|
|
|
363
421
|
|
|
364
422
|
bool scr_map_has_f64(const ScrMap *m, double key) {
|
|
365
423
|
uint64_t k = scr_map_f64_bits(key);
|
|
366
|
-
return scr_map_find(m,
|
|
424
|
+
return scr_map_find(m, scr_map_hash_word(k), k) != SCR_MAP_EMPTY;
|
|
367
425
|
}
|
|
368
426
|
|
|
369
427
|
bool scr_map_has_str(const ScrMap *m, const ScrStr *key) {
|
|
@@ -373,7 +431,7 @@ bool scr_map_has_str(const ScrMap *m, const ScrStr *key) {
|
|
|
373
431
|
|
|
374
432
|
static bool scr_map_delete_found(ScrMap *m, size_t e) {
|
|
375
433
|
if (e == SCR_MAP_EMPTY) return false;
|
|
376
|
-
m->entries[e].
|
|
434
|
+
m->entries[e].hash = 0; /* bucket slot stays: probe chains intact */
|
|
377
435
|
m->nlive--;
|
|
378
436
|
scr_map_release_key(m, m->entries[e].key);
|
|
379
437
|
scr_map_release_val(m, m->entries[e].val);
|
|
@@ -382,7 +440,7 @@ static bool scr_map_delete_found(ScrMap *m, size_t e) {
|
|
|
382
440
|
|
|
383
441
|
bool scr_map_delete_f64(ScrMap *m, double key) {
|
|
384
442
|
uint64_t k = scr_map_f64_bits(key);
|
|
385
|
-
return scr_map_delete_found(m, scr_map_find(m,
|
|
443
|
+
return scr_map_delete_found(m, scr_map_find(m, scr_map_hash_word(k), k));
|
|
386
444
|
}
|
|
387
445
|
|
|
388
446
|
bool scr_map_delete_str(ScrMap *m, const ScrStr *key) {
|
|
@@ -412,18 +470,28 @@ bool scr_map_delete_ref(ScrMap *m, const void *key) {
|
|
|
412
470
|
* insertion slot. */
|
|
413
471
|
|
|
414
472
|
static void scr_map_set(ScrMap *m, uint64_t hash, uint64_t key, uint64_t val) {
|
|
415
|
-
|
|
473
|
+
hash = hash ? hash : 1;
|
|
474
|
+
size_t slot = scr_map_probe(m, hash, key);
|
|
475
|
+
size_t e = m->nbuckets == 0 ? scr_map_find(m, hash, key) : m->buckets[slot];
|
|
416
476
|
if (e != SCR_MAP_EMPTY) {
|
|
417
477
|
uint64_t old = m->entries[e].val;
|
|
418
478
|
m->entries[e].val = val; /* unlink before releasing (cycle collector) */
|
|
419
479
|
scr_map_release_val(m, old);
|
|
420
480
|
return;
|
|
421
481
|
}
|
|
482
|
+
size_t old_entries = m->nentries, old_buckets = m->nbuckets;
|
|
422
483
|
scr_map_reserve_append(m);
|
|
484
|
+
/* Growth or compaction can move the insertion bucket. Otherwise keep the
|
|
485
|
+
* empty slot from the first probe instead of walking the chain twice. */
|
|
486
|
+
if (m->nbuckets && (m->nentries != old_entries || m->nbuckets != old_buckets)) {
|
|
487
|
+
size_t mask = m->nbuckets - 1;
|
|
488
|
+
slot = hash & mask;
|
|
489
|
+
while (m->buckets[slot] != SCR_MAP_EMPTY) slot = (slot + 1) & mask;
|
|
490
|
+
}
|
|
423
491
|
size_t idx = m->nentries++;
|
|
424
492
|
m->entries[idx].key = key;
|
|
425
493
|
m->entries[idx].val = val;
|
|
426
|
-
m->entries[idx].
|
|
494
|
+
m->entries[idx].hash = hash;
|
|
427
495
|
m->nlive++;
|
|
428
496
|
if (m->key_kind == SCR_MAP_KEY_STR) {
|
|
429
497
|
scr_str_retain((ScrStr *)scr_map_slot_to_ptr(key)); /* key is borrowed */
|
|
@@ -436,18 +504,21 @@ static void scr_map_set(ScrMap *m, uint64_t hash, uint64_t key, uint64_t val) {
|
|
|
436
504
|
} else {
|
|
437
505
|
m->key_retain(scr_map_slot_to_ptr(key));
|
|
438
506
|
}
|
|
439
|
-
} else if (m->key_kind ==
|
|
507
|
+
} else if (m->key_kind == SCR_MAP_KEY_UNION_VALUE &&
|
|
508
|
+
m->union_keys[((ScrUnion *)scr_map_slot_to_ptr(key))->tag] == SCR_MAP_KEY_F64 &&
|
|
509
|
+
((ScrUnion *)scr_map_slot_to_ptr(key))->slot == UINT64_C(0x8000000000000000)) {
|
|
510
|
+
/* Normalize stored -0 without mutating the caller's immutable box. */
|
|
511
|
+
ScrUnion *u = scr_map_slot_to_ptr(key);
|
|
512
|
+
m->entries[idx].key = scr_map_slot_from_ptr(scr_union_new_f64(u->tag, 0));
|
|
513
|
+
} else if (scr_map_ref_key(m->key_kind)) {
|
|
440
514
|
m->key_retain(scr_map_slot_to_ptr(key)); /* key is borrowed */
|
|
441
515
|
}
|
|
442
|
-
|
|
443
|
-
size_t i = hash & mask;
|
|
444
|
-
while (m->buckets[i] != SCR_MAP_EMPTY) i = (i + 1) & mask;
|
|
445
|
-
m->buckets[i] = idx;
|
|
516
|
+
if (m->nbuckets) m->buckets[slot] = idx;
|
|
446
517
|
}
|
|
447
518
|
|
|
448
519
|
static void scr_map_set_f64_key(ScrMap *m, double key, uint64_t val) {
|
|
449
520
|
uint64_t k = scr_map_f64_bits(key); /* stores +0 for -0, canonical NaN */
|
|
450
|
-
scr_map_set(m,
|
|
521
|
+
scr_map_set(m, scr_map_hash_word(k), k, val);
|
|
451
522
|
}
|
|
452
523
|
|
|
453
524
|
static void scr_map_set_str_key(ScrMap *m, ScrStr *key, uint64_t val) {
|
|
@@ -501,7 +572,7 @@ ScrMap *scr_set_new_ref(void *(*elem_retain)(void *), void (*elem_release)(void
|
|
|
501
572
|
|
|
502
573
|
static size_t scr_map_find_f64(const ScrMap *m, double key) {
|
|
503
574
|
uint64_t k = scr_map_f64_bits(key);
|
|
504
|
-
return scr_map_find(m,
|
|
575
|
+
return scr_map_find(m, scr_map_hash_word(k), k);
|
|
505
576
|
}
|
|
506
577
|
|
|
507
578
|
static size_t scr_map_find_str(const ScrMap *m, const ScrStr *key) {
|
|
@@ -568,17 +639,63 @@ void *scr_map_get_ref_ref(const ScrMap *m, const void *key) {
|
|
|
568
639
|
return m->val_retain(scr_map_slot_to_ptr(m->entries[e].val));
|
|
569
640
|
}
|
|
570
641
|
|
|
642
|
+
/* Boolean keys use unboxed 0/1 slots and the same probe path. */
|
|
643
|
+
static size_t scr_map_find_bool(const ScrMap *m, bool key) {
|
|
644
|
+
uint64_t slot = key ? 1 : 0;
|
|
645
|
+
return scr_map_find(m, scr_map_hash_word(slot), slot);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
bool scr_map_has_bool(const ScrMap *m, bool key) {
|
|
649
|
+
return scr_map_find_bool(m, key) != SCR_MAP_EMPTY;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
bool scr_map_delete_bool(ScrMap *m, bool key) {
|
|
653
|
+
return scr_map_delete_found(m, scr_map_find_bool(m, key));
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
void scr_map_set_bool_f64(ScrMap *m, bool key, double value) {
|
|
657
|
+
scr_map_set(m, scr_map_hash_word(key ? 1 : 0), key ? 1 : 0, scr_map_slot_from_f64(value));
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
void scr_map_set_bool_bool(ScrMap *m, bool key, bool value) {
|
|
661
|
+
scr_map_set(m, scr_map_hash_word(key ? 1 : 0), key ? 1 : 0, value ? 1 : 0);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
void scr_map_set_bool_ref(ScrMap *m, bool key, void *value) {
|
|
665
|
+
scr_map_set(m, scr_map_hash_word(key ? 1 : 0), key ? 1 : 0, scr_map_slot_from_ptr(value));
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
bool scr_map_get_bool_f64(const ScrMap *m, bool key, double *out) {
|
|
669
|
+
size_t entry = scr_map_find_bool(m, key);
|
|
670
|
+
if (entry == SCR_MAP_EMPTY) return false;
|
|
671
|
+
*out = scr_map_slot_to_f64(m->entries[entry].val);
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
bool scr_map_get_bool_bool(const ScrMap *m, bool key, bool *out) {
|
|
676
|
+
size_t entry = scr_map_find_bool(m, key);
|
|
677
|
+
if (entry == SCR_MAP_EMPTY) return false;
|
|
678
|
+
*out = m->entries[entry].val != 0;
|
|
679
|
+
return true;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
void *scr_map_get_bool_ref(const ScrMap *m, bool key) {
|
|
683
|
+
size_t entry = scr_map_find_bool(m, key);
|
|
684
|
+
if (entry == SCR_MAP_EMPTY) return NULL;
|
|
685
|
+
return m->val_retain(scr_map_slot_to_ptr(m->entries[entry].val));
|
|
686
|
+
}
|
|
687
|
+
|
|
571
688
|
/* ── iteration primitives (the forEach desugar) ────────────────────────── */
|
|
572
689
|
|
|
573
690
|
double scr_map_iter_count(const ScrMap *m) { return (double)m->nentries; }
|
|
574
691
|
|
|
575
692
|
bool scr_map_iter_live(const ScrMap *m, double i) {
|
|
576
693
|
if (!(i >= 0) || i >= (double)m->nentries) return false;
|
|
577
|
-
return m->entries[(size_t)i].
|
|
694
|
+
return m->entries[(size_t)i].hash;
|
|
578
695
|
}
|
|
579
696
|
|
|
580
697
|
static const ScrMapEntry *scr_map_iter_at(const ScrMap *m, double i) {
|
|
581
|
-
if (!(i >= 0) || i >= (double)m->nentries || !m->entries[(size_t)i].
|
|
698
|
+
if (!(i >= 0) || i >= (double)m->nentries || !m->entries[(size_t)i].hash) {
|
|
582
699
|
scr_trap("scriptc: internal error: map iteration index out of range\n");
|
|
583
700
|
}
|
|
584
701
|
return &m->entries[(size_t)i];
|
|
@@ -588,6 +705,10 @@ double scr_map_iter_key_f64(const ScrMap *m, double i) {
|
|
|
588
705
|
return scr_map_slot_to_f64(scr_map_iter_at(m, i)->key);
|
|
589
706
|
}
|
|
590
707
|
|
|
708
|
+
bool scr_map_iter_key_bool(const ScrMap *m, double i) {
|
|
709
|
+
return scr_map_iter_at(m, i)->key != 0;
|
|
710
|
+
}
|
|
711
|
+
|
|
591
712
|
ScrStr *scr_map_iter_key_str(const ScrMap *m, double i) {
|
|
592
713
|
return scr_str_retain((ScrStr *)scr_map_slot_to_ptr(scr_map_iter_at(m, i)->key));
|
|
593
714
|
}
|
|
@@ -649,6 +770,68 @@ void scr_map_dyn_set(ScrMap *map, const ScrDyn *key, const ScrDyn *value, bool s
|
|
|
649
770
|
scr_map_release_key(map, key_slot);
|
|
650
771
|
}
|
|
651
772
|
|
|
773
|
+
/* Copy only live entries. The source is borrowed, contains unique keys,
|
|
774
|
+
* and runs no user code while traversed, so cached hashes remain valid. */
|
|
775
|
+
ScrMap *scr_map_clone(const ScrMap *source, bool keys_only) {
|
|
776
|
+
ScrMap *out = scr_map_new_typed(source->key_kind, keys_only ? SCR_MAP_VAL_F64 : source->val_kind,
|
|
777
|
+
source->key_retain, source->key_release, source->key_trace,
|
|
778
|
+
keys_only ? NULL : source->val_retain, keys_only ? NULL : source->val_release,
|
|
779
|
+
keys_only ? NULL : source->val_trace);
|
|
780
|
+
out->union_keys = source->union_keys;
|
|
781
|
+
size_t count = source->nlive;
|
|
782
|
+
if (!count) return out;
|
|
783
|
+
if (count > SIZE_MAX / sizeof(ScrMapEntry) || count > SIZE_MAX / 2 / sizeof(size_t)) scr_map_oom();
|
|
784
|
+
out->entries = malloc(count * sizeof(ScrMapEntry));
|
|
785
|
+
if (!out->entries) scr_map_oom();
|
|
786
|
+
out->ecap = count;
|
|
787
|
+
for (size_t i = 0; i < source->nentries; i++) {
|
|
788
|
+
const ScrMapEntry *entry = &source->entries[i];
|
|
789
|
+
if (!entry->hash) continue;
|
|
790
|
+
ScrMapEntry *copy = &out->entries[out->nentries++];
|
|
791
|
+
*copy = *entry;
|
|
792
|
+
if (out->key_kind == SCR_MAP_KEY_STR) scr_str_retain(scr_map_slot_to_ptr(copy->key));
|
|
793
|
+
else if (scr_map_ref_key(out->key_kind)) out->key_retain(scr_map_slot_to_ptr(copy->key));
|
|
794
|
+
if (keys_only) copy->val = 0;
|
|
795
|
+
else if (out->val_kind == SCR_MAP_VAL_REF) out->val_retain(scr_map_slot_to_ptr(copy->val));
|
|
796
|
+
}
|
|
797
|
+
out->nlive = count;
|
|
798
|
+
if (count <= SCR_MAP_LINEAR_LIMIT) return out;
|
|
799
|
+
size_t buckets = 16;
|
|
800
|
+
while (buckets < 2 * count) {
|
|
801
|
+
if (buckets > SIZE_MAX / 2 / sizeof(size_t)) scr_map_oom();
|
|
802
|
+
buckets *= 2;
|
|
803
|
+
}
|
|
804
|
+
scr_map_rebuild_buckets(out, buckets);
|
|
805
|
+
return out;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/* A generic view can be backed by typed slots. Its copy must accept new
|
|
809
|
+
* JavaScript values independently of that backing's narrower adapters. */
|
|
810
|
+
ScrMap *scr_map_clone_dyn(const ScrMap *source, bool keys_only) {
|
|
811
|
+
ScrMap *out = scr_map_new_typed(SCR_MAP_KEY_DYN, keys_only ? SCR_MAP_VAL_F64 : SCR_MAP_VAL_REF,
|
|
812
|
+
scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v,
|
|
813
|
+
keys_only ? NULL : scr_dyn_retain_v, keys_only ? NULL : scr_dyn_release_v,
|
|
814
|
+
keys_only ? NULL : scr_dyn_trace_v);
|
|
815
|
+
for (size_t i = 0; i < source->nentries; i++) {
|
|
816
|
+
if (!source->entries[i].hash) continue;
|
|
817
|
+
ScrDyn *key = scr_map_dyn_key(source, (double)i);
|
|
818
|
+
uint64_t value = keys_only ? 0 : scr_map_slot_from_ptr(scr_map_dyn_value(source, (double)i));
|
|
819
|
+
scr_map_set(out, scr_map_hash_dyn(key), scr_map_slot_from_ptr(key), value);
|
|
820
|
+
scr_dyn_release(key);
|
|
821
|
+
}
|
|
822
|
+
return out;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
void scr_map_values_into(ScrMap *set, const ScrMap *source, bool checked) {
|
|
826
|
+
for (size_t i = 0; i < source->nentries; i++) {
|
|
827
|
+
if (!source->entries[i].hash) continue;
|
|
828
|
+
uint64_t value = checked ? scr_map_slot_from_ptr(scr_map_dyn_value(source, (double)i)) : source->entries[i].val;
|
|
829
|
+
if (set->key_kind == SCR_MAP_KEY_F64) value = scr_map_f64_bits(scr_map_slot_to_f64(value));
|
|
830
|
+
scr_map_set(set, scr_map_hash_key(set, value), value, 0);
|
|
831
|
+
if (checked) scr_dyn_release(scr_map_slot_to_ptr(value));
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
652
835
|
ScrArr *scr_set_to_arr_dyn(const ScrMap *map) {
|
|
653
836
|
ScrArr *out = scr_arr_new_ref(scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v, map->nlive);
|
|
654
837
|
for (size_t i = 0; i < map->nentries; i++) {
|
|
@@ -683,14 +866,23 @@ void scr_map_iter_exit(ScrMap *m) {
|
|
|
683
866
|
void scr_set_add_all(ScrMap *set, ScrArr *values) {
|
|
684
867
|
size_t n = values->len;
|
|
685
868
|
for (size_t i = 0; i < n; i++) {
|
|
686
|
-
|
|
869
|
+
/* Packed values stay owned by the seed array throughout construction.
|
|
870
|
+
* Avoid taking a temporary owner only to release it after insertion.
|
|
871
|
+
* Sparse/missing positions retain the existing accessor semantics. */
|
|
872
|
+
if (i < values->cap && values->present[i] == SCR_ARR_VALUE) {
|
|
873
|
+
uint64_t key = values->data[i];
|
|
874
|
+
if (set->key_kind == SCR_MAP_KEY_F64) key = scr_map_f64_bits(scr_map_slot_to_f64(key));
|
|
875
|
+
scr_map_set(set, scr_map_hash_key(set, key), key, 0);
|
|
876
|
+
} else if (values->elem == SCR_ELEM_STR) {
|
|
687
877
|
ScrStr *s = (ScrStr *)scr_arr_get_ref(values, (double)i); /* +1 */
|
|
688
878
|
scr_map_set_str_f64(set, s, 0); /* borrows; retains stored copy */
|
|
689
879
|
scr_str_release(s);
|
|
690
|
-
} else if (set->key_kind
|
|
880
|
+
} else if (scr_map_ref_key(set->key_kind)) {
|
|
691
881
|
void *p = scr_arr_get_ref(values, (double)i); /* +1 */
|
|
692
882
|
scr_map_set_ref_f64(set, p, 0); /* borrows; retains stored copy */
|
|
693
883
|
set->key_release(p);
|
|
884
|
+
} else if (set->key_kind == SCR_MAP_KEY_BOOL) {
|
|
885
|
+
scr_map_set_bool_f64(set, scr_arr_get_bool(values, (double)i), 0);
|
|
694
886
|
} else {
|
|
695
887
|
scr_map_set_f64_f64(set, scr_arr_get_f64(values, (double)i), 0);
|
|
696
888
|
}
|
|
@@ -702,59 +894,39 @@ void scr_set_add_all(ScrMap *set, ScrArr *values) {
|
|
|
702
894
|
/* Canonical array index test: "0".."4294967294" — digits only, no leading
|
|
703
895
|
* zero (except "0" itself), value <= 2^32 - 2. JS orders these OWN keys
|
|
704
896
|
* first, ascending numerically, before every other string key. */
|
|
705
|
-
static bool scr_map_key_array_index(const ScrStr *
|
|
706
|
-
|
|
707
|
-
if (n == 0 || n > 10) return false;
|
|
708
|
-
const char *s = k->data;
|
|
709
|
-
if (s[0] == '0' && n > 1) return false;
|
|
710
|
-
uint64_t v = 0;
|
|
711
|
-
for (size_t i = 0; i < n; i++) {
|
|
712
|
-
if (s[i] < '0' || s[i] > '9') return false;
|
|
713
|
-
v = v * 10 + (uint64_t)(s[i] - '0');
|
|
714
|
-
}
|
|
715
|
-
if (v > UINT64_C(4294967294)) return false;
|
|
716
|
-
*out = (uint32_t)v;
|
|
717
|
-
return true;
|
|
897
|
+
static bool scr_map_key_array_index(const ScrStr *key, uint32_t *out) {
|
|
898
|
+
return scr_key_array_index(key->data, key->len, out);
|
|
718
899
|
}
|
|
719
900
|
|
|
720
|
-
/*
|
|
721
|
-
*
|
|
722
|
-
* first in ascending numeric order, then the rest in insertion order.
|
|
723
|
-
* Returns a fresh ScrStr* array (+1); the map is borrowed. Insertion sort
|
|
724
|
-
* over the integer-like subset — overflow maps are small, and ties are
|
|
725
|
-
* impossible (keys are unique). */
|
|
901
|
+
/* Enumerate numeric keys in ascending order, then other keys in insertion
|
|
902
|
+
* order. Scratch entries refer to stable map indices, not copied strings. */
|
|
726
903
|
ScrArr *scr_map_keys_js_order(const ScrMap *m) {
|
|
727
|
-
size_t n = m->nentries;
|
|
728
904
|
ScrArr *out = scr_arr_new(SCR_ELEM_STR, m->nlive);
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
if (
|
|
737
|
-
|
|
738
|
-
|
|
905
|
+
if (m->nlive > SIZE_MAX / sizeof(ScrKeyIndex)) scr_map_oom();
|
|
906
|
+
ScrKeyIndex *indices = NULL;
|
|
907
|
+
size_t count = 0;
|
|
908
|
+
for (size_t i = 0; i < m->nentries; i++) {
|
|
909
|
+
if (!m->entries[i].hash) continue;
|
|
910
|
+
ScrStr *key = scr_map_slot_to_ptr(m->entries[i].key);
|
|
911
|
+
uint32_t index;
|
|
912
|
+
if (!scr_map_key_array_index(key, &index)) continue;
|
|
913
|
+
if (!indices) {
|
|
914
|
+
indices = malloc(m->nlive * sizeof *indices);
|
|
915
|
+
if (!indices) scr_map_oom();
|
|
739
916
|
}
|
|
740
|
-
|
|
741
|
-
while (j > 0 && idx[j - 1].v > v) {
|
|
742
|
-
idx[j] = idx[j - 1];
|
|
743
|
-
j--;
|
|
744
|
-
}
|
|
745
|
-
idx[j].v = v;
|
|
746
|
-
idx[j].k = k;
|
|
917
|
+
indices[count++] = (ScrKeyIndex){index, i};
|
|
747
918
|
}
|
|
748
|
-
|
|
749
|
-
|
|
919
|
+
scr_key_index_sort(indices, count);
|
|
920
|
+
for (size_t i = 0; i < count; i++) {
|
|
921
|
+
ScrStr *key = scr_map_slot_to_ptr(m->entries[indices[i].entry].key);
|
|
922
|
+
scr_arr_push_ref(out, scr_str_retain(key));
|
|
750
923
|
}
|
|
751
|
-
free(
|
|
752
|
-
for (size_t i = 0; i <
|
|
753
|
-
if (!m->entries[i].
|
|
754
|
-
ScrStr *
|
|
755
|
-
uint32_t
|
|
756
|
-
if (scr_map_key_array_index(
|
|
757
|
-
scr_arr_push_ref(out, scr_str_retain(k));
|
|
924
|
+
free(indices);
|
|
925
|
+
for (size_t i = 0; i < m->nentries; i++) {
|
|
926
|
+
if (!m->entries[i].hash) continue;
|
|
927
|
+
ScrStr *key = scr_map_slot_to_ptr(m->entries[i].key);
|
|
928
|
+
uint32_t index;
|
|
929
|
+
if (!scr_map_key_array_index(key, &index)) scr_arr_push_ref(out, scr_str_retain(key));
|
|
758
930
|
}
|
|
759
931
|
return out;
|
|
760
932
|
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* and the 1M-double fuzz gate (packages/runtime/test/gen-number-cases.mjs).
|
|
15
15
|
*/
|
|
16
16
|
#include "scr_runtime.h"
|
|
17
|
+
#include "scr_numeric.h"
|
|
17
18
|
|
|
18
19
|
#include <math.h>
|
|
19
20
|
#include <stdint.h>
|
|
@@ -27,10 +28,7 @@
|
|
|
27
28
|
/* ECMA ToUint32, shared by bitwise operators and split's limit: non-finite
|
|
28
29
|
* values become zero, finite values truncate toward zero and wrap mod 2^32. */
|
|
29
30
|
uint32_t scr_to_uint32(double d) {
|
|
30
|
-
|
|
31
|
-
double t = fmod(trunc(d), 4294967296.0);
|
|
32
|
-
if (t < 0) t += 4294967296.0;
|
|
33
|
-
return (uint32_t)t;
|
|
31
|
+
return scr_numeric_to_u32(d);
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
/* ── bitwise operators ─────────────────────────────────────────────────
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* Internal numeric coercions shared by scalar operators and typed storage. */
|
|
2
|
+
#ifndef SCR_NUMERIC_H
|
|
3
|
+
#define SCR_NUMERIC_H
|
|
4
|
+
#include <float.h>
|
|
5
|
+
#include <stdint.h>
|
|
6
|
+
#include <string.h>
|
|
7
|
+
|
|
8
|
+
_Static_assert(sizeof(double) == sizeof(uint64_t) && DBL_MANT_DIG == 53 && DBL_MAX_EXP == 1024,
|
|
9
|
+
"numeric coercions require binary64 doubles");
|
|
10
|
+
|
|
11
|
+
/* ToUint32 truncates toward zero and keeps the low 32 bits. Reading the
|
|
12
|
+
* binary64 exponent also handles non-finite values without floating modulo.
|
|
13
|
+
* Subnormals have magnitude below one; exponents >= 84 have no low bits. */
|
|
14
|
+
static inline uint32_t scr_numeric_to_u32(double value) {
|
|
15
|
+
uint64_t bits;
|
|
16
|
+
memcpy(&bits, &value, sizeof bits);
|
|
17
|
+
unsigned exponent = (unsigned)((bits >> 52) & 0x7ff);
|
|
18
|
+
if (exponent < 1023 || exponent >= 1023 + 84) return 0;
|
|
19
|
+
unsigned shift = exponent - 1023;
|
|
20
|
+
uint64_t significand = (bits & UINT64_C(0x000fffffffffffff)) | UINT64_C(0x0010000000000000);
|
|
21
|
+
uint32_t integer = shift >= 52 ? (uint32_t)(significand << (shift - 52))
|
|
22
|
+
: (uint32_t)(significand >> (52 - shift));
|
|
23
|
+
return bits >> 63 ? UINT32_C(0) - integer : integer;
|
|
24
|
+
}
|
|
25
|
+
#endif
|