@shd101wyy/yo 0.1.26 → 0.1.27

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 (167) hide show
  1. package/.github/skills/yo-async-effects/SKILL.md +4 -4
  2. package/.github/skills/yo-async-effects/async-effects-recipes.md +34 -34
  3. package/.github/skills/yo-core-patterns/SKILL.md +1 -1
  4. package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +26 -26
  5. package/.github/skills/yo-project-workflow/SKILL.md +6 -3
  6. package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +34 -11
  7. package/.github/skills/yo-syntax/SKILL.md +7 -6
  8. package/.github/skills/yo-syntax/syntax-cheatsheet.md +73 -60
  9. package/.github/skills/yo-wasm-integration/wasm-integration-cheatsheet.md +3 -3
  10. package/README.md +10 -8
  11. package/out/cjs/index.cjs +456 -438
  12. package/out/cjs/yo-cli.cjs +576 -543
  13. package/out/cjs/yo-lsp.cjs +559 -532
  14. package/out/esm/index.mjs +281 -263
  15. package/out/types/src/formatter.d.ts +11 -0
  16. package/out/types/src/lsp/formatting.d.ts +2 -0
  17. package/out/types/src/tests/formatter.test.d.ts +1 -0
  18. package/out/types/tsconfig.tsbuildinfo +1 -1
  19. package/package.json +1 -1
  20. package/std/alg/hash.yo +13 -21
  21. package/std/allocator.yo +25 -40
  22. package/std/async.yo +3 -7
  23. package/std/build.yo +105 -151
  24. package/std/cli/arg_parser.yo +184 -169
  25. package/std/collections/array_list.yo +350 -314
  26. package/std/collections/btree_map.yo +142 -131
  27. package/std/collections/deque.yo +132 -128
  28. package/std/collections/hash_map.yo +542 -566
  29. package/std/collections/hash_set.yo +623 -687
  30. package/std/collections/linked_list.yo +275 -293
  31. package/std/collections/ordered_map.yo +113 -85
  32. package/std/collections/priority_queue.yo +73 -73
  33. package/std/crypto/md5.yo +191 -95
  34. package/std/crypto/random.yo +56 -64
  35. package/std/crypto/sha256.yo +151 -107
  36. package/std/encoding/base64.yo +87 -81
  37. package/std/encoding/hex.yo +43 -50
  38. package/std/encoding/html.yo +56 -81
  39. package/std/encoding/html_char_utils.yo +7 -13
  40. package/std/encoding/html_entities.yo +2248 -2253
  41. package/std/encoding/json.yo +316 -224
  42. package/std/encoding/punycode.yo +86 -116
  43. package/std/encoding/toml.yo +67 -66
  44. package/std/encoding/utf16.yo +37 -44
  45. package/std/env.yo +62 -91
  46. package/std/error.yo +7 -15
  47. package/std/fmt/display.yo +5 -9
  48. package/std/fmt/index.yo +8 -14
  49. package/std/fmt/to_string.yo +330 -315
  50. package/std/fmt/writer.yo +58 -87
  51. package/std/fs/dir.yo +83 -102
  52. package/std/fs/file.yo +147 -180
  53. package/std/fs/metadata.yo +45 -78
  54. package/std/fs/temp.yo +55 -65
  55. package/std/fs/types.yo +27 -40
  56. package/std/fs/walker.yo +53 -68
  57. package/std/gc.yo +5 -8
  58. package/std/glob.yo +30 -43
  59. package/std/http/client.yo +107 -120
  60. package/std/http/http.yo +106 -96
  61. package/std/http/index.yo +4 -6
  62. package/std/imm/list.yo +88 -93
  63. package/std/imm/map.yo +528 -464
  64. package/std/imm/set.yo +52 -57
  65. package/std/imm/sorted_map.yo +340 -286
  66. package/std/imm/sorted_set.yo +57 -63
  67. package/std/imm/string.yo +404 -345
  68. package/std/imm/vec.yo +173 -181
  69. package/std/io/reader.yo +3 -6
  70. package/std/io/writer.yo +4 -8
  71. package/std/libc/assert.yo +5 -9
  72. package/std/libc/ctype.yo +32 -22
  73. package/std/libc/dirent.yo +26 -25
  74. package/std/libc/errno.yo +164 -90
  75. package/std/libc/fcntl.yo +52 -45
  76. package/std/libc/float.yo +66 -44
  77. package/std/libc/limits.yo +42 -33
  78. package/std/libc/math.yo +53 -82
  79. package/std/libc/signal.yo +72 -47
  80. package/std/libc/stdatomic.yo +217 -188
  81. package/std/libc/stdint.yo +5 -29
  82. package/std/libc/stdio.yo +5 -29
  83. package/std/libc/stdlib.yo +32 -39
  84. package/std/libc/string.yo +5 -23
  85. package/std/libc/sys/stat.yo +58 -56
  86. package/std/libc/time.yo +5 -19
  87. package/std/libc/unistd.yo +5 -20
  88. package/std/libc/wctype.yo +6 -9
  89. package/std/libc/windows.yo +26 -30
  90. package/std/log.yo +41 -55
  91. package/std/net/addr.yo +102 -97
  92. package/std/net/dns.yo +27 -28
  93. package/std/net/errors.yo +50 -49
  94. package/std/net/tcp.yo +113 -124
  95. package/std/net/udp.yo +55 -66
  96. package/std/os/env.yo +35 -33
  97. package/std/os/signal.yo +15 -25
  98. package/std/path.yo +276 -311
  99. package/std/prelude.yo +6304 -4315
  100. package/std/process/command.yo +87 -103
  101. package/std/process/index.yo +12 -31
  102. package/std/regex/compiler.yo +196 -95
  103. package/std/regex/flags.yo +58 -39
  104. package/std/regex/index.yo +157 -173
  105. package/std/regex/match.yo +20 -31
  106. package/std/regex/node.yo +134 -152
  107. package/std/regex/parser.yo +283 -259
  108. package/std/regex/unicode.yo +172 -202
  109. package/std/regex/vm.yo +155 -171
  110. package/std/string/index.yo +5 -7
  111. package/std/string/rune.yo +45 -55
  112. package/std/string/string.yo +937 -964
  113. package/std/string/string_builder.yo +94 -104
  114. package/std/string/unicode.yo +46 -64
  115. package/std/sync/channel.yo +72 -73
  116. package/std/sync/cond.yo +31 -36
  117. package/std/sync/mutex.yo +30 -32
  118. package/std/sync/once.yo +13 -16
  119. package/std/sync/rwlock.yo +26 -31
  120. package/std/sync/waitgroup.yo +20 -25
  121. package/std/sys/advise.yo +16 -24
  122. package/std/sys/bufio/buf_reader.yo +77 -93
  123. package/std/sys/bufio/buf_writer.yo +52 -65
  124. package/std/sys/clock.yo +4 -9
  125. package/std/sys/constants.yo +77 -61
  126. package/std/sys/copy.yo +4 -10
  127. package/std/sys/dir.yo +26 -43
  128. package/std/sys/dns.yo +41 -61
  129. package/std/sys/errors.yo +95 -103
  130. package/std/sys/events.yo +45 -57
  131. package/std/sys/externs.yo +319 -267
  132. package/std/sys/fallocate.yo +7 -11
  133. package/std/sys/fcntl.yo +14 -22
  134. package/std/sys/file.yo +26 -40
  135. package/std/sys/future.yo +5 -8
  136. package/std/sys/iov.yo +12 -25
  137. package/std/sys/lock.yo +12 -13
  138. package/std/sys/mmap.yo +38 -43
  139. package/std/sys/path.yo +3 -8
  140. package/std/sys/perm.yo +7 -21
  141. package/std/sys/pipe.yo +5 -12
  142. package/std/sys/process.yo +23 -29
  143. package/std/sys/seek.yo +10 -12
  144. package/std/sys/signal.yo +7 -13
  145. package/std/sys/signals.yo +52 -35
  146. package/std/sys/socket.yo +63 -58
  147. package/std/sys/socketpair.yo +3 -6
  148. package/std/sys/sockinfo.yo +11 -20
  149. package/std/sys/statfs.yo +11 -34
  150. package/std/sys/statx.yo +25 -52
  151. package/std/sys/sysinfo.yo +15 -20
  152. package/std/sys/tcp.yo +62 -92
  153. package/std/sys/temp.yo +5 -9
  154. package/std/sys/time.yo +5 -15
  155. package/std/sys/timer.yo +6 -11
  156. package/std/sys/tty.yo +10 -18
  157. package/std/sys/udp.yo +22 -39
  158. package/std/sys/umask.yo +3 -6
  159. package/std/sys/unix.yo +33 -52
  160. package/std/testing/bench.yo +49 -52
  161. package/std/thread.yo +10 -15
  162. package/std/time/datetime.yo +105 -89
  163. package/std/time/duration.yo +43 -56
  164. package/std/time/instant.yo +13 -18
  165. package/std/time/sleep.yo +5 -9
  166. package/std/url/index.yo +184 -209
  167. package/std/worker.yo +6 -10
@@ -1,8 +1,6 @@
1
1
  //! Hash map using SwissTable algorithm with SIMD-accelerated lookup.
2
-
3
- { GlobalAllocator, AllocError } :: import "../allocator.yo";
2
+ { GlobalAllocator, AllocError } :: import("../allocator.yo");
4
3
  { malloc, calloc, realloc, free } :: GlobalAllocator;
5
-
6
4
  /// Error variants for HashMap operations.
7
5
  HashMapError :: enum(
8
6
  /// Memory allocation failed.
@@ -12,487 +10,437 @@ HashMapError :: enum(
12
10
  /// Capacity calculation overflowed.
13
11
  CapacityOverflow
14
12
  );
15
-
16
13
  /// Control byte for an empty bucket (never used).
17
14
  CTRL_EMPTY :: u8(255);
18
15
  /// Control byte for a deleted bucket (tombstone).
19
16
  CTRL_DELETED :: u8(254);
20
-
21
17
  /// Default initial capacity (must be power of 2).
22
18
  DEFAULT_CAPACITY :: usize(16);
23
-
24
19
  /// Maximum load factor numerator (7/8 = 0.875). Resize when `size > capacity * 7 / 8`.
25
20
  MAX_LOAD_FACTOR_NUMERATOR :: usize(7);
26
21
  MAX_LOAD_FACTOR_DENOMINATOR :: usize(8);
27
-
28
22
  /// Key-value pair stored in a hash map bucket.
29
- Bucket :: (fn(comptime(K): Type, comptime(V): Type) -> comptime(Type))
23
+ Bucket :: (fn(comptime(K) : Type, comptime(V) : Type) -> comptime(Type))(
30
24
  struct(
31
25
  key : K,
32
26
  value : V
33
27
  )
34
- ;
35
-
28
+ );
36
29
  /// Extract H2 hash (lower 7 bits) from full hash for control byte comparison.
37
- h2_hash :: (fn(hash: u64) -> u8)
38
- u8(hash & u64(127))
39
- ;
40
-
30
+ h2_hash :: (fn(hash : u64) -> u8)(u8(hash & u64(127)));
41
31
  /// Extract H1 hash (upper bits) for bucket index calculation.
42
- h1_hash :: (fn(hash: u64, capacity: usize) -> usize)
43
- (usize((hash >> u64(7))) % capacity)
44
- ;
45
-
32
+ h1_hash :: (fn(hash : u64, capacity : usize) -> usize)(usize(hash >> u64(7)) % capacity);
46
33
  /// High-performance hash map using SwissTable algorithm.
47
34
  /// Keys must implement `Eq` and `Hash`. Provides O(1) average lookup, insert, and delete.
48
- HashMap :: (fn(
49
- comptime(K): Type,
50
- comptime(V): Type,
51
- where(K <: (Eq(K), Hash))
52
- ) -> comptime(Type))
35
+ HashMap :: (
36
+ fn(
37
+ comptime(K) : Type,
38
+ comptime(V) : Type,
39
+ where(K <: (Eq(K), Hash))
40
+ ) -> comptime(Type)
41
+ )(
53
42
  object(
54
43
  ctrl : ?*(u8),
55
44
  data : ?*(Bucket(K, V)),
56
45
  capacity : usize,
57
46
  size : usize
58
47
  )
59
- ;
60
-
61
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMap(K, V),
48
+ );
49
+ impl(
50
+ forall(K : Type, V : Type),
51
+ where(K <: (Eq(K), Hash)),
52
+ HashMap(K, V),
62
53
  /**
63
- * Allocate memory for HashMap with given capacity
64
- * Initializes all control bytes to EMPTY
65
- */
66
- _alloc_with_capacity : (fn(capacity: usize) -> Result(Self, HashMapError))(
67
- {
68
- bucket_size :: sizeof(Bucket(K, V));
69
- ctrl_size := capacity;
70
- data_size := (capacity * bucket_size);
71
-
72
- ctrl_result := malloc(ctrl_size);
73
- match(ctrl_result,
74
- .None => .Err(.AllocError(error: .OutOfMemory)),
75
- .Some(ctrl_void_ptr) => {
76
- ctrl_ptr := *(u8)(ctrl_void_ptr);
77
-
78
- data_result := malloc(data_size);
79
- match(data_result,
80
- .None => {
81
- free(.Some(*(void)(ctrl_ptr)));
82
- .Err(.AllocError(error: .OutOfMemory))
83
- },
84
- .Some(data_void_ptr) => {
85
- data_ptr := *(Bucket(K, V))(data_void_ptr);
86
-
87
- i := usize(0);
88
- while(i < capacity, i = (i + usize(1)), {
89
- (ctrl_ptr &+ i).* = CTRL_EMPTY;
90
- });
91
-
92
- .Ok(Self(
93
- ctrl: .Some(ctrl_ptr),
94
- data: .Some(data_ptr),
95
- capacity: capacity,
96
- size: usize(0)
97
- ))
98
- }
99
- )
100
- }
101
- )
102
- }
103
- ),
104
-
54
+ * Allocate memory for HashMap with given capacity
55
+ * Initializes all control bytes to EMPTY
56
+ */
57
+ _alloc_with_capacity : (fn(capacity : usize) -> Result(Self, HashMapError))({
58
+ bucket_size :: sizeof(Bucket(K, V));
59
+ ctrl_size := capacity;
60
+ data_size := (capacity * bucket_size);
61
+ ctrl_result := malloc(ctrl_size);
62
+ match(
63
+ ctrl_result,
64
+ .None =>.Err(.AllocError(error :.OutOfMemory)),
65
+ .Some(ctrl_void_ptr) => {
66
+ ctrl_ptr := *(u8)(ctrl_void_ptr);
67
+ data_result := malloc(data_size);
68
+ match(
69
+ data_result,
70
+ .None => {
71
+ free(.Some(*(void)(ctrl_ptr)));
72
+ .Err(.AllocError(error :.OutOfMemory))
73
+ },
74
+ .Some(data_void_ptr) => {
75
+ data_ptr := *(Bucket(K, V))(data_void_ptr);
76
+ i := usize(0);
77
+ while(i < capacity, i = (i + usize(1)), {
78
+ (ctrl_ptr &+ i).* = CTRL_EMPTY;
79
+ });
80
+ .Ok(
81
+ Self(
82
+ ctrl :.Some(ctrl_ptr),
83
+ data :.Some(data_ptr),
84
+ capacity : capacity,
85
+ size : usize(0)
86
+ )
87
+ )
88
+ }
89
+ )
90
+ }
91
+ )
92
+ }),
105
93
  /**
106
- * Create a new empty HashMap with default capacity
107
- */
94
+ * Create a new empty HashMap with default capacity
95
+ */
108
96
  new : (fn() -> Self)({
109
97
  result := Self._alloc_with_capacity(DEFAULT_CAPACITY);
110
- match(result,
98
+ match(
99
+ result,
111
100
  .Ok(map) => map,
112
101
  .Err(_) => panic("Failed to allocate HashMap")
113
102
  )
114
103
  }),
115
-
116
104
  /**
117
- * Create a HashMap with a specific initial capacity
118
- * Capacity will be rounded up to next power of 2
119
- */
120
- with_capacity : (fn(requested_capacity: usize) -> Self)(
121
- {
122
- capacity := cond(
123
- (requested_capacity < DEFAULT_CAPACITY) => DEFAULT_CAPACITY,
124
- true => {
125
- c := requested_capacity;
126
- c = (c - usize(1));
127
- c = (c | (c >> usize(1)));
128
- c = (c | (c >> usize(2)));
129
- c = (c | (c >> usize(4)));
130
- c = (c | (c >> usize(8)));
131
- c = (c | (c >> usize(16)));
132
- (c + usize(1))
133
- }
134
- );
135
-
136
- result := Self._alloc_with_capacity(capacity);
137
- match(result,
138
- .Ok(map) => map,
139
- .Err(_) => panic("Failed to allocate HashMap")
140
- )
141
- }
142
- ),
143
-
105
+ * Create a HashMap with a specific initial capacity
106
+ * Capacity will be rounded up to next power of 2
107
+ */
108
+ with_capacity : (fn(requested_capacity : usize) -> Self)({
109
+ capacity := cond(
110
+ (requested_capacity < DEFAULT_CAPACITY) => DEFAULT_CAPACITY,
111
+ true => {
112
+ c := requested_capacity;
113
+ c = (c - usize(1));
114
+ c = (c | (c >> usize(1)));
115
+ c = (c | (c >> usize(2)));
116
+ c = (c | (c >> usize(4)));
117
+ c = (c | (c >> usize(8)));
118
+ c = (c | (c >> usize(16)));
119
+ c + usize(1)
120
+ }
121
+ );
122
+ result := Self._alloc_with_capacity(capacity);
123
+ match(
124
+ result,
125
+ .Ok(map) => map,
126
+ .Err(_) => panic("Failed to allocate HashMap")
127
+ )
128
+ }),
144
129
  /**
145
- * Get ctrl pointer (unwrapped for internal use)
146
- */
147
- _ctrl_ptr : (fn(self: Self) -> *(u8))(
148
- match(self.ctrl,
130
+ * Get ctrl pointer (unwrapped for internal use)
131
+ */
132
+ _ctrl_ptr : (fn(self : Self) -> *(u8))(
133
+ match(
134
+ self.ctrl,
149
135
  .Some(ptr) => ptr,
150
136
  .None => panic("HashMap ctrl pointer is null")
151
137
  )
152
138
  ),
153
-
154
139
  /**
155
- * Get data pointer (unwrapped for internal use)
156
- */
157
- _data_ptr : (fn(self: Self) -> *(Bucket(K, V)))(
158
- match(self.data,
140
+ * Get data pointer (unwrapped for internal use)
141
+ */
142
+ _data_ptr : (fn(self : Self) -> *(Bucket(K, V)))(
143
+ match(
144
+ self.data,
159
145
  .Some(ptr) => ptr,
160
146
  .None => panic("HashMap data pointer is null")
161
147
  )
162
148
  ),
163
-
164
149
  /**
165
- * Find bucket index for a given key using quadratic probing
166
- * Returns Some(index) if key is found, None otherwise
167
- */
168
- _find_bucket : (fn(self: Self, key: K, hash: u64) -> Option(usize))(
169
- {
170
- h2 := h2_hash(hash);
171
- index := h1_hash(hash, self.capacity);
172
- probe := usize(0);
173
- ctrl_ptr := Self._ctrl_ptr(self);
174
- data_ptr := Self._data_ptr(self);
175
-
176
- while(probe < self.capacity, probe = (probe + usize(1)), {
177
- probe_index := ((index + probe) % self.capacity);
178
- ctrl_byte := (ctrl_ptr &+ probe_index).*;
179
-
180
- cond(
181
- (ctrl_byte == CTRL_EMPTY) => {
182
- return .None;
183
- },
184
- (ctrl_byte == h2) => {
185
- bucket := (data_ptr &+ probe_index).*;
186
- cond(
187
- (bucket.key == key) => {
188
- return .Some(probe_index);
189
- },
190
- true => ()
191
- );
192
- },
193
- true => ()
194
- );
195
- });
196
-
197
- .None
198
- }
199
- ),
200
-
201
- /**
202
- * Find first available bucket (EMPTY or DELETED) for insertion
203
- * Returns bucket index using quadratic probing
204
- */
205
- _find_insert_bucket : (fn(self: Self, hash: u64) -> usize)(
206
- {
207
- index := h1_hash(hash, self.capacity);
208
- probe := usize(0);
209
- ctrl_ptr := Self._ctrl_ptr(self);
210
-
211
- while(probe < self.capacity, probe = (probe + usize(1)), {
212
- probe_index := ((index + probe) % self.capacity);
213
- ctrl_byte := (ctrl_ptr &+ probe_index).*;
214
-
215
- cond(
216
- ((ctrl_byte == CTRL_EMPTY) || (ctrl_byte == CTRL_DELETED)) => {
217
- return probe_index;
218
- },
219
- true => ()
220
- );
221
- });
222
-
223
- panic("HashMap is full - should have resized")
224
- }
225
- ),
226
-
227
- /**
228
- * Check if HashMap needs resizing based on load factor
229
- */
230
- _needs_resize : (fn(self: Self) -> bool)(
231
- {
232
- threshold := ((self.capacity * MAX_LOAD_FACTOR_NUMERATOR) / MAX_LOAD_FACTOR_DENOMINATOR);
233
- (self.size >= threshold)
234
- }
235
- ),
236
-
237
- /**
238
- * Resize and rehash the HashMap to a new capacity
239
- */
240
- _resize : (fn(self: Self, new_capacity: usize) -> Result(unit, HashMapError))(
241
- {
242
- result := Self._alloc_with_capacity(new_capacity);
243
- match(result,
244
- .Err(err) => .Err(err),
245
- .Ok(new_map) => {
246
- i := usize(0);
247
- ctrl_ptr := Self._ctrl_ptr(self);
248
- data_ptr := Self._data_ptr(self);
249
- while(i < self.capacity, i = (i + usize(1)), {
250
- ctrl_byte := (ctrl_ptr &+ i).*;
251
- cond(
252
- ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
253
- bucket := (data_ptr &+ i).*;
254
- hash := (bucket.key).hash();
255
- h2 := h2_hash(hash);
256
- new_index := Self._find_insert_bucket(new_map, hash);
257
-
258
- new_ctrl_ptr := Self._ctrl_ptr(new_map);
259
- new_data_ptr := Self._data_ptr(new_map);
260
- (new_ctrl_ptr &+ new_index).* = h2;
261
- consume((new_data_ptr &+ new_index).* = bucket);
262
- new_map.size = (new_map.size + usize(1));
263
- },
264
- true => ()
265
- );
266
- });
267
-
268
- // Drop old buckets before freeing old data array
269
- // (bucket := ... above duped them, so we need to drop the old refs)
150
+ * Find bucket index for a given key using quadratic probing
151
+ * Returns Some(index) if key is found, None otherwise
152
+ */
153
+ _find_bucket : (fn(self : Self, key : K, hash : u64) -> Option(usize))({
154
+ h2 := h2_hash(hash);
155
+ index := h1_hash(hash, self.capacity);
156
+ probe := usize(0);
157
+ ctrl_ptr := Self._ctrl_ptr(self);
158
+ data_ptr := Self._data_ptr(self);
159
+ while(probe < self.capacity, probe = (probe + usize(1)), {
160
+ probe_index := ((index + probe) % self.capacity);
161
+ ctrl_byte := (ctrl_ptr &+ probe_index).*;
162
+ cond(
163
+ (ctrl_byte == CTRL_EMPTY) => {
164
+ return(.None);
165
+ },
166
+ (ctrl_byte == h2) => {
167
+ bucket := (data_ptr &+ probe_index).*;
270
168
  cond(
271
- (Type.contains_rc_type(K) || Type.contains_rc_type(V)) => {
272
- j := usize(0);
273
- while(j < self.capacity, j = (j + usize(1)), {
274
- ctrl_byte := (ctrl_ptr &+ j).*;
275
- cond(
276
- ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
277
- bucket_ptr := (data_ptr &+ j);
278
- cond(
279
- Type.contains_rc_type(K) => unsafe.drop((bucket_ptr.*).key),
280
- true => ()
281
- );
282
- cond(
283
- Type.contains_rc_type(V) => unsafe.drop((bucket_ptr.*).value),
284
- true => ()
285
- );
286
- },
287
- true => ()
288
- );
289
- });
169
+ (bucket.key == key) => {
170
+ return(.Some(probe_index));
290
171
  },
291
172
  true => ()
292
173
  );
293
-
294
- match(self.ctrl,
295
- .Some(ptr) => free(.Some(*(void)(ptr))),
296
- .None => ()
297
- );
298
- match(self.data,
299
- .Some(ptr) => free(.Some(*(void)(ptr))),
300
- .None => ()
301
- );
302
-
303
- self.ctrl = new_map.ctrl;
304
- self.data = new_map.data;
305
- self.capacity = new_map.capacity;
306
-
307
- new_map.ctrl = .None;
308
- new_map.data = .None;
309
-
310
- .Ok(())
311
- }
312
- )
313
- }
314
- ),
315
-
174
+ },
175
+ true => ()
176
+ );
177
+ });
178
+ .None
179
+ }),
316
180
  /**
317
- * Insert or update a key-value pair
318
- * Returns Ok(Some(old_value)) if key existed, Ok(None) if new key
319
- */
320
- set : (fn(self: Self, key: K, value: V) -> Result(Option(V), HashMapError))(
321
- {
322
- hash := key.hash();
323
- bucket_opt := Self._find_bucket(self, key, hash);
324
-
325
- match(bucket_opt,
326
- .Some(index) => {
327
- data_ptr := Self._data_ptr(self);
328
- old_bucket := (data_ptr &+ index).*;
329
- old_value := old_bucket.value;
330
- new_bucket := Bucket(K, V)(key: key, value: value);
331
- // Don't use consume here - we want to drop the old bucket at memory
332
- // Note: old_bucket already duped it, so dropping here decrements to RC=1
333
- // Then old_bucket goes out of scope and drops again to RC=0
334
- // But wait - we return old_value which was duped from old_bucket...
335
- // Actually the Bucket struct contains RC types, so assignment drops old + dups new
336
- (data_ptr &+ index).* = new_bucket;
337
- .Ok(.Some(old_value))
181
+ * Find first available bucket (EMPTY or DELETED) for insertion
182
+ * Returns bucket index using quadratic probing
183
+ */
184
+ _find_insert_bucket : (fn(self : Self, hash : u64) -> usize)({
185
+ index := h1_hash(hash, self.capacity);
186
+ probe := usize(0);
187
+ ctrl_ptr := Self._ctrl_ptr(self);
188
+ while(probe < self.capacity, probe = (probe + usize(1)), {
189
+ probe_index := ((index + probe) % self.capacity);
190
+ ctrl_byte := (ctrl_ptr &+ probe_index).*;
191
+ cond(
192
+ ((ctrl_byte == CTRL_EMPTY) || (ctrl_byte == CTRL_DELETED)) => {
193
+ return(probe_index);
338
194
  },
339
- .None => {
340
- resize_check := cond(
341
- (Self._needs_resize(self)) => {
342
- new_capacity := (self.capacity * usize(2));
343
- Self._resize(self, new_capacity)
195
+ true => ()
196
+ );
197
+ });
198
+ panic("HashMap is full - should have resized")
199
+ }),
200
+ /**
201
+ * Check if HashMap needs resizing based on load factor
202
+ */
203
+ _needs_resize : (fn(self : Self) -> bool)({
204
+ threshold := ((self.capacity * MAX_LOAD_FACTOR_NUMERATOR) / MAX_LOAD_FACTOR_DENOMINATOR);
205
+ self.size >= threshold
206
+ }),
207
+ /**
208
+ * Resize and rehash the HashMap to a new capacity
209
+ */
210
+ _resize : (fn(self : Self, new_capacity : usize) -> Result(unit, HashMapError))({
211
+ result := Self._alloc_with_capacity(new_capacity);
212
+ match(
213
+ result,
214
+ .Err(err) =>.Err(err),
215
+ .Ok(new_map) => {
216
+ i := usize(0);
217
+ ctrl_ptr := Self._ctrl_ptr(self);
218
+ data_ptr := Self._data_ptr(self);
219
+ while(i < self.capacity, i = (i + usize(1)), {
220
+ ctrl_byte := (ctrl_ptr &+ i).*;
221
+ cond(
222
+ ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
223
+ bucket := (data_ptr &+ i).*;
224
+ hash := (bucket.key).hash();
225
+ h2 := h2_hash(hash);
226
+ new_index := Self._find_insert_bucket(new_map, hash);
227
+ new_ctrl_ptr := Self._ctrl_ptr(new_map);
228
+ new_data_ptr := Self._data_ptr(new_map);
229
+ (new_ctrl_ptr &+ new_index).* = h2;
230
+ consume((new_data_ptr &+ new_index).* = bucket);
231
+ new_map.size = (new_map.size + usize(1));
344
232
  },
345
- true => (Result(unit, HashMapError).Ok(()))
233
+ true => ()
346
234
  );
347
-
348
- match(resize_check,
349
- .Err(err) => .Err(err),
350
- .Ok(_) => {
351
- h2 := h2_hash(hash);
352
- index := Self._find_insert_bucket(self, hash);
353
-
354
- ctrl_ptr := Self._ctrl_ptr(self);
355
- data_ptr := Self._data_ptr(self);
356
- (ctrl_ptr &+ index).* = h2;
357
- new_bucket := Bucket(K, V)(key: key, value: value);
358
- consume((data_ptr &+ index).* = new_bucket);
359
- self.size = (self.size + usize(1));
360
-
361
- .Ok(.None)
362
- }
363
- )
364
- }
365
- )
366
- }
367
- ),
368
-
235
+ });
236
+ // Drop old buckets before freeing old data array
237
+ // (bucket := ... above duped them, so we need to drop the old refs)
238
+ cond(
239
+ (Type.contains_rc_type(K) || Type.contains_rc_type(V)) => {
240
+ j := usize(0);
241
+ while(j < self.capacity, j = (j + usize(1)), {
242
+ ctrl_byte := (ctrl_ptr &+ j).*;
243
+ cond(
244
+ ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
245
+ bucket_ptr := (data_ptr &+ j);
246
+ cond(
247
+ Type.contains_rc_type(K) => unsafe.drop((bucket_ptr.*).key),
248
+ true => ()
249
+ );
250
+ cond(
251
+ Type.contains_rc_type(V) => unsafe.drop((bucket_ptr.*).value),
252
+ true => ()
253
+ );
254
+ },
255
+ true => ()
256
+ );
257
+ });
258
+ },
259
+ true => ()
260
+ );
261
+ match(
262
+ self.ctrl,
263
+ .Some(ptr) => free(.Some(*(void)(ptr))),
264
+ .None => ()
265
+ );
266
+ match(
267
+ self.data,
268
+ .Some(ptr) => free(.Some(*(void)(ptr))),
269
+ .None => ()
270
+ );
271
+ self.ctrl = new_map.ctrl;
272
+ self.data = new_map.data;
273
+ self.capacity = new_map.capacity;
274
+ new_map.ctrl =.None;
275
+ new_map.data =.None;
276
+ .Ok(())
277
+ }
278
+ )
279
+ }),
369
280
  /**
370
- * Get a value by key
371
- * Returns Some(value) if found, None otherwise
372
- */
373
- get : (fn(self: Self, key: K) -> Option(V))(
374
- {
375
- hash := key.hash();
376
- bucket_opt := Self._find_bucket(self, key, hash);
377
- match(bucket_opt,
378
- .Some(index) => {
379
- data_ptr := Self._data_ptr(self);
380
- bucket := (data_ptr &+ index).*;
381
- .Some(bucket.value)
382
- },
383
- .None => .None
384
- )
385
- }
386
- ),
387
-
281
+ * Insert or update a key-value pair
282
+ * Returns Ok(Some(old_value)) if key existed, Ok(None) if new key
283
+ */
284
+ set : (fn(self : Self, key : K, value : V) -> Result(Option(V), HashMapError))({
285
+ hash := key.hash();
286
+ bucket_opt := Self._find_bucket(self, key, hash);
287
+ match(
288
+ bucket_opt,
289
+ .Some(index) => {
290
+ data_ptr := Self._data_ptr(self);
291
+ old_bucket := (data_ptr &+ index).*;
292
+ old_value := old_bucket.value;
293
+ new_bucket := Bucket(K, V)(key : key, value : value);
294
+ // Don't use consume here - we want to drop the old bucket at memory
295
+ // Note: old_bucket already duped it, so dropping here decrements to RC=1
296
+ // Then old_bucket goes out of scope and drops again to RC=0
297
+ // But wait - we return old_value which was duped from old_bucket...
298
+ // Actually the Bucket struct contains RC types, so assignment drops old + dups new
299
+ (data_ptr &+ index).* = new_bucket;
300
+ .Ok(.Some(old_value))
301
+ },
302
+ .None => {
303
+ resize_check := cond(
304
+ (Self._needs_resize(self)) => {
305
+ new_capacity := (self.capacity * usize(2));
306
+ Self._resize(self, new_capacity)
307
+ },
308
+ true => Result(unit, HashMapError).Ok(())
309
+ );
310
+ match(
311
+ resize_check,
312
+ .Err(err) =>.Err(err),
313
+ .Ok(_) => {
314
+ h2 := h2_hash(hash);
315
+ index := Self._find_insert_bucket(self, hash);
316
+ ctrl_ptr := Self._ctrl_ptr(self);
317
+ data_ptr := Self._data_ptr(self);
318
+ (ctrl_ptr &+ index).* = h2;
319
+ new_bucket := Bucket(K, V)(key : key, value : value);
320
+ consume((data_ptr &+ index).* = new_bucket);
321
+ self.size = (self.size + usize(1));
322
+ .Ok(.None)
323
+ }
324
+ )
325
+ }
326
+ )
327
+ }),
388
328
  /**
389
- * Check if a key exists in the map
390
- */
391
- contains_key : (fn(self: Self, key: K) -> bool)(
392
- {
393
- hash := key.hash();
394
- bucket_opt := Self._find_bucket(self, key, hash);
395
- match(bucket_opt,
396
- .Some(_) => true,
397
- .None => false
398
- )
399
- }
400
- ),
401
-
329
+ * Get a value by key
330
+ * Returns Some(value) if found, None otherwise
331
+ */
332
+ get : (fn(self : Self, key : K) -> Option(V))({
333
+ hash := key.hash();
334
+ bucket_opt := Self._find_bucket(self, key, hash);
335
+ match(
336
+ bucket_opt,
337
+ .Some(index) => {
338
+ data_ptr := Self._data_ptr(self);
339
+ bucket := (data_ptr &+ index).*;
340
+ .Some(bucket.value)
341
+ },
342
+ .None =>.None
343
+ )
344
+ }),
402
345
  /**
403
- * Remove a key-value pair by key
404
- * Returns Some(value) if the key was found and removed, None otherwise
405
- */
406
- remove : (fn(self: Self, key: K) -> Option(V))(
407
- {
408
- hash := key.hash();
409
- bucket_opt := Self._find_bucket(self, key, hash);
410
- match(bucket_opt,
411
- .Some(index) => {
412
- data_ptr := Self._data_ptr(self);
413
- ctrl_ptr := Self._ctrl_ptr(self);
414
- bucket_ptr := (data_ptr &+ index);
415
-
416
- // Read and dup value for return
417
- value := bucket_ptr.*.value;
418
-
419
- // Drop the bucket's key (we're removing it)
420
- unsafe.drop(bucket_ptr.*.key);
421
-
422
- // Drop the bucket's value extra ref (we duped it above)
423
- unsafe.drop(bucket_ptr.*.value);
424
-
425
- (ctrl_ptr &+ index).* = CTRL_DELETED;
426
- self.size = (self.size - usize(1));
427
-
428
- .Some(value)
429
- },
430
- .None => .None
431
- )
432
- }
433
- ),
434
-
346
+ * Check if a key exists in the map
347
+ */
348
+ contains_key : (fn(self : Self, key : K) -> bool)({
349
+ hash := key.hash();
350
+ bucket_opt := Self._find_bucket(self, key, hash);
351
+ match(
352
+ bucket_opt,
353
+ .Some(_) => true,
354
+ .None => false
355
+ )
356
+ }),
435
357
  /**
436
- * Get the number of key-value pairs in the map
437
- */
438
- len : (fn(self: Self) -> usize)(
358
+ * Remove a key-value pair by key
359
+ * Returns Some(value) if the key was found and removed, None otherwise
360
+ */
361
+ remove : (fn(self : Self, key : K) -> Option(V))({
362
+ hash := key.hash();
363
+ bucket_opt := Self._find_bucket(self, key, hash);
364
+ match(
365
+ bucket_opt,
366
+ .Some(index) => {
367
+ data_ptr := Self._data_ptr(self);
368
+ ctrl_ptr := Self._ctrl_ptr(self);
369
+ bucket_ptr := (data_ptr &+ index);
370
+ // Read and dup value for return
371
+ value := bucket_ptr.*.value;
372
+ // Drop the bucket's key (we're removing it)
373
+ unsafe.drop(bucket_ptr.*.key);
374
+ // Drop the bucket's value extra ref (we duped it above)
375
+ unsafe.drop(bucket_ptr.*.value);
376
+ (ctrl_ptr &+ index).* = CTRL_DELETED;
377
+ self.size = (self.size - usize(1));
378
+ .Some(value)
379
+ },
380
+ .None =>.None
381
+ )
382
+ }),
383
+ /**
384
+ * Get the number of key-value pairs in the map
385
+ */
386
+ len : (fn(self : Self) -> usize)(
439
387
  self.size
440
388
  ),
441
-
442
389
  /**
443
- * Check if the map is empty
444
- */
445
- is_empty : (fn(self: Self) -> bool)(
446
- (self.size == usize(0))
390
+ * Check if the map is empty
391
+ */
392
+ is_empty : (fn(self : Self) -> bool)(
393
+ self.size == usize(0)
447
394
  ),
448
-
449
395
  /**
450
- * Clear all key-value pairs
451
- * Resets all control bytes to EMPTY
452
- */
453
- clear : (fn(self: Self) -> unit)(
454
- {
455
- // Drop all occupied buckets before clearing
456
- cond(
457
- (Type.contains_rc_type(K) || Type.contains_rc_type(V)) => {
458
- ctrl_ptr := Self._ctrl_ptr(self);
459
- data_ptr := Self._data_ptr(self);
460
- i := usize(0);
461
- while(i < self.capacity, i = (i + usize(1)), {
462
- ctrl_byte := (ctrl_ptr &+ i).*;
463
- cond(
464
- ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
465
- bucket_ptr := (data_ptr &+ i);
466
- unsafe.drop(bucket_ptr.*);
467
- },
468
- true => ()
469
- );
470
- });
471
- },
472
- true => ()
473
- );
474
-
475
- ctrl_ptr := Self._ctrl_ptr(self);
476
- i := usize(0);
477
- while(i < self.capacity, i = (i + usize(1)), {
478
- (ctrl_ptr &+ i).* = CTRL_EMPTY;
479
- });
480
- self.size = usize(0);
481
- }
482
- )
396
+ * Clear all key-value pairs
397
+ * Resets all control bytes to EMPTY
398
+ */
399
+ clear : (fn(self : Self) -> unit)({
400
+ // Drop all occupied buckets before clearing
401
+ cond(
402
+ (Type.contains_rc_type(K) || Type.contains_rc_type(V)) => {
403
+ ctrl_ptr := Self._ctrl_ptr(self);
404
+ data_ptr := Self._data_ptr(self);
405
+ i := usize(0);
406
+ while(i < self.capacity, i = (i + usize(1)), {
407
+ ctrl_byte := (ctrl_ptr &+ i).*;
408
+ cond(
409
+ ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
410
+ bucket_ptr := (data_ptr &+ i);
411
+ unsafe.drop(bucket_ptr.*);
412
+ },
413
+ true => ()
414
+ );
415
+ });
416
+ },
417
+ true => ()
418
+ );
419
+ ctrl_ptr := Self._ctrl_ptr(self);
420
+ i := usize(0);
421
+ while(i < self.capacity, i = (i + usize(1)), {
422
+ (ctrl_ptr &+ i).* = CTRL_EMPTY;
423
+ });
424
+ self.size = usize(0);
425
+ })
483
426
  );
484
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMap(K, V),
427
+ impl(
428
+ forall(K : Type, V : Type),
429
+ where(K <: (Eq(K), Hash)),
430
+ HashMap(K, V),
485
431
  Dispose(
486
432
  /**
487
- * RAII destructor - automatically called when HashMap goes out of scope
488
- */
489
- dispose : (fn(self: Self) -> unit)({
433
+ * RAII destructor - automatically called when HashMap goes out of scope
434
+ */
435
+ dispose : (fn(self : Self) -> unit)({
490
436
  // Drop all occupied buckets before freeing memory
491
437
  cond(
492
438
  (Type.contains_rc_type(K) || Type.contains_rc_type(V)) => {
493
- match(self.ctrl,
439
+ match(
440
+ self.ctrl,
494
441
  .Some(ctrl_ptr) => {
495
- match(self.data,
442
+ match(
443
+ self.data,
496
444
  .Some(data_ptr) => {
497
445
  i := usize(0);
498
446
  while(i < self.capacity, i = (i + usize(1)), {
@@ -514,192 +462,221 @@ impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMap(K, V),
514
462
  },
515
463
  true => ()
516
464
  );
517
-
518
- match(self.ctrl,
465
+ match(
466
+ self.ctrl,
519
467
  .Some(ptr) => free(.Some(*(void)(ptr))),
520
468
  .None => ()
521
469
  );
522
- match(self.data,
470
+ match(
471
+ self.data,
523
472
  .Some(ptr) => free(.Some(*(void)(ptr))),
524
473
  .None => ()
525
474
  );
526
475
  })
527
- ));
528
-
476
+ )
477
+ );
529
478
  /**
530
- * Value iterator for HashMap - yields Bucket(K, V) by value
531
- * Scans ctrl bytes to find occupied slots.
532
- */
479
+ * Value iterator for HashMap - yields Bucket(K, V) by value
480
+ * Scans ctrl bytes to find occupied slots.
481
+ */
533
482
  HashMapIter :: (fn(comptime(K) : Type, comptime(V) : Type) -> comptime(Type))(
534
483
  struct(
535
- _map : HashMap(K, V),
484
+ _map : HashMap(K, V),
536
485
  _index : usize
537
486
  )
538
487
  );
539
-
540
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMapIter(K, V), Iterator(
541
- Item : Bucket(K, V),
542
- next : (fn(self : *(Self)) -> Option(Bucket(K, V)))(
543
- cond(
544
- (self._map.capacity == usize(0)) => .None,
545
- true => {
546
- ctrl_ptr := self._map.ctrl.unwrap();
547
- data_ptr := self._map.data.unwrap();
548
- result := Option(Bucket(K, V)).None;
549
- while ((self._index < self._map.capacity) && result.is_none()), (self._index = (self._index + usize(1))), {
550
- ctrl_byte := (ctrl_ptr &+ self._index).*;
551
- cond(
552
- ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
553
- result = .Some((data_ptr &+ self._index).*);
554
- },
555
- true => ()
556
- );
557
- };
558
- result
559
- }
488
+ impl(
489
+ forall(K : Type, V : Type),
490
+ where(K <: (Eq(K), Hash)),
491
+ HashMapIter(K, V),
492
+ Iterator(
493
+ Item : Bucket(K, V),
494
+ next : (fn(self : *(Self)) -> Option(Bucket(K, V)))(
495
+ cond(
496
+ (self._map.capacity == usize(0)) =>.None,
497
+ true => {
498
+ ctrl_ptr := self._map.ctrl.unwrap();
499
+ data_ptr := self._map.data.unwrap();
500
+ result := Option(Bucket(K, V)).None;
501
+ while((self._index < self._map.capacity) && result.is_none(), self._index = (self._index + usize(1)), {
502
+ ctrl_byte := (ctrl_ptr &+ self._index).*;
503
+ cond(
504
+ ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
505
+ result =.Some((data_ptr &+ self._index).*);
506
+ },
507
+ true => ()
508
+ );
509
+ });
510
+ result
511
+ }
512
+ )
560
513
  )
561
514
  )
562
- ));
563
-
564
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMap(K, V),
515
+ );
516
+ impl(
517
+ forall(K : Type, V : Type),
518
+ where(K <: (Eq(K), Hash)),
519
+ HashMap(K, V),
565
520
  into_iter : (fn(self : Self) -> HashMapIter(K, V))(
566
- HashMapIter(K, V)(_map: self, _index: usize(0))
521
+ HashMapIter(K, V)(_map : self, _index : usize(0))
567
522
  )
568
523
  );
569
-
570
524
  /**
571
- * Pointer iterator for HashMap - yields pointers to Bucket(K, V)
572
- * Pointers are valid as long as the map is not modified during iteration.
573
- */
525
+ * Pointer iterator for HashMap - yields pointers to Bucket(K, V)
526
+ * Pointers are valid as long as the map is not modified during iteration.
527
+ */
574
528
  HashMapIterPtr :: (fn(comptime(K) : Type, comptime(V) : Type) -> comptime(Type))(
575
529
  struct(
576
- _map : HashMap(K, V),
530
+ _map : HashMap(K, V),
577
531
  _index : usize
578
532
  )
579
533
  );
580
-
581
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMapIterPtr(K, V), Iterator(
582
- Item : *(Bucket(K, V)),
583
- next : (fn(self : *(Self)) -> Option(*(Bucket(K, V))))(
584
- cond(
585
- (self._map.capacity == usize(0)) => .None,
586
- true => {
587
- ctrl_ptr := self._map.ctrl.unwrap();
588
- data_ptr := self._map.data.unwrap();
589
- result := Option(*(Bucket(K, V))).None;
590
- while ((self._index < self._map.capacity) && result.is_none()), (self._index = (self._index + usize(1))), {
591
- ctrl_byte := (ctrl_ptr &+ self._index).*;
592
- cond(
593
- ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
594
- result = .Some((data_ptr &+ self._index));
595
- },
596
- true => ()
597
- );
598
- };
599
- result
600
- }
534
+ impl(
535
+ forall(K : Type, V : Type),
536
+ where(K <: (Eq(K), Hash)),
537
+ HashMapIterPtr(K, V),
538
+ Iterator(
539
+ Item : *(Bucket(K, V)),
540
+ next : (fn(self : *(Self)) -> Option(*(Bucket(K, V))))(
541
+ cond(
542
+ (self._map.capacity == usize(0)) =>.None,
543
+ true => {
544
+ ctrl_ptr := self._map.ctrl.unwrap();
545
+ data_ptr := self._map.data.unwrap();
546
+ result := Option(*(Bucket(K, V))).None;
547
+ while((self._index < self._map.capacity) && result.is_none(), self._index = (self._index + usize(1)), {
548
+ ctrl_byte := (ctrl_ptr &+ self._index).*;
549
+ cond(
550
+ ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
551
+ result =.Some(data_ptr &+ self._index);
552
+ },
553
+ true => ()
554
+ );
555
+ });
556
+ result
557
+ }
558
+ )
601
559
  )
602
560
  )
603
- ));
604
-
605
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMap(K, V),
561
+ );
562
+ impl(
563
+ forall(K : Type, V : Type),
564
+ where(K <: (Eq(K), Hash)),
565
+ HashMap(K, V),
606
566
  iter : (fn(self : *(Self)) -> HashMapIterPtr(K, V))(
607
- HashMapIterPtr(K, V)(_map: self.*, _index: usize(0))
567
+ HashMapIterPtr(K, V)(_map : self.*, _index : usize(0))
608
568
  )
609
569
  );
610
-
611
570
  /**
612
- * Keys iterator - wraps HashMapIter and yields only the keys
613
- */
571
+ * Keys iterator - wraps HashMapIter and yields only the keys
572
+ */
614
573
  HashMapKeys :: (fn(comptime(K) : Type, comptime(V) : Type) -> comptime(Type))(
615
574
  struct(
616
575
  _inner : HashMapIter(K, V)
617
576
  )
618
577
  );
619
-
620
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMapKeys(K, V), Iterator(
621
- Item : K,
622
- next : (fn(self : *(Self)) -> Option(K))(
623
- match(self._inner.next(),
624
- .None => .None,
625
- .Some(bucket) => .Some(bucket.key)
578
+ impl(
579
+ forall(K : Type, V : Type),
580
+ where(K <: (Eq(K), Hash)),
581
+ HashMapKeys(K, V),
582
+ Iterator(
583
+ Item : K,
584
+ next : (fn(self : *(Self)) -> Option(K))(
585
+ match(
586
+ self._inner.next(),
587
+ .None =>.None,
588
+ .Some(bucket) =>.Some(bucket.key)
589
+ )
626
590
  )
627
591
  )
628
- ));
629
-
630
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMap(K, V),
592
+ );
593
+ impl(
594
+ forall(K : Type, V : Type),
595
+ where(K <: (Eq(K), Hash)),
596
+ HashMap(K, V),
631
597
  keys : (fn(self : Self) -> HashMapKeys(K, V))(
632
- HashMapKeys(K, V)(_inner: HashMapIter(K, V)(_map: self, _index: usize(0)))
598
+ HashMapKeys(K, V)(_inner : HashMapIter(K, V)(_map : self, _index : usize(0)))
633
599
  )
634
600
  );
635
-
636
601
  /**
637
- * Values iterator - wraps HashMapIter and yields only the values
638
- */
602
+ * Values iterator - wraps HashMapIter and yields only the values
603
+ */
639
604
  HashMapValues :: (fn(comptime(K) : Type, comptime(V) : Type) -> comptime(Type))(
640
605
  struct(
641
606
  _inner : HashMapIter(K, V)
642
607
  )
643
608
  );
644
-
645
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMapValues(K, V), Iterator(
646
- Item : V,
647
- next : (fn(self : *(Self)) -> Option(V))(
648
- match(self._inner.next(),
649
- .None => .None,
650
- .Some(bucket) => .Some(bucket.value)
609
+ impl(
610
+ forall(K : Type, V : Type),
611
+ where(K <: (Eq(K), Hash)),
612
+ HashMapValues(K, V),
613
+ Iterator(
614
+ Item : V,
615
+ next : (fn(self : *(Self)) -> Option(V))(
616
+ match(
617
+ self._inner.next(),
618
+ .None =>.None,
619
+ .Some(bucket) =>.Some(bucket.value)
620
+ )
651
621
  )
652
622
  )
653
- ));
654
-
655
- impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMap(K, V),
623
+ );
624
+ impl(
625
+ forall(K : Type, V : Type),
626
+ where(K <: (Eq(K), Hash)),
627
+ HashMap(K, V),
656
628
  values : (fn(self : Self) -> HashMapValues(K, V))(
657
- HashMapValues(K, V)(_inner: HashMapIter(K, V)(_map: self, _index: usize(0)))
629
+ HashMapValues(K, V)(_inner : HashMapIter(K, V)(_map : self, _index : usize(0)))
630
+ )
631
+ );
632
+ impl(
633
+ forall(K : Type, V : Type),
634
+ HashMap(K, V),
635
+ Index(K)(
636
+ Output : V,
637
+ index : (fn(self : *(Self), idx : K, where(K <: (Eq(K), Hash))) -> *(Self.Output))({
638
+ hash := idx.hash();
639
+ bucket_opt := Self._find_bucket(self.*, idx, hash);
640
+ match(
641
+ bucket_opt,
642
+ .Some(i) => {
643
+ data_ptr := Self._data_ptr(self.*);
644
+ &((data_ptr &+ i).*.value)
645
+ },
646
+ .None => panic("HashMap: key not found")
647
+ )
648
+ })
658
649
  )
659
650
  );
660
-
661
- impl(forall(K : Type, V : Type), HashMap(K, V), Index(K)(
662
- Output : V,
663
- index : (fn(self: *(Self), idx: K, where(K <: (Eq(K), Hash))) -> *(Self.Output))({
664
- hash := idx.hash();
665
- bucket_opt := Self._find_bucket(self.*, idx, hash);
666
- match(bucket_opt,
667
- .Some(i) => {
668
- data_ptr := Self._data_ptr(self.*);
669
- &((data_ptr &+ i).*.value)
670
- },
671
- .None => panic("HashMap: key not found")
672
- )
673
- })
674
- ));
675
-
676
651
  /// Clone implementation for HashMap — deep-clones all key-value entries.
677
- impl(forall(K : Type, V : Type),
678
- where(K <: (Clone, Eq(K), Hash), V <: Clone),
679
- HashMap(K, V),
680
- Clone(
681
- clone : (fn(self: *(Self)) -> Self)(
682
- {
683
- result := Self.new();
684
- it := self.iter();
685
- running := true;
686
- while running, {
687
- nxt := it.next();
688
- match(nxt,
689
- .None => { running = false; },
690
- .Some(bucket_ptr) => {
691
- k := (&(bucket_ptr.*.key)).clone();
692
- v := (&(bucket_ptr.*.value)).clone();
693
- result.set(k, v);
694
- }
695
- );
696
- };
697
- result
698
- }
699
- )
700
- ));
701
-
702
- export
652
+ impl(
653
+ forall(K : Type, V : Type),
654
+ where(K <: (Clone, Eq(K), Hash), V <: Clone),
655
+ HashMap(K, V),
656
+ Clone(
657
+ clone : (fn(self : *(Self)) -> Self)({
658
+ result := Self.new();
659
+ it := self.iter();
660
+ running := true;
661
+ while(running, {
662
+ nxt := it.next();
663
+ match(
664
+ nxt,
665
+ .None => {
666
+ running = false;
667
+ },
668
+ .Some(bucket_ptr) => {
669
+ k := (&(bucket_ptr.*.key)).clone();
670
+ v := (&(bucket_ptr.*.value)).clone();
671
+ result.set(k, v);
672
+ }
673
+ );
674
+ });
675
+ result
676
+ })
677
+ )
678
+ );
679
+ export(
703
680
  HashMap,
704
681
  HashMapError,
705
682
  Bucket,
@@ -707,12 +684,10 @@ export
707
684
  HashMapIterPtr,
708
685
  HashMapKeys,
709
686
  HashMapValues
710
- ;
711
-
687
+ );
712
688
  // =============================================================================
713
689
  // hash_map! literal macro
714
690
  // =============================================================================
715
-
716
691
  /// Internal helper: build a list of `tmp.set(k, v).unwrap()` statements from
717
692
  /// a sequence of `k => v` arrow expressions.
718
693
  __hash_map_build_sets :: (fn(comptime(tmp) : Expr, comptime(entries) : ExprList) -> comptime(ExprList))(
@@ -723,17 +698,16 @@ __hash_map_build_sets :: (fn(comptime(tmp) : Expr, comptime(entries) : ExprList)
723
698
  rest :: entries.cdr();
724
699
  __ :: comptime_assert(first.is_fn_call(), "hash_map entries must use 'k => v'");
725
700
  callee :: first.get_callee();
726
- __1 :: comptime_assert((callee.is_atom() && (callee == quote(=>))), "hash_map entries must use 'k => v'");
701
+ __1 :: comptime_assert(callee.is_atom() && (callee == quote(=>)), "hash_map entries must use 'k => v'");
727
702
  pair :: first.get_args();
728
- __2 :: comptime_assert((pair.len() == usize(2)), "hash_map entries must use 'k => v'");
703
+ __2 :: comptime_assert(pair.len() == usize(2), "hash_map entries must use 'k => v'");
729
704
  key :: pair.car();
730
705
  val :: pair.cdr().car();
731
- stmt :: quote((unquote(tmp).set(unquote(key), unquote(val)).unwrap()));
706
+ stmt :: quote(unquote(tmp).set(unquote(key), unquote(val)).unwrap());
732
707
  stmt.cons(recur(tmp, rest))
733
708
  }
734
709
  )
735
710
  );
736
-
737
711
  /// `hash_map` macro — construct a `HashMap(K, V)` literal.
738
712
  ///
739
713
  /// `K` and `V` are inferred from the first entry's key and value via `typeof`,
@@ -743,15 +717,17 @@ __hash_map_build_sets :: (fn(comptime(tmp) : Expr, comptime(entries) : ExprList)
743
717
  /// ```rust
744
718
  /// m := hash_map(`a` => i32(1), `b` => i32(2));
745
719
  /// ```
746
- hash_map :: (fn(...(quote(entries))) -> unquote(Expr)) {
747
- __ :: comptime_assert((entries.len() > usize(0)),
748
- "hash_map requires at least one 'k => v' entry to infer K and V");
720
+ hash_map :: (fn(...(quote(entries))) -> unquote(Expr))({
721
+ __ :: comptime_assert(
722
+ entries.len() > usize(0),
723
+ "hash_map requires at least one 'k => v' entry to infer K and V"
724
+ );
749
725
  first :: entries.car();
750
726
  __1 :: comptime_assert(first.is_fn_call(), "hash_map entries must use 'k => v'");
751
727
  callee :: first.get_callee();
752
- __2 :: comptime_assert((callee.is_atom() && (callee == quote(=>))), "hash_map entries must use 'k => v'");
728
+ __2 :: comptime_assert(callee.is_atom() && (callee == quote(=>)), "hash_map entries must use 'k => v'");
753
729
  pair :: first.get_args();
754
- __3 :: comptime_assert((pair.len() == usize(2)), "hash_map entries must use 'k => v'");
730
+ __3 :: comptime_assert(pair.len() == usize(2), "hash_map entries must use 'k => v'");
755
731
  first_key :: pair.car();
756
732
  first_val :: pair.cdr().car();
757
733
  rest :: entries.cdr();
@@ -759,13 +735,13 @@ hash_map :: (fn(...(quote(entries))) -> unquote(Expr)) {
759
735
  k_tmp :: gensym("hash_map_k0");
760
736
  v_tmp :: gensym("hash_map_v0");
761
737
  rest_sets :: __hash_map_build_sets(tmp, rest);
762
- quote {
738
+ quote({
763
739
  unquote(k_tmp) := unquote(first_key);
764
740
  unquote(v_tmp) := unquote(first_val);
765
741
  unquote(tmp) := HashMap(typeof(unquote(k_tmp)), typeof(unquote(v_tmp))).new();
766
742
  unquote(tmp).set(unquote(k_tmp), unquote(v_tmp)).unwrap();
767
743
  unquote_splicing(rest_sets);
768
744
  unquote(tmp)
769
- }
770
- };
771
- export hash_map;
745
+ })
746
+ });
747
+ export(hash_map);