@@ -129,14 +129,10 @@ pub fn StaticArrayMapWithEql(
129
129
130
130
/// Returns the value for the key if any, else null.
131
131
pub fn get (comptime self : Self , key : []const T ) ? V {
132
- return switch (self .kvs .len ) {
133
- 0 = > null ,
134
- 1 = > blk : {
135
- const equal = std .mem .eql (T , self .kvs [0 ].key , key );
136
- break :blk if (equal ) self .kvs [0 ].value else null ;
137
- },
138
- else = > self .filterLength (key ),
139
- };
132
+ switch (comptime self .kvs .len ) {
133
+ 0 = > return null ,
134
+ else = > return self .filterLength (key ),
135
+ }
140
136
}
141
137
142
138
/// The list of all the keys in the map.
@@ -166,13 +162,30 @@ pub fn StaticArrayMapWithEql(
166
162
/// Filters the input key by length, then compares it to the possible matches.
167
163
/// Because we know the length at comptime, we can compare the strings faster.
168
164
fn filterLength (comptime self : Self , key : []const T ) ? V {
169
- // Provide 2000 branches per key/value pair to compile.
165
+ // separateLength is hungry - provide 2000 branches per key/value pair
170
166
@setEvalBranchQuota (2000 * self .kvs .len );
171
167
const kvs_by_lengths = comptime self .separateLength ();
168
+
172
169
inline for (kvs_by_lengths ) | kvs_by_len | {
173
170
const len = kvs_by_len .length ;
174
171
if (key .len == len ) {
175
- inline for (kvs_by_len .kvs ) | kv | {
172
+ inline for (kvs_by_len .kvs , 0.. ) | kv , idx | {
173
+
174
+ // Out of keys with the same length, check for duplicates
175
+ @setEvalBranchQuota (10 * len * idx );
176
+ comptime for (kvs_by_len .kvs [0.. idx ]) | prev_kv | {
177
+ if (eql (kv .key [0.. len ].* , prev_kv .key [0.. len ].* )) {
178
+ if (T == u8 and std .unicode .utf8ValidateSlice (kv .key )) {
179
+ @compileError ("duplicate key \" " ++ kv .key ++ "\" " );
180
+ } else {
181
+ @compileError (std .fmt .comptimePrint (
182
+ "duplicate key: {any}" ,
183
+ .{kv .key },
184
+ ));
185
+ }
186
+ }
187
+ };
188
+
176
189
if (eql (kv .key [0.. len ].* , key [0.. len ].* )) {
177
190
return kv .value ;
178
191
}
@@ -200,6 +213,7 @@ pub fn StaticArrayMapWithEql(
200
213
}
201
214
}
202
215
216
+ // Add keys with the same length to the set.
203
217
var added_kvs : []const Kv = &.{};
204
218
for (self .kvs [index .. ]) | add_kv | {
205
219
if (add_kv .key .len == length ) {
@@ -361,42 +375,6 @@ test "empty" {
361
375
try testing .expect (null == m2 .get ("anything" ));
362
376
}
363
377
364
- test "redundant entries" {
365
- const slice = [_ ]TestKV {
366
- .{ "redundant" , .D },
367
- .{ "theNeedle" , .A },
368
- .{ "redundant" , .B },
369
- .{ "re" ++ "dundant" , .C },
370
- .{ "redun" ++ "dant" , .E },
371
- };
372
- const map = TestMap .initComptime (slice );
373
-
374
- // No promises about which one you get:
375
- try testing .expect (null != map .get ("redundant" ));
376
-
377
- // Default map is not case sensitive:
378
- try testing .expect (null == map .get ("REDUNDANT" ));
379
-
380
- try testing .expectEqual (TestEnum .A , map .get ("theNeedle" ).? );
381
- }
382
-
383
- test "redundant insensitive" {
384
- const slice = [_ ]TestKV {
385
- .{ "redundant" , .D },
386
- .{ "theNeedle" , .A },
387
- .{ "redundanT" , .B },
388
- .{ "RE" ++ "dundant" , .C },
389
- .{ "redun" ++ "DANT" , .E },
390
- };
391
-
392
- const map = TestMapIgnoreCase .initComptime (slice );
393
-
394
- // No promises about which result you'll get ...
395
- try testing .expect (null != map .get ("REDUNDANT" ));
396
- try testing .expect (null != map .get ("ReDuNdAnT" ));
397
- try testing .expectEqual (TestEnum .A , map .get ("theNeedle" ).? );
398
- }
399
-
400
378
test "comptime-only value" {
401
379
const map = StaticStringMap (type ).initComptime (.{
402
380
.{ "a" , struct {
@@ -482,3 +460,18 @@ test "array elements that are padded" {
482
460
try testing .expectEqual (1 , map .get (&.{ 0 , 1 , 127 , 3 , 4 , 5 }));
483
461
try testing .expectEqual (2 , map .get (&.{ 0 , 1 , 2 , 126 , 4 , 5 }));
484
462
}
463
+
464
+ test "single string StaticStringMap" {
465
+ const map = StaticStringMap (void ).initComptime (.{.{"o kama pona" }});
466
+
467
+ try testing .expectEqual (true , map .has ("o kama pona" ));
468
+ try testing .expectEqual (false , map .has ("o kama ike" ));
469
+ try testing .expectEqual (false , map .has ("o kama pona ala" ));
470
+ }
471
+
472
+ test "empty StaticStringMap" {
473
+ const map = StaticStringMap (void ).initComptime (.{});
474
+ try testing .expectEqual (false , map .has (&.{}));
475
+ try testing .expectEqual (null , map .get (&.{}));
476
+ try testing .expectEqual (false , map .has ("anything really" ));
477
+ }
0 commit comments