diff options
| author | Pat Tullmann <pat.github@tullmann.org> | 2023-12-08 19:33:39 -0800 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2024-01-05 05:09:24 +0200 |
| commit | 04ac028a2cd20ea430dd6a05b956363ec182b6ff (patch) | |
| tree | 4cb9ec2bc8185c90b5bbd7b1ae1adc56823dd808 /lib/std/comptime_string_map.zig | |
| parent | 45836678d76014f94d35a2ffea983c21a57426c4 (diff) | |
| download | zig-04ac028a2cd20ea430dd6a05b956363ec182b6ff.tar.gz zig-04ac028a2cd20ea430dd6a05b956363ec182b6ff.zip | |
std.CompTimeStringMap*: support empty initialization list
Add tests for empty initialization, and some more corner cases (empty key,
very long key, duplicate keys).
Fixes #18212
Diffstat (limited to 'lib/std/comptime_string_map.zig')
| -rw-r--r-- | lib/std/comptime_string_map.zig | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/lib/std/comptime_string_map.zig b/lib/std/comptime_string_map.zig index 486677e4b3..f4da1490b7 100644 --- a/lib/std/comptime_string_map.zig +++ b/lib/std/comptime_string_map.zig @@ -43,12 +43,15 @@ pub fn ComptimeStringMapWithEql( comptime kvs_list: anytype, comptime eql: fn (a: []const u8, b: []const u8) bool, ) type { - const precomputed = comptime blk: { + const empty_list = kvs_list.len == 0; + const precomputed = blk: { @setEvalBranchQuota(1500); const KV = struct { key: []const u8, value: V, }; + if (empty_list) + break :blk .{}; var sorted_kvs: [kvs_list.len]KV = undefined; for (kvs_list, 0..) |kv, i| { if (V != void) { @@ -103,10 +106,16 @@ pub fn ComptimeStringMapWithEql( /// Returns the value for the key if any, else null. pub fn get(str: []const u8) ?V { + if (empty_list) + return null; + return precomputed.sorted_kvs[getIndex(str) orelse return null].value; } pub fn getIndex(str: []const u8) ?usize { + if (empty_list) + return null; + if (str.len < precomputed.min_len or str.len > precomputed.max_len) return null; @@ -143,6 +152,9 @@ test "ComptimeStringMap list literal of list literals" { }); try testMap(map); + + // Default comparison is case sensitive + try std.testing.expect(null == map.get("NOTHING")); } test "ComptimeStringMap array of structs" { @@ -181,6 +193,9 @@ fn testMap(comptime map: anytype) !void { try std.testing.expect(!map.has("missing")); try std.testing.expect(map.has("these")); + + try std.testing.expect(null == map.get("")); + try std.testing.expect(null == map.get("averylongstringthathasnomatches")); } test "ComptimeStringMap void value type, slice of structs" { @@ -195,6 +210,9 @@ test "ComptimeStringMap void value type, slice of structs" { const map = ComptimeStringMap(void, slice); try testSet(map); + + // Default comparison is case sensitive + try std.testing.expect(null == map.get("NOTHING")); } test "ComptimeStringMap void value type, list literal of list literals" { @@ -218,6 +236,9 @@ fn testSet(comptime map: anytype) !void { try std.testing.expect(!map.has("missing")); try std.testing.expect(map.has("these")); + + try std.testing.expect(null == map.get("")); + try std.testing.expect(null == map.get("averylongstringthathasnomatches")); } test "ComptimeStringMapWithEql" { @@ -236,3 +257,45 @@ test "ComptimeStringMapWithEql" { try std.testing.expect(map.has("ThESe")); } + +test "ComptimeStringMap empty" { + const m1 = ComptimeStringMap(usize, .{}); + try std.testing.expect(null == m1.get("anything")); + + const m2 = ComptimeStringMapWithEql(usize, .{}, eqlAsciiIgnoreCase); + try std.testing.expect(null == m2.get("anything")); +} + +test "ComptimeStringMap redundant entries" { + const map = ComptimeStringMap(TestEnum, .{ + .{ "redundant", .D }, + .{ "theNeedle", .A }, + .{ "redundant", .B }, + .{ "re" ++ "dundant", .C }, + .{ "redun" ++ "dant", .E }, + }); + + // No promises about which one you get: + try std.testing.expect(null != map.get("redundant")); + + // Default map is not case sensitive: + try std.testing.expect(null == map.get("REDUNDANT")); + + try std.testing.expectEqual(TestEnum.A, map.get("theNeedle").?); +} + +test "ComptimeStringMap redundant insensitive" { + const map = ComptimeStringMapWithEql(TestEnum, .{ + .{ "redundant", .D }, + .{ "theNeedle", .A }, + .{ "redundanT", .B }, + .{ "RE" ++ "dundant", .C }, + .{ "redun" ++ "DANT", .E }, + }, eqlAsciiIgnoreCase); + + // No promises about which result you'll get ... + try std.testing.expect(null != map.get("REDUNDANT")); + try std.testing.expect(null != map.get("ReDuNdAnT")); + + try std.testing.expectEqual(TestEnum.A, map.get("theNeedle").?); +} |
