| author | |
| committer | |
| log | 8af59d1f98266bd70b3afb44d196bbd151cedf22 |
| tree | 64b0c48f2b2d222629acbd5698c1f5310fdc708f |
| parent | fefdbca6e62145a20777789961262f15c2bf6cbe |
this patch renames ComptimeStringMap to StaticStringMap, makes it
accept only a single type parameter, and return a known struct type
instead of an anonymous struct. initial motivation for these changes
was to reduce the 'very long type names' issue described here
https://github.com/ziglang/zig/pull/19682.
this breaks the previous API. users will now need to write:
`const map = std.StaticStringMap(T).initComptime(kvs_list);`
* move `kvs_list` param from type param to an `initComptime()` param
* new public methods
* `keys()`, `values()` helpers
* `init(allocator)`, `deinit(allocator)` for runtime data
* `getLongestPrefix(str)`, `getLongestPrefixIndex(str)` - i'm not sure
these belong but have left in for now incase they are deemed useful
* performance notes:
* i posted some benchmarking results here:
https://github.com/travisstaloch/comptime-string-map-revised/issues/1
* i noticed a speedup reducing the size of the struct from 48 to 32
bytes and thus use u32s instead of usize for all length fields
* i noticed speedup storing KVs as a struct of arrays
* latest benchmark shows these wall_time improvements for
debug/safe/small/fast builds: -6.6% / -10.2% / -19.1% / -8.9%. full
output in link above.25 files changed, 608 insertions(+), 387 deletions(-)
CMakeLists.txt+1-1| ... | @@ -222,7 +222,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -222,7 +222,7 @@ set(ZIG_STAGE2_SOURCES |
| 222 | "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig" | 222 | "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig" |
| 223 | "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig" | 223 | "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig" |
| 224 | "${CMAKE_SOURCE_DIR}/lib/std/coff.zig" | 224 | "${CMAKE_SOURCE_DIR}/lib/std/coff.zig" |
| 225 | "${CMAKE_SOURCE_DIR}/lib/std/comptime_string_map.zig" | 225 | "${CMAKE_SOURCE_DIR}/lib/std/static_string_map.zig" |
| 226 | "${CMAKE_SOURCE_DIR}/lib/std/crypto.zig" | 226 | "${CMAKE_SOURCE_DIR}/lib/std/crypto.zig" |
| 227 | "${CMAKE_SOURCE_DIR}/lib/std/crypto/blake3.zig" | 227 | "${CMAKE_SOURCE_DIR}/lib/std/crypto/blake3.zig" |
| 228 | "${CMAKE_SOURCE_DIR}/lib/std/crypto/siphash.zig" | 228 | "${CMAKE_SOURCE_DIR}/lib/std/crypto/siphash.zig" |
lib/compiler/aro/aro/LangOpts.zig+1-1| ... | @@ -47,7 +47,7 @@ pub const Standard = enum { | ... | @@ -47,7 +47,7 @@ pub const Standard = enum { |
| 47 | /// Working Draft for ISO C23 with GNU extensions | 47 | /// Working Draft for ISO C23 with GNU extensions |
| 48 | gnu23, | 48 | gnu23, |
| 49 | 49 | ||
| 50 | const NameMap = std.ComptimeStringMap(Standard, .{ | 50 | const NameMap = std.StaticStringMap(Standard).initComptime(.{ |
| 51 | .{ "c89", .c89 }, .{ "c90", .c89 }, .{ "iso9899:1990", .c89 }, | 51 | .{ "c89", .c89 }, .{ "c90", .c89 }, .{ "iso9899:1990", .c89 }, |
| 52 | .{ "iso9899:199409", .iso9899 }, .{ "gnu89", .gnu89 }, .{ "gnu90", .gnu89 }, | 52 | .{ "iso9899:199409", .iso9899 }, .{ "gnu89", .gnu89 }, .{ "gnu90", .gnu89 }, |
| 53 | .{ "c99", .c99 }, .{ "iso9899:1999", .c99 }, .{ "c9x", .c99 }, | 53 | .{ "c99", .c99 }, .{ "iso9899:1999", .c99 }, .{ "c9x", .c99 }, |
lib/compiler/aro/aro/Preprocessor.zig+1-1| ... | @@ -1709,7 +1709,7 @@ fn expandFuncMacro( | ... | @@ -1709,7 +1709,7 @@ fn expandFuncMacro( |
| 1709 | } | 1709 | } |
| 1710 | if (!pp.comp.langopts.standard.atLeast(.c23)) break :res not_found; | 1710 | if (!pp.comp.langopts.standard.atLeast(.c23)) break :res not_found; |
| 1711 | 1711 | ||
| 1712 | const attrs = std.ComptimeStringMap([]const u8, .{ | 1712 | const attrs = std.StaticStringMap([]const u8).initComptime(.{ |
| 1713 | .{ "deprecated", "201904L\n" }, | 1713 | .{ "deprecated", "201904L\n" }, |
| 1714 | .{ "fallthrough", "201904L\n" }, | 1714 | .{ "fallthrough", "201904L\n" }, |
| 1715 | .{ "maybe_unused", "201904L\n" }, | 1715 | .{ "maybe_unused", "201904L\n" }, |
lib/compiler/aro/aro/Tokenizer.zig+1-1| ... | @@ -872,7 +872,7 @@ pub const Token = struct { | ... | @@ -872,7 +872,7 @@ pub const Token = struct { |
| 872 | }; | 872 | }; |
| 873 | } | 873 | } |
| 874 | 874 | ||
| 875 | const all_kws = std.ComptimeStringMap(Id, .{ | 875 | const all_kws = std.StaticStringMap(Id).initComptime(.{ |
| 876 | .{ "auto", auto: { | 876 | .{ "auto", auto: { |
| 877 | @setEvalBranchQuota(3000); | 877 | @setEvalBranchQuota(3000); |
| 878 | break :auto .keyword_auto; | 878 | break :auto .keyword_auto; |
lib/compiler/resinator/errors.zig+1-1| ... | @@ -240,7 +240,7 @@ pub const ErrorDetails = struct { | ... | @@ -240,7 +240,7 @@ pub const ErrorDetails = struct { |
| 240 | // see https://github.com/ziglang/zig/issues/15395 | 240 | // see https://github.com/ziglang/zig/issues/15395 |
| 241 | _: u26 = 0, | 241 | _: u26 = 0, |
| 242 | 242 | ||
| 243 | pub const strings = std.ComptimeStringMap([]const u8, .{ | 243 | pub const strings = std.StaticStringMap([]const u8).initComptime(.{ |
| 244 | .{ "number", "number" }, | 244 | .{ "number", "number" }, |
| 245 | .{ "number_expression", "number expression" }, | 245 | .{ "number_expression", "number expression" }, |
| 246 | .{ "string_literal", "quoted string literal" }, | 246 | .{ "string_literal", "quoted string literal" }, |
lib/compiler/resinator/rc.zig+65-26| ... | @@ -47,7 +47,10 @@ pub const Resource = enum { | ... | @@ -47,7 +47,10 @@ pub const Resource = enum { |
| 47 | fontdir_num, | 47 | fontdir_num, |
| 48 | manifest_num, | 48 | manifest_num, |
| 49 | 49 | ||
| 50 | const map = std.ComptimeStringMapWithEql(Resource, .{ | 50 | const map = std.StaticStringMapWithEql( |
| 51 | Resource, | ||
| 52 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 53 | ).initComptime(.{ | ||
| 51 | .{ "ACCELERATORS", .accelerators }, | 54 | .{ "ACCELERATORS", .accelerators }, |
| 52 | .{ "BITMAP", .bitmap }, | 55 | .{ "BITMAP", .bitmap }, |
| 53 | .{ "CURSOR", .cursor }, | 56 | .{ "CURSOR", .cursor }, |
| ... | @@ -67,7 +70,7 @@ pub const Resource = enum { | ... | @@ -67,7 +70,7 @@ pub const Resource = enum { |
| 67 | .{ "TOOLBAR", .toolbar }, | 70 | .{ "TOOLBAR", .toolbar }, |
| 68 | .{ "VERSIONINFO", .versioninfo }, | 71 | .{ "VERSIONINFO", .versioninfo }, |
| 69 | .{ "VXD", .vxd }, | 72 | .{ "VXD", .vxd }, |
| 70 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 73 | }); |
| 71 | 74 | ||
| 72 | pub fn fromString(bytes: SourceBytes) Resource { | 75 | pub fn fromString(bytes: SourceBytes) Resource { |
| 73 | const maybe_ordinal = res.NameOrOrdinal.maybeOrdinalFromString(bytes); | 76 | const maybe_ordinal = res.NameOrOrdinal.maybeOrdinalFromString(bytes); |
| ... | @@ -157,20 +160,26 @@ pub const OptionalStatements = enum { | ... | @@ -157,20 +160,26 @@ pub const OptionalStatements = enum { |
| 157 | menu, | 160 | menu, |
| 158 | style, | 161 | style, |
| 159 | 162 | ||
| 160 | pub const map = std.ComptimeStringMapWithEql(OptionalStatements, .{ | 163 | pub const map = std.StaticStringMapWithEql( |
| 164 | OptionalStatements, | ||
| 165 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 166 | ).initComptime(.{ | ||
| 161 | .{ "CHARACTERISTICS", .characteristics }, | 167 | .{ "CHARACTERISTICS", .characteristics }, |
| 162 | .{ "LANGUAGE", .language }, | 168 | .{ "LANGUAGE", .language }, |
| 163 | .{ "VERSION", .version }, | 169 | .{ "VERSION", .version }, |
| 164 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 170 | }); |
| 165 | 171 | ||
| 166 | pub const dialog_map = std.ComptimeStringMapWithEql(OptionalStatements, .{ | 172 | pub const dialog_map = std.StaticStringMapWithEql( |
| 173 | OptionalStatements, | ||
| 174 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 175 | ).initComptime(.{ | ||
| 167 | .{ "CAPTION", .caption }, | 176 | .{ "CAPTION", .caption }, |
| 168 | .{ "CLASS", .class }, | 177 | .{ "CLASS", .class }, |
| 169 | .{ "EXSTYLE", .exstyle }, | 178 | .{ "EXSTYLE", .exstyle }, |
| 170 | .{ "FONT", .font }, | 179 | .{ "FONT", .font }, |
| 171 | .{ "MENU", .menu }, | 180 | .{ "MENU", .menu }, |
| 172 | .{ "STYLE", .style }, | 181 | .{ "STYLE", .style }, |
| 173 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 182 | }); |
| 174 | }; | 183 | }; |
| 175 | 184 | ||
| 176 | pub const Control = enum { | 185 | pub const Control = enum { |
| ... | @@ -197,7 +206,10 @@ pub const Control = enum { | ... | @@ -197,7 +206,10 @@ pub const Control = enum { |
| 197 | state3, | 206 | state3, |
| 198 | userbutton, | 207 | userbutton, |
| 199 | 208 | ||
| 200 | pub const map = std.ComptimeStringMapWithEql(Control, .{ | 209 | pub const map = std.StaticStringMapWithEql( |
| 210 | Control, | ||
| 211 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 212 | ).initComptime(.{ | ||
| 201 | .{ "AUTO3STATE", .auto3state }, | 213 | .{ "AUTO3STATE", .auto3state }, |
| 202 | .{ "AUTOCHECKBOX", .autocheckbox }, | 214 | .{ "AUTOCHECKBOX", .autocheckbox }, |
| 203 | .{ "AUTORADIOBUTTON", .autoradiobutton }, | 215 | .{ "AUTORADIOBUTTON", .autoradiobutton }, |
| ... | @@ -220,7 +232,7 @@ pub const Control = enum { | ... | @@ -220,7 +232,7 @@ pub const Control = enum { |
| 220 | .{ "SCROLLBAR", .scrollbar }, | 232 | .{ "SCROLLBAR", .scrollbar }, |
| 221 | .{ "STATE3", .state3 }, | 233 | .{ "STATE3", .state3 }, |
| 222 | .{ "USERBUTTON", .userbutton }, | 234 | .{ "USERBUTTON", .userbutton }, |
| 223 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 235 | }); |
| 224 | 236 | ||
| 225 | pub fn hasTextParam(control: Control) bool { | 237 | pub fn hasTextParam(control: Control) bool { |
| 226 | switch (control) { | 238 | switch (control) { |
| ... | @@ -231,14 +243,17 @@ pub const Control = enum { | ... | @@ -231,14 +243,17 @@ pub const Control = enum { |
| 231 | }; | 243 | }; |
| 232 | 244 | ||
| 233 | pub const ControlClass = struct { | 245 | pub const ControlClass = struct { |
| 234 | pub const map = std.ComptimeStringMapWithEql(res.ControlClass, .{ | 246 | pub const map = std.StaticStringMapWithEql( |
| 247 | res.ControlClass, | ||
| 248 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 249 | ).initComptime(.{ | ||
| 235 | .{ "BUTTON", .button }, | 250 | .{ "BUTTON", .button }, |
| 236 | .{ "EDIT", .edit }, | 251 | .{ "EDIT", .edit }, |
| 237 | .{ "STATIC", .static }, | 252 | .{ "STATIC", .static }, |
| 238 | .{ "LISTBOX", .listbox }, | 253 | .{ "LISTBOX", .listbox }, |
| 239 | .{ "SCROLLBAR", .scrollbar }, | 254 | .{ "SCROLLBAR", .scrollbar }, |
| 240 | .{ "COMBOBOX", .combobox }, | 255 | .{ "COMBOBOX", .combobox }, |
| 241 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 256 | }); |
| 242 | 257 | ||
| 243 | /// Like `map.get` but works on WTF16 strings, for use with parsed | 258 | /// Like `map.get` but works on WTF16 strings, for use with parsed |
| 244 | /// string literals ("BUTTON", or even "\x42UTTON") | 259 | /// string literals ("BUTTON", or even "\x42UTTON") |
| ... | @@ -280,10 +295,13 @@ pub const MenuItem = enum { | ... | @@ -280,10 +295,13 @@ pub const MenuItem = enum { |
| 280 | menuitem, | 295 | menuitem, |
| 281 | popup, | 296 | popup, |
| 282 | 297 | ||
| 283 | pub const map = std.ComptimeStringMapWithEql(MenuItem, .{ | 298 | pub const map = std.StaticStringMapWithEql( |
| 299 | MenuItem, | ||
| 300 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 301 | ).initComptime(.{ | ||
| 284 | .{ "MENUITEM", .menuitem }, | 302 | .{ "MENUITEM", .menuitem }, |
| 285 | .{ "POPUP", .popup }, | 303 | .{ "POPUP", .popup }, |
| 286 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 304 | }); |
| 287 | 305 | ||
| 288 | pub fn isSeparator(bytes: []const u8) bool { | 306 | pub fn isSeparator(bytes: []const u8) bool { |
| 289 | return std.ascii.eqlIgnoreCase(bytes, "SEPARATOR"); | 307 | return std.ascii.eqlIgnoreCase(bytes, "SEPARATOR"); |
| ... | @@ -297,14 +315,17 @@ pub const MenuItem = enum { | ... | @@ -297,14 +315,17 @@ pub const MenuItem = enum { |
| 297 | menubarbreak, | 315 | menubarbreak, |
| 298 | menubreak, | 316 | menubreak, |
| 299 | 317 | ||
| 300 | pub const map = std.ComptimeStringMapWithEql(Option, .{ | 318 | pub const map = std.StaticStringMapWithEql( |
| 319 | Option, | ||
| 320 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 321 | ).initComptime(.{ | ||
| 301 | .{ "CHECKED", .checked }, | 322 | .{ "CHECKED", .checked }, |
| 302 | .{ "GRAYED", .grayed }, | 323 | .{ "GRAYED", .grayed }, |
| 303 | .{ "HELP", .help }, | 324 | .{ "HELP", .help }, |
| 304 | .{ "INACTIVE", .inactive }, | 325 | .{ "INACTIVE", .inactive }, |
| 305 | .{ "MENUBARBREAK", .menubarbreak }, | 326 | .{ "MENUBARBREAK", .menubarbreak }, |
| 306 | .{ "MENUBREAK", .menubreak }, | 327 | .{ "MENUBREAK", .menubreak }, |
| 307 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 328 | }); |
| 308 | }; | 329 | }; |
| 309 | }; | 330 | }; |
| 310 | 331 | ||
| ... | @@ -312,10 +333,13 @@ pub const ToolbarButton = enum { | ... | @@ -312,10 +333,13 @@ pub const ToolbarButton = enum { |
| 312 | button, | 333 | button, |
| 313 | separator, | 334 | separator, |
| 314 | 335 | ||
| 315 | pub const map = std.ComptimeStringMapWithEql(ToolbarButton, .{ | 336 | pub const map = std.StaticStringMapWithEql( |
| 337 | ToolbarButton, | ||
| 338 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 339 | ).initComptime(.{ | ||
| 316 | .{ "BUTTON", .button }, | 340 | .{ "BUTTON", .button }, |
| 317 | .{ "SEPARATOR", .separator }, | 341 | .{ "SEPARATOR", .separator }, |
| 318 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 342 | }); |
| 319 | }; | 343 | }; |
| 320 | 344 | ||
| 321 | pub const VersionInfo = enum { | 345 | pub const VersionInfo = enum { |
| ... | @@ -327,7 +351,10 @@ pub const VersionInfo = enum { | ... | @@ -327,7 +351,10 @@ pub const VersionInfo = enum { |
| 327 | file_type, | 351 | file_type, |
| 328 | file_subtype, | 352 | file_subtype, |
| 329 | 353 | ||
| 330 | pub const map = std.ComptimeStringMapWithEql(VersionInfo, .{ | 354 | pub const map = std.StaticStringMapWithEql( |
| 355 | VersionInfo, | ||
| 356 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 357 | ).initComptime(.{ | ||
| 331 | .{ "FILEVERSION", .file_version }, | 358 | .{ "FILEVERSION", .file_version }, |
| 332 | .{ "PRODUCTVERSION", .product_version }, | 359 | .{ "PRODUCTVERSION", .product_version }, |
| 333 | .{ "FILEFLAGSMASK", .file_flags_mask }, | 360 | .{ "FILEFLAGSMASK", .file_flags_mask }, |
| ... | @@ -335,17 +362,20 @@ pub const VersionInfo = enum { | ... | @@ -335,17 +362,20 @@ pub const VersionInfo = enum { |
| 335 | .{ "FILEOS", .file_os }, | 362 | .{ "FILEOS", .file_os }, |
| 336 | .{ "FILETYPE", .file_type }, | 363 | .{ "FILETYPE", .file_type }, |
| 337 | .{ "FILESUBTYPE", .file_subtype }, | 364 | .{ "FILESUBTYPE", .file_subtype }, |
| 338 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 365 | }); |
| 339 | }; | 366 | }; |
| 340 | 367 | ||
| 341 | pub const VersionBlock = enum { | 368 | pub const VersionBlock = enum { |
| 342 | block, | 369 | block, |
| 343 | value, | 370 | value, |
| 344 | 371 | ||
| 345 | pub const map = std.ComptimeStringMapWithEql(VersionBlock, .{ | 372 | pub const map = std.StaticStringMapWithEql( |
| 373 | VersionBlock, | ||
| 374 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 375 | ).initComptime(.{ | ||
| 346 | .{ "BLOCK", .block }, | 376 | .{ "BLOCK", .block }, |
| 347 | .{ "VALUE", .value }, | 377 | .{ "VALUE", .value }, |
| 348 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 378 | }); |
| 349 | }; | 379 | }; |
| 350 | 380 | ||
| 351 | /// Keywords that are be the first token in a statement and (if so) dictate how the rest | 381 | /// Keywords that are be the first token in a statement and (if so) dictate how the rest |
| ... | @@ -356,12 +386,15 @@ pub const TopLevelKeywords = enum { | ... | @@ -356,12 +386,15 @@ pub const TopLevelKeywords = enum { |
| 356 | characteristics, | 386 | characteristics, |
| 357 | stringtable, | 387 | stringtable, |
| 358 | 388 | ||
| 359 | pub const map = std.ComptimeStringMapWithEql(TopLevelKeywords, .{ | 389 | pub const map = std.StaticStringMapWithEql( |
| 390 | TopLevelKeywords, | ||
| 391 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 392 | ).initComptime(.{ | ||
| 360 | .{ "LANGUAGE", .language }, | 393 | .{ "LANGUAGE", .language }, |
| 361 | .{ "VERSION", .version }, | 394 | .{ "VERSION", .version }, |
| 362 | .{ "CHARACTERISTICS", .characteristics }, | 395 | .{ "CHARACTERISTICS", .characteristics }, |
| 363 | .{ "STRINGTABLE", .stringtable }, | 396 | .{ "STRINGTABLE", .stringtable }, |
| 364 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 397 | }); |
| 365 | }; | 398 | }; |
| 366 | 399 | ||
| 367 | pub const CommonResourceAttributes = enum { | 400 | pub const CommonResourceAttributes = enum { |
| ... | @@ -375,7 +408,10 @@ pub const CommonResourceAttributes = enum { | ... | @@ -375,7 +408,10 @@ pub const CommonResourceAttributes = enum { |
| 375 | shared, | 408 | shared, |
| 376 | nonshared, | 409 | nonshared, |
| 377 | 410 | ||
| 378 | pub const map = std.ComptimeStringMapWithEql(CommonResourceAttributes, .{ | 411 | pub const map = std.StaticStringMapWithEql( |
| 412 | CommonResourceAttributes, | ||
| 413 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 414 | ).initComptime(.{ | ||
| 379 | .{ "PRELOAD", .preload }, | 415 | .{ "PRELOAD", .preload }, |
| 380 | .{ "LOADONCALL", .loadoncall }, | 416 | .{ "LOADONCALL", .loadoncall }, |
| 381 | .{ "FIXED", .fixed }, | 417 | .{ "FIXED", .fixed }, |
| ... | @@ -385,7 +421,7 @@ pub const CommonResourceAttributes = enum { | ... | @@ -385,7 +421,7 @@ pub const CommonResourceAttributes = enum { |
| 385 | .{ "IMPURE", .impure }, | 421 | .{ "IMPURE", .impure }, |
| 386 | .{ "SHARED", .shared }, | 422 | .{ "SHARED", .shared }, |
| 387 | .{ "NONSHARED", .nonshared }, | 423 | .{ "NONSHARED", .nonshared }, |
| 388 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 424 | }); |
| 389 | }; | 425 | }; |
| 390 | 426 | ||
| 391 | pub const AcceleratorTypeAndOptions = enum { | 427 | pub const AcceleratorTypeAndOptions = enum { |
| ... | @@ -396,12 +432,15 @@ pub const AcceleratorTypeAndOptions = enum { | ... | @@ -396,12 +432,15 @@ pub const AcceleratorTypeAndOptions = enum { |
| 396 | shift, | 432 | shift, |
| 397 | control, | 433 | control, |
| 398 | 434 | ||
| 399 | pub const map = std.ComptimeStringMapWithEql(AcceleratorTypeAndOptions, .{ | 435 | pub const map = std.StaticStringMapWithEql( |
| 436 | AcceleratorTypeAndOptions, | ||
| 437 | std.static_string_map.eqlAsciiIgnoreCase, | ||
| 438 | ).initComptime(.{ | ||
| 400 | .{ "VIRTKEY", .virtkey }, | 439 | .{ "VIRTKEY", .virtkey }, |
| 401 | .{ "ASCII", .ascii }, | 440 | .{ "ASCII", .ascii }, |
| 402 | .{ "NOINVERT", .noinvert }, | 441 | .{ "NOINVERT", .noinvert }, |
| 403 | .{ "ALT", .alt }, | 442 | .{ "ALT", .alt }, |
| 404 | .{ "SHIFT", .shift }, | 443 | .{ "SHIFT", .shift }, |
| 405 | .{ "CONTROL", .control }, | 444 | .{ "CONTROL", .control }, |
| 406 | }, std.comptime_string_map.eqlAsciiIgnoreCase); | 445 | }); |
| 407 | }; | 446 | }; |
lib/std/comptime_string_map.zig deleted-320| ... | @@ -1,320 +0,0 @@ | ||
| 1 | const std = @import("std.zig"); | ||
| 2 | const mem = std.mem; | ||
| 3 | |||
| 4 | /// Comptime string map optimized for small sets of disparate string keys. | ||
| 5 | /// Works by separating the keys by length at comptime and only checking strings of | ||
| 6 | /// equal length at runtime. | ||
| 7 | /// | ||
| 8 | /// `kvs_list` expects a list of `struct { []const u8, V }` (key-value pair) tuples. | ||
| 9 | /// You can pass `struct { []const u8 }` (only keys) tuples if `V` is `void`. | ||
| 10 | pub fn ComptimeStringMap( | ||
| 11 | comptime V: type, | ||
| 12 | comptime kvs_list: anytype, | ||
| 13 | ) type { | ||
| 14 | return ComptimeStringMapWithEql(V, kvs_list, defaultEql); | ||
| 15 | } | ||
| 16 | |||
| 17 | /// Like `std.mem.eql`, but takes advantage of the fact that the lengths | ||
| 18 | /// of `a` and `b` are known to be equal. | ||
| 19 | pub fn defaultEql(a: []const u8, b: []const u8) bool { | ||
| 20 | if (a.ptr == b.ptr) return true; | ||
| 21 | for (a, b) |a_elem, b_elem| { | ||
| 22 | if (a_elem != b_elem) return false; | ||
| 23 | } | ||
| 24 | return true; | ||
| 25 | } | ||
| 26 | |||
| 27 | /// Like `std.ascii.eqlIgnoreCase` but takes advantage of the fact that | ||
| 28 | /// the lengths of `a` and `b` are known to be equal. | ||
| 29 | pub fn eqlAsciiIgnoreCase(a: []const u8, b: []const u8) bool { | ||
| 30 | if (a.ptr == b.ptr) return true; | ||
| 31 | for (a, b) |a_c, b_c| { | ||
| 32 | if (std.ascii.toLower(a_c) != std.ascii.toLower(b_c)) return false; | ||
| 33 | } | ||
| 34 | return true; | ||
| 35 | } | ||
| 36 | |||
| 37 | /// ComptimeStringMap, but accepts an equality function (`eql`). | ||
| 38 | /// The `eql` function is only called to determine the equality | ||
| 39 | /// of equal length strings. Any strings that are not equal length | ||
| 40 | /// are never compared using the `eql` function. | ||
| 41 | pub fn ComptimeStringMapWithEql( | ||
| 42 | comptime V: type, | ||
| 43 | comptime kvs_list: anytype, | ||
| 44 | comptime eql: fn (a: []const u8, b: []const u8) bool, | ||
| 45 | ) type { | ||
| 46 | const empty_list = kvs_list.len == 0; | ||
| 47 | const precomputed = blk: { | ||
| 48 | @setEvalBranchQuota(1500); | ||
| 49 | const KV = struct { | ||
| 50 | key: []const u8, | ||
| 51 | value: V, | ||
| 52 | }; | ||
| 53 | if (empty_list) | ||
| 54 | break :blk .{}; | ||
| 55 | var sorted_kvs: [kvs_list.len]KV = undefined; | ||
| 56 | for (kvs_list, 0..) |kv, i| { | ||
| 57 | if (V != void) { | ||
| 58 | sorted_kvs[i] = .{ .key = kv.@"0", .value = kv.@"1" }; | ||
| 59 | } else { | ||
| 60 | sorted_kvs[i] = .{ .key = kv.@"0", .value = {} }; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | const SortContext = struct { | ||
| 65 | kvs: []KV, | ||
| 66 | |||
| 67 | pub fn lessThan(ctx: @This(), a: usize, b: usize) bool { | ||
| 68 | return ctx.kvs[a].key.len < ctx.kvs[b].key.len; | ||
| 69 | } | ||
| 70 | |||
| 71 | pub fn swap(ctx: @This(), a: usize, b: usize) void { | ||
| 72 | return std.mem.swap(KV, &ctx.kvs[a], &ctx.kvs[b]); | ||
| 73 | } | ||
| 74 | }; | ||
| 75 | mem.sortUnstableContext(0, sorted_kvs.len, SortContext{ .kvs = &sorted_kvs }); | ||
| 76 | |||
| 77 | const min_len = sorted_kvs[0].key.len; | ||
| 78 | const max_len = sorted_kvs[sorted_kvs.len - 1].key.len; | ||
| 79 | var len_indexes: [max_len + 1]usize = undefined; | ||
| 80 | var len: usize = 0; | ||
| 81 | var i: usize = 0; | ||
| 82 | while (len <= max_len) : (len += 1) { | ||
| 83 | // find the first keyword len == len | ||
| 84 | while (len > sorted_kvs[i].key.len) { | ||
| 85 | i += 1; | ||
| 86 | } | ||
| 87 | len_indexes[len] = i; | ||
| 88 | } | ||
| 89 | break :blk .{ | ||
| 90 | .min_len = min_len, | ||
| 91 | .max_len = max_len, | ||
| 92 | .sorted_kvs = sorted_kvs, | ||
| 93 | .len_indexes = len_indexes, | ||
| 94 | }; | ||
| 95 | }; | ||
| 96 | |||
| 97 | return struct { | ||
| 98 | /// Array of `struct { key: []const u8, value: V }` where `value` is `void{}` if `V` is `void`. | ||
| 99 | /// Sorted by `key` length. | ||
| 100 | pub const kvs = precomputed.sorted_kvs; | ||
| 101 | |||
| 102 | /// Checks if the map has a value for the key. | ||
| 103 | pub fn has(str: []const u8) bool { | ||
| 104 | return get(str) != null; | ||
| 105 | } | ||
| 106 | |||
| 107 | /// Returns the value for the key if any, else null. | ||
| 108 | pub fn get(str: []const u8) ?V { | ||
| 109 | if (empty_list) | ||
| 110 | return null; | ||
| 111 | |||
| 112 | return precomputed.sorted_kvs[getIndex(str) orelse return null].value; | ||
| 113 | } | ||
| 114 | |||
| 115 | pub fn getIndex(str: []const u8) ?usize { | ||
| 116 | if (empty_list) | ||
| 117 | return null; | ||
| 118 | |||
| 119 | if (str.len < precomputed.min_len or str.len > precomputed.max_len) | ||
| 120 | return null; | ||
| 121 | |||
| 122 | var i = precomputed.len_indexes[str.len]; | ||
| 123 | while (true) { | ||
| 124 | const kv = precomputed.sorted_kvs[i]; | ||
| 125 | if (kv.key.len != str.len) | ||
| 126 | return null; | ||
| 127 | if (eql(kv.key, str)) | ||
| 128 | return i; | ||
| 129 | i += 1; | ||
| 130 | if (i >= precomputed.sorted_kvs.len) | ||
| 131 | return null; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | }; | ||
| 135 | } | ||
| 136 | |||
| 137 | const TestEnum = enum { | ||
| 138 | A, | ||
| 139 | B, | ||
| 140 | C, | ||
| 141 | D, | ||
| 142 | E, | ||
| 143 | }; | ||
| 144 | |||
| 145 | test "list literal of list literals" { | ||
| 146 | const map = ComptimeStringMap(TestEnum, .{ | ||
| 147 | .{ "these", .D }, | ||
| 148 | .{ "have", .A }, | ||
| 149 | .{ "nothing", .B }, | ||
| 150 | .{ "incommon", .C }, | ||
| 151 | .{ "samelen", .E }, | ||
| 152 | }); | ||
| 153 | |||
| 154 | try testMap(map); | ||
| 155 | |||
| 156 | // Default comparison is case sensitive | ||
| 157 | try std.testing.expect(null == map.get("NOTHING")); | ||
| 158 | } | ||
| 159 | |||
| 160 | test "array of structs" { | ||
| 161 | const KV = struct { []const u8, TestEnum }; | ||
| 162 | const map = ComptimeStringMap(TestEnum, [_]KV{ | ||
| 163 | .{ "these", .D }, | ||
| 164 | .{ "have", .A }, | ||
| 165 | .{ "nothing", .B }, | ||
| 166 | .{ "incommon", .C }, | ||
| 167 | .{ "samelen", .E }, | ||
| 168 | }); | ||
| 169 | |||
| 170 | try testMap(map); | ||
| 171 | } | ||
| 172 | |||
| 173 | test "slice of structs" { | ||
| 174 | const KV = struct { []const u8, TestEnum }; | ||
| 175 | const slice: []const KV = &[_]KV{ | ||
| 176 | .{ "these", .D }, | ||
| 177 | .{ "have", .A }, | ||
| 178 | .{ "nothing", .B }, | ||
| 179 | .{ "incommon", .C }, | ||
| 180 | .{ "samelen", .E }, | ||
| 181 | }; | ||
| 182 | const map = ComptimeStringMap(TestEnum, slice); | ||
| 183 | |||
| 184 | try testMap(map); | ||
| 185 | } | ||
| 186 | |||
| 187 | fn testMap(comptime map: anytype) !void { | ||
| 188 | try std.testing.expectEqual(TestEnum.A, map.get("have").?); | ||
| 189 | try std.testing.expectEqual(TestEnum.B, map.get("nothing").?); | ||
| 190 | try std.testing.expect(null == map.get("missing")); | ||
| 191 | try std.testing.expectEqual(TestEnum.D, map.get("these").?); | ||
| 192 | try std.testing.expectEqual(TestEnum.E, map.get("samelen").?); | ||
| 193 | |||
| 194 | try std.testing.expect(!map.has("missing")); | ||
| 195 | try std.testing.expect(map.has("these")); | ||
| 196 | |||
| 197 | try std.testing.expect(null == map.get("")); | ||
| 198 | try std.testing.expect(null == map.get("averylongstringthathasnomatches")); | ||
| 199 | } | ||
| 200 | |||
| 201 | test "void value type, slice of structs" { | ||
| 202 | const KV = struct { []const u8 }; | ||
| 203 | const slice: []const KV = &[_]KV{ | ||
| 204 | .{"these"}, | ||
| 205 | .{"have"}, | ||
| 206 | .{"nothing"}, | ||
| 207 | .{"incommon"}, | ||
| 208 | .{"samelen"}, | ||
| 209 | }; | ||
| 210 | const map = ComptimeStringMap(void, slice); | ||
| 211 | |||
| 212 | try testSet(map); | ||
| 213 | |||
| 214 | // Default comparison is case sensitive | ||
| 215 | try std.testing.expect(null == map.get("NOTHING")); | ||
| 216 | } | ||
| 217 | |||
| 218 | test "void value type, list literal of list literals" { | ||
| 219 | const map = ComptimeStringMap(void, .{ | ||
| 220 | .{"these"}, | ||
| 221 | .{"have"}, | ||
| 222 | .{"nothing"}, | ||
| 223 | .{"incommon"}, | ||
| 224 | .{"samelen"}, | ||
| 225 | }); | ||
| 226 | |||
| 227 | try testSet(map); | ||
| 228 | } | ||
| 229 | |||
| 230 | fn testSet(comptime map: anytype) !void { | ||
| 231 | try std.testing.expectEqual({}, map.get("have").?); | ||
| 232 | try std.testing.expectEqual({}, map.get("nothing").?); | ||
| 233 | try std.testing.expect(null == map.get("missing")); | ||
| 234 | try std.testing.expectEqual({}, map.get("these").?); | ||
| 235 | try std.testing.expectEqual({}, map.get("samelen").?); | ||
| 236 | |||
| 237 | try std.testing.expect(!map.has("missing")); | ||
| 238 | try std.testing.expect(map.has("these")); | ||
| 239 | |||
| 240 | try std.testing.expect(null == map.get("")); | ||
| 241 | try std.testing.expect(null == map.get("averylongstringthathasnomatches")); | ||
| 242 | } | ||
| 243 | |||
| 244 | test "ComptimeStringMapWithEql" { | ||
| 245 | const map = ComptimeStringMapWithEql(TestEnum, .{ | ||
| 246 | .{ "these", .D }, | ||
| 247 | .{ "have", .A }, | ||
| 248 | .{ "nothing", .B }, | ||
| 249 | .{ "incommon", .C }, | ||
| 250 | .{ "samelen", .E }, | ||
| 251 | }, eqlAsciiIgnoreCase); | ||
| 252 | |||
| 253 | try testMap(map); | ||
| 254 | try std.testing.expectEqual(TestEnum.A, map.get("HAVE").?); | ||
| 255 | try std.testing.expectEqual(TestEnum.E, map.get("SameLen").?); | ||
| 256 | try std.testing.expect(null == map.get("SameLength")); | ||
| 257 | |||
| 258 | try std.testing.expect(map.has("ThESe")); | ||
| 259 | } | ||
| 260 | |||
| 261 | test "empty" { | ||
| 262 | const m1 = ComptimeStringMap(usize, .{}); | ||
| 263 | try std.testing.expect(null == m1.get("anything")); | ||
| 264 | |||
| 265 | const m2 = ComptimeStringMapWithEql(usize, .{}, eqlAsciiIgnoreCase); | ||
| 266 | try std.testing.expect(null == m2.get("anything")); | ||
| 267 | } | ||
| 268 | |||
| 269 | test "redundant entries" { | ||
| 270 | const map = ComptimeStringMap(TestEnum, .{ | ||
| 271 | .{ "redundant", .D }, | ||
| 272 | .{ "theNeedle", .A }, | ||
| 273 | .{ "redundant", .B }, | ||
| 274 | .{ "re" ++ "dundant", .C }, | ||
| 275 | .{ "redun" ++ "dant", .E }, | ||
| 276 | }); | ||
| 277 | |||
| 278 | // No promises about which one you get: | ||
| 279 | try std.testing.expect(null != map.get("redundant")); | ||
| 280 | |||
| 281 | // Default map is not case sensitive: | ||
| 282 | try std.testing.expect(null == map.get("REDUNDANT")); | ||
| 283 | |||
| 284 | try std.testing.expectEqual(TestEnum.A, map.get("theNeedle").?); | ||
| 285 | } | ||
| 286 | |||
| 287 | test "redundant insensitive" { | ||
| 288 | const map = ComptimeStringMapWithEql(TestEnum, .{ | ||
| 289 | .{ "redundant", .D }, | ||
| 290 | .{ "theNeedle", .A }, | ||
| 291 | .{ "redundanT", .B }, | ||
| 292 | .{ "RE" ++ "dundant", .C }, | ||
| 293 | .{ "redun" ++ "DANT", .E }, | ||
| 294 | }, eqlAsciiIgnoreCase); | ||
| 295 | |||
| 296 | // No promises about which result you'll get ... | ||
| 297 | try std.testing.expect(null != map.get("REDUNDANT")); | ||
| 298 | try std.testing.expect(null != map.get("ReDuNdAnT")); | ||
| 299 | |||
| 300 | try std.testing.expectEqual(TestEnum.A, map.get("theNeedle").?); | ||
| 301 | } | ||
| 302 | |||
| 303 | test "comptime-only value" { | ||
| 304 | const map = std.ComptimeStringMap(type, .{ | ||
| 305 | .{ "a", struct { | ||
| 306 | pub const foo = 1; | ||
| 307 | } }, | ||
| 308 | .{ "b", struct { | ||
| 309 | pub const foo = 2; | ||
| 310 | } }, | ||
| 311 | .{ "c", struct { | ||
| 312 | pub const foo = 3; | ||
| 313 | } }, | ||
| 314 | }); | ||
| 315 | |||
| 316 | try std.testing.expect(map.get("a").?.foo == 1); | ||
| 317 | try std.testing.expect(map.get("b").?.foo == 2); | ||
| 318 | try std.testing.expect(map.get("c").?.foo == 3); | ||
| 319 | try std.testing.expect(map.get("d") == null); | ||
| 320 | } | ||
lib/std/crypto/Certificate.zig+5-5| ... | @@ -19,7 +19,7 @@ pub const Algorithm = enum { | ... | @@ -19,7 +19,7 @@ pub const Algorithm = enum { |
| 19 | md5WithRSAEncryption, | 19 | md5WithRSAEncryption, |
| 20 | curveEd25519, | 20 | curveEd25519, |
| 21 | 21 | ||
| 22 | pub const map = std.ComptimeStringMap(Algorithm, .{ | 22 | pub const map = std.StaticStringMap(Algorithm).initComptime(.{ |
| 23 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 }, .sha1WithRSAEncryption }, | 23 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 }, .sha1WithRSAEncryption }, |
| 24 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B }, .sha256WithRSAEncryption }, | 24 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B }, .sha256WithRSAEncryption }, |
| 25 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C }, .sha384WithRSAEncryption }, | 25 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C }, .sha384WithRSAEncryption }, |
| ... | @@ -52,7 +52,7 @@ pub const AlgorithmCategory = enum { | ... | @@ -52,7 +52,7 @@ pub const AlgorithmCategory = enum { |
| 52 | X9_62_id_ecPublicKey, | 52 | X9_62_id_ecPublicKey, |
| 53 | curveEd25519, | 53 | curveEd25519, |
| 54 | 54 | ||
| 55 | pub const map = std.ComptimeStringMap(AlgorithmCategory, .{ | 55 | pub const map = std.StaticStringMap(AlgorithmCategory).initComptime(.{ |
| 56 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }, .rsaEncryption }, | 56 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }, .rsaEncryption }, |
| 57 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }, .X9_62_id_ecPublicKey }, | 57 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }, .X9_62_id_ecPublicKey }, |
| 58 | .{ &[_]u8{ 0x2B, 0x65, 0x70 }, .curveEd25519 }, | 58 | .{ &[_]u8{ 0x2B, 0x65, 0x70 }, .curveEd25519 }, |
| ... | @@ -73,7 +73,7 @@ pub const Attribute = enum { | ... | @@ -73,7 +73,7 @@ pub const Attribute = enum { |
| 73 | pkcs9_emailAddress, | 73 | pkcs9_emailAddress, |
| 74 | domainComponent, | 74 | domainComponent, |
| 75 | 75 | ||
| 76 | pub const map = std.ComptimeStringMap(Attribute, .{ | 76 | pub const map = std.StaticStringMap(Attribute).initComptime(.{ |
| 77 | .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName }, | 77 | .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName }, |
| 78 | .{ &[_]u8{ 0x55, 0x04, 0x05 }, .serialNumber }, | 78 | .{ &[_]u8{ 0x55, 0x04, 0x05 }, .serialNumber }, |
| 79 | .{ &[_]u8{ 0x55, 0x04, 0x06 }, .countryName }, | 79 | .{ &[_]u8{ 0x55, 0x04, 0x06 }, .countryName }, |
| ... | @@ -94,7 +94,7 @@ pub const NamedCurve = enum { | ... | @@ -94,7 +94,7 @@ pub const NamedCurve = enum { |
| 94 | secp521r1, | 94 | secp521r1, |
| 95 | X9_62_prime256v1, | 95 | X9_62_prime256v1, |
| 96 | 96 | ||
| 97 | pub const map = std.ComptimeStringMap(NamedCurve, .{ | 97 | pub const map = std.StaticStringMap(NamedCurve).initComptime(.{ |
| 98 | .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x22 }, .secp384r1 }, | 98 | .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x22 }, .secp384r1 }, |
| 99 | .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x23 }, .secp521r1 }, | 99 | .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x23 }, .secp521r1 }, |
| 100 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }, .X9_62_prime256v1 }, | 100 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }, .X9_62_prime256v1 }, |
| ... | @@ -130,7 +130,7 @@ pub const ExtensionId = enum { | ... | @@ -130,7 +130,7 @@ pub const ExtensionId = enum { |
| 130 | netscape_cert_type, | 130 | netscape_cert_type, |
| 131 | netscape_comment, | 131 | netscape_comment, |
| 132 | 132 | ||
| 133 | pub const map = std.ComptimeStringMap(ExtensionId, .{ | 133 | pub const map = std.StaticStringMap(ExtensionId).initComptime(.{ |
| 134 | .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName }, | 134 | .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName }, |
| 135 | .{ &[_]u8{ 0x55, 0x1D, 0x01 }, .authority_key_identifier }, | 135 | .{ &[_]u8{ 0x55, 0x1D, 0x01 }, .authority_key_identifier }, |
| 136 | .{ &[_]u8{ 0x55, 0x1D, 0x07 }, .subject_alt_name }, | 136 | .{ &[_]u8{ 0x55, 0x1D, 0x07 }, .subject_alt_name }, |
lib/std/fs/test.zig+4-4| ... | @@ -1641,7 +1641,7 @@ test "walker" { | ... | @@ -1641,7 +1641,7 @@ test "walker" { |
| 1641 | 1641 | ||
| 1642 | // iteration order of walker is undefined, so need lookup maps to check against | 1642 | // iteration order of walker is undefined, so need lookup maps to check against |
| 1643 | 1643 | ||
| 1644 | const expected_paths = std.ComptimeStringMap(void, .{ | 1644 | const expected_paths = std.StaticStringMap(void).initComptime(.{ |
| 1645 | .{"dir1"}, | 1645 | .{"dir1"}, |
| 1646 | .{"dir2"}, | 1646 | .{"dir2"}, |
| 1647 | .{"dir3"}, | 1647 | .{"dir3"}, |
| ... | @@ -1651,7 +1651,7 @@ test "walker" { | ... | @@ -1651,7 +1651,7 @@ test "walker" { |
| 1651 | .{"dir3" ++ fs.path.sep_str ++ "sub2" ++ fs.path.sep_str ++ "subsub1"}, | 1651 | .{"dir3" ++ fs.path.sep_str ++ "sub2" ++ fs.path.sep_str ++ "subsub1"}, |
| 1652 | }); | 1652 | }); |
| 1653 | 1653 | ||
| 1654 | const expected_basenames = std.ComptimeStringMap(void, .{ | 1654 | const expected_basenames = std.StaticStringMap(void).initComptime(.{ |
| 1655 | .{"dir1"}, | 1655 | .{"dir1"}, |
| 1656 | .{"dir2"}, | 1656 | .{"dir2"}, |
| 1657 | .{"dir3"}, | 1657 | .{"dir3"}, |
| ... | @@ -1661,8 +1661,8 @@ test "walker" { | ... | @@ -1661,8 +1661,8 @@ test "walker" { |
| 1661 | .{"subsub1"}, | 1661 | .{"subsub1"}, |
| 1662 | }); | 1662 | }); |
| 1663 | 1663 | ||
| 1664 | for (expected_paths.kvs) |kv| { | 1664 | for (expected_paths.keys()) |key| { |
| 1665 | try tmp.dir.makePath(kv.key); | 1665 | try tmp.dir.makePath(key); |
| 1666 | } | 1666 | } |
| 1667 | 1667 | ||
| 1668 | var walker = try tmp.dir.walk(testing.allocator); | 1668 | var walker = try tmp.dir.walk(testing.allocator); |
lib/std/http/Client.zig+1-1| ... | @@ -1570,7 +1570,7 @@ pub const RequestOptions = struct { | ... | @@ -1570,7 +1570,7 @@ pub const RequestOptions = struct { |
| 1570 | }; | 1570 | }; |
| 1571 | 1571 | ||
| 1572 | fn validateUri(uri: Uri, arena: Allocator) !struct { Connection.Protocol, Uri } { | 1572 | fn validateUri(uri: Uri, arena: Allocator) !struct { Connection.Protocol, Uri } { |
| 1573 | const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{ | 1573 | const protocol_map = std.StaticStringMap(Connection.Protocol).initComptime(.{ |
| 1574 | .{ "http", .plain }, | 1574 | .{ "http", .plain }, |
| 1575 | .{ "ws", .plain }, | 1575 | .{ "ws", .plain }, |
| 1576 | .{ "https", .tls }, | 1576 | .{ "https", .tls }, |
lib/std/meta.zig+2-2| ... | @@ -19,7 +19,7 @@ pub const isTag = @compileError("deprecated; use 'tagged_value == @field(E, tag_ | ... | @@ -19,7 +19,7 @@ pub const isTag = @compileError("deprecated; use 'tagged_value == @field(E, tag_ |
| 19 | 19 | ||
| 20 | /// Returns the variant of an enum type, `T`, which is named `str`, or `null` if no such variant exists. | 20 | /// Returns the variant of an enum type, `T`, which is named `str`, or `null` if no such variant exists. |
| 21 | pub fn stringToEnum(comptime T: type, str: []const u8) ?T { | 21 | pub fn stringToEnum(comptime T: type, str: []const u8) ?T { |
| 22 | // Using ComptimeStringMap here is more performant, but it will start to take too | 22 | // Using StaticStringMap here is more performant, but it will start to take too |
| 23 | // long to compile if the enum is large enough, due to the current limits of comptime | 23 | // long to compile if the enum is large enough, due to the current limits of comptime |
| 24 | // performance when doing things like constructing lookup maps at comptime. | 24 | // performance when doing things like constructing lookup maps at comptime. |
| 25 | // TODO The '100' here is arbitrary and should be increased when possible: | 25 | // TODO The '100' here is arbitrary and should be increased when possible: |
| ... | @@ -34,7 +34,7 @@ pub fn stringToEnum(comptime T: type, str: []const u8) ?T { | ... | @@ -34,7 +34,7 @@ pub fn stringToEnum(comptime T: type, str: []const u8) ?T { |
| 34 | } | 34 | } |
| 35 | break :build_kvs kvs_array[0..]; | 35 | break :build_kvs kvs_array[0..]; |
| 36 | }; | 36 | }; |
| 37 | const map = std.ComptimeStringMap(T, kvs); | 37 | const map = std.StaticStringMap(T).initComptime(kvs); |
| 38 | return map.get(str); | 38 | return map.get(str); |
| 39 | } else { | 39 | } else { |
| 40 | inline for (@typeInfo(T).Enum.fields) |enumField| { | 40 | inline for (@typeInfo(T).Enum.fields) |enumField| { |
lib/std/static_string_map.zig created+502| ... | @@ -0,0 +1,502 @@ | ||
| 1 | const std = @import("std.zig"); | ||
| 2 | const mem = std.mem; | ||
| 3 | |||
| 4 | /// Static string map optimized for small sets of disparate string keys. | ||
| 5 | /// Works by separating the keys by length at initialization and only checking | ||
| 6 | /// strings of equal length at runtime. | ||
| 7 | pub fn StaticStringMap(comptime V: type) type { | ||
| 8 | return StaticStringMapWithEql(V, defaultEql); | ||
| 9 | } | ||
| 10 | |||
| 11 | /// Like `std.mem.eql`, but takes advantage of the fact that the lengths | ||
| 12 | /// of `a` and `b` are known to be equal. | ||
| 13 | pub fn defaultEql(a: []const u8, b: []const u8) bool { | ||
| 14 | if (a.ptr == b.ptr) return true; | ||
| 15 | for (a, b) |a_elem, b_elem| { | ||
| 16 | if (a_elem != b_elem) return false; | ||
| 17 | } | ||
| 18 | return true; | ||
| 19 | } | ||
| 20 | |||
| 21 | /// Like `std.ascii.eqlIgnoreCase` but takes advantage of the fact that | ||
| 22 | /// the lengths of `a` and `b` are known to be equal. | ||
| 23 | pub fn eqlAsciiIgnoreCase(a: []const u8, b: []const u8) bool { | ||
| 24 | if (a.ptr == b.ptr) return true; | ||
| 25 | for (a, b) |a_c, b_c| { | ||
| 26 | if (std.ascii.toLower(a_c) != std.ascii.toLower(b_c)) return false; | ||
| 27 | } | ||
| 28 | return true; | ||
| 29 | } | ||
| 30 | |||
| 31 | /// StaticStringMap, but accepts an equality function (`eql`). | ||
| 32 | /// The `eql` function is only called to determine the equality | ||
| 33 | /// of equal length strings. Any strings that are not equal length | ||
| 34 | /// are never compared using the `eql` function. | ||
| 35 | pub fn StaticStringMapWithEql( | ||
| 36 | comptime V: type, | ||
| 37 | comptime eql: fn (a: []const u8, b: []const u8) bool, | ||
| 38 | ) type { | ||
| 39 | return struct { | ||
| 40 | kvs: *const KVs = &empty_kvs, | ||
| 41 | len_indexes: [*]const u32 = &empty_len_indexes, | ||
| 42 | len_indexes_len: u32 = 0, | ||
| 43 | min_len: u32 = std.math.maxInt(u32), | ||
| 44 | max_len: u32 = 0, | ||
| 45 | |||
| 46 | pub const KV = struct { | ||
| 47 | key: []const u8, | ||
| 48 | value: V, | ||
| 49 | }; | ||
| 50 | |||
| 51 | const Self = @This(); | ||
| 52 | const KVs = struct { | ||
| 53 | keys: [*]const []const u8, | ||
| 54 | values: [*]const V, | ||
| 55 | len: u32, | ||
| 56 | }; | ||
| 57 | const empty_kvs = KVs{ | ||
| 58 | .keys = &empty_keys, | ||
| 59 | .values = &empty_vals, | ||
| 60 | .len = 0, | ||
| 61 | }; | ||
| 62 | const empty_len_indexes = [0]u32{}; | ||
| 63 | const empty_keys = [0][]const u8{}; | ||
| 64 | const empty_vals = [0]V{}; | ||
| 65 | |||
| 66 | /// Returns a map backed by static, comptime allocated memory. | ||
| 67 | /// | ||
| 68 | /// `kvs_list` must be either a list of `struct { []const u8, V }` | ||
| 69 | /// (key-value pair) tuples, or a list of `struct { []const u8 }` | ||
| 70 | /// (only keys) tuples if `V` is `void`. | ||
| 71 | pub inline fn initComptime(comptime kvs_list: anytype) Self { | ||
| 72 | comptime { | ||
| 73 | @setEvalBranchQuota(30 * kvs_list.len); | ||
| 74 | var self = Self{}; | ||
| 75 | if (kvs_list.len == 0) | ||
| 76 | return self; | ||
| 77 | |||
| 78 | var sorted_keys: [kvs_list.len][]const u8 = undefined; | ||
| 79 | var sorted_vals: [kvs_list.len]V = undefined; | ||
| 80 | |||
| 81 | self.initSortedKVs(kvs_list, &sorted_keys, &sorted_vals); | ||
| 82 | const final_keys = sorted_keys; | ||
| 83 | const final_vals = sorted_vals; | ||
| 84 | self.kvs = &.{ | ||
| 85 | .keys = &final_keys, | ||
| 86 | .values = &final_vals, | ||
| 87 | .len = @intCast(kvs_list.len), | ||
| 88 | }; | ||
| 89 | |||
| 90 | var len_indexes: [self.max_len + 1]u32 = undefined; | ||
| 91 | self.initLenIndexes(&len_indexes); | ||
| 92 | const final_len_indexes = len_indexes; | ||
| 93 | self.len_indexes = &final_len_indexes; | ||
| 94 | self.len_indexes_len = @intCast(len_indexes.len); | ||
| 95 | return self; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | /// Returns a map backed by memory allocated with `allocator`. | ||
| 100 | /// | ||
| 101 | /// Handles `kvs_list` the same way as `initComptime()`. | ||
| 102 | pub fn init(kvs_list: anytype, allocator: mem.Allocator) !Self { | ||
| 103 | var self = Self{}; | ||
| 104 | if (kvs_list.len == 0) | ||
| 105 | return self; | ||
| 106 | |||
| 107 | const sorted_keys = try allocator.alloc([]const u8, kvs_list.len); | ||
| 108 | errdefer allocator.free(sorted_keys); | ||
| 109 | const sorted_vals = try allocator.alloc(V, kvs_list.len); | ||
| 110 | errdefer allocator.free(sorted_vals); | ||
| 111 | const kvs = try allocator.create(KVs); | ||
| 112 | errdefer allocator.destroy(kvs); | ||
| 113 | |||
| 114 | self.initSortedKVs(kvs_list, sorted_keys, sorted_vals); | ||
| 115 | kvs.* = .{ | ||
| 116 | .keys = sorted_keys.ptr, | ||
| 117 | .values = sorted_vals.ptr, | ||
| 118 | .len = kvs_list.len, | ||
| 119 | }; | ||
| 120 | self.kvs = kvs; | ||
| 121 | |||
| 122 | const len_indexes = try allocator.alloc(u32, self.max_len + 1); | ||
| 123 | self.initLenIndexes(len_indexes); | ||
| 124 | self.len_indexes = len_indexes.ptr; | ||
| 125 | self.len_indexes_len = @intCast(len_indexes.len); | ||
| 126 | return self; | ||
| 127 | } | ||
| 128 | |||
| 129 | /// this method should only be used with init() and not with initComptime(). | ||
| 130 | pub fn deinit(self: Self, allocator: mem.Allocator) void { | ||
| 131 | allocator.free(self.len_indexes[0..self.len_indexes_len]); | ||
| 132 | allocator.free(self.kvs.keys[0..self.kvs.len]); | ||
| 133 | allocator.free(self.kvs.values[0..self.kvs.len]); | ||
| 134 | allocator.destroy(self.kvs); | ||
| 135 | } | ||
| 136 | |||
| 137 | const SortContext = struct { | ||
| 138 | keys: [][]const u8, | ||
| 139 | vals: []V, | ||
| 140 | |||
| 141 | pub fn lessThan(ctx: @This(), a: usize, b: usize) bool { | ||
| 142 | return ctx.keys[a].len < ctx.keys[b].len; | ||
| 143 | } | ||
| 144 | |||
| 145 | pub fn swap(ctx: @This(), a: usize, b: usize) void { | ||
| 146 | std.mem.swap([]const u8, &ctx.keys[a], &ctx.keys[b]); | ||
| 147 | std.mem.swap(V, &ctx.vals[a], &ctx.vals[b]); | ||
| 148 | } | ||
| 149 | }; | ||
| 150 | |||
| 151 | fn initSortedKVs( | ||
| 152 | self: *Self, | ||
| 153 | kvs_list: anytype, | ||
| 154 | sorted_keys: [][]const u8, | ||
| 155 | sorted_vals: []V, | ||
| 156 | ) void { | ||
| 157 | for (kvs_list, 0..) |kv, i| { | ||
| 158 | sorted_keys[i] = kv.@"0"; | ||
| 159 | sorted_vals[i] = if (V == void) {} else kv.@"1"; | ||
| 160 | self.min_len = @intCast(@min(self.min_len, kv.@"0".len)); | ||
| 161 | self.max_len = @intCast(@max(self.max_len, kv.@"0".len)); | ||
| 162 | } | ||
| 163 | mem.sortUnstableContext(0, sorted_keys.len, SortContext{ | ||
| 164 | .keys = sorted_keys, | ||
| 165 | .vals = sorted_vals, | ||
| 166 | }); | ||
| 167 | } | ||
| 168 | |||
| 169 | fn initLenIndexes(self: Self, len_indexes: []u32) void { | ||
| 170 | var len: usize = 0; | ||
| 171 | var i: u32 = 0; | ||
| 172 | while (len <= self.max_len) : (len += 1) { | ||
| 173 | // find the first keyword len == len | ||
| 174 | while (len > self.kvs.keys[i].len) { | ||
| 175 | i += 1; | ||
| 176 | } | ||
| 177 | len_indexes[len] = i; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | /// Checks if the map has a value for the key. | ||
| 182 | pub fn has(self: Self, str: []const u8) bool { | ||
| 183 | return self.get(str) != null; | ||
| 184 | } | ||
| 185 | |||
| 186 | /// Returns the value for the key if any, else null. | ||
| 187 | pub fn get(self: Self, str: []const u8) ?V { | ||
| 188 | if (self.kvs.len == 0) | ||
| 189 | return null; | ||
| 190 | |||
| 191 | return self.kvs.values[self.getIndex(str) orelse return null]; | ||
| 192 | } | ||
| 193 | |||
| 194 | pub fn getIndex(self: Self, str: []const u8) ?usize { | ||
| 195 | const kvs = self.kvs.*; | ||
| 196 | if (kvs.len == 0) | ||
| 197 | return null; | ||
| 198 | |||
| 199 | if (str.len < self.min_len or str.len > self.max_len) | ||
| 200 | return null; | ||
| 201 | |||
| 202 | var i = self.len_indexes[str.len]; | ||
| 203 | while (true) { | ||
| 204 | const key = kvs.keys[i]; | ||
| 205 | if (key.len != str.len) | ||
| 206 | return null; | ||
| 207 | if (eql(key, str)) | ||
| 208 | return i; | ||
| 209 | i += 1; | ||
| 210 | if (i >= kvs.len) | ||
| 211 | return null; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | /// Returns the longest key, value pair where key is a prefix of `str` | ||
| 216 | /// else null. | ||
| 217 | pub fn getLongestPrefix(self: Self, str: []const u8) ?KV { | ||
| 218 | if (self.kvs.len == 0) | ||
| 219 | return null; | ||
| 220 | const i = self.getLongestPrefixIndex(str) orelse return null; | ||
| 221 | const kvs = self.kvs.*; | ||
| 222 | return .{ | ||
| 223 | .key = kvs.keys[i], | ||
| 224 | .value = kvs.values[i], | ||
| 225 | }; | ||
| 226 | } | ||
| 227 | |||
| 228 | pub fn getLongestPrefixIndex(self: Self, str: []const u8) ?usize { | ||
| 229 | if (self.kvs.len == 0) | ||
| 230 | return null; | ||
| 231 | |||
| 232 | if (str.len < self.min_len) | ||
| 233 | return null; | ||
| 234 | |||
| 235 | var len = @min(self.max_len, str.len); | ||
| 236 | while (len >= self.min_len) : (len -= 1) { | ||
| 237 | if (self.getIndex(str[0..len])) |i| | ||
| 238 | return i; | ||
| 239 | } | ||
| 240 | return null; | ||
| 241 | } | ||
| 242 | |||
| 243 | pub fn keys(self: Self) []const []const u8 { | ||
| 244 | const kvs = self.kvs.*; | ||
| 245 | return kvs.keys[0..kvs.len]; | ||
| 246 | } | ||
| 247 | |||
| 248 | pub fn values(self: Self) []const V { | ||
| 249 | const kvs = self.kvs.*; | ||
| 250 | return kvs.values[0..kvs.len]; | ||
| 251 | } | ||
| 252 | }; | ||
| 253 | } | ||
| 254 | |||
| 255 | const TestEnum = enum { A, B, C, D, E }; | ||
| 256 | const TestMap = StaticStringMap(TestEnum); | ||
| 257 | const TestKV = struct { []const u8, TestEnum }; | ||
| 258 | const TestMapVoid = StaticStringMap(void); | ||
| 259 | const TestKVVoid = struct { []const u8 }; | ||
| 260 | const TestMapWithEql = StaticStringMapWithEql(TestEnum, eqlAsciiIgnoreCase); | ||
| 261 | const testing = std.testing; | ||
| 262 | const test_alloc = testing.allocator; | ||
| 263 | |||
| 264 | test "list literal of list literals" { | ||
| 265 | const slice = [_]TestKV{ | ||
| 266 | .{ "these", .D }, | ||
| 267 | .{ "have", .A }, | ||
| 268 | .{ "nothing", .B }, | ||
| 269 | .{ "incommon", .C }, | ||
| 270 | .{ "samelen", .E }, | ||
| 271 | }; | ||
| 272 | const map = TestMap.initComptime(slice); | ||
| 273 | try testMap(map); | ||
| 274 | // Default comparison is case sensitive | ||
| 275 | try testing.expect(null == map.get("NOTHING")); | ||
| 276 | |||
| 277 | // runtime init(), deinit() | ||
| 278 | const map_rt = try TestMap.init(slice, test_alloc); | ||
| 279 | defer map_rt.deinit(test_alloc); | ||
| 280 | try testMap(map_rt); | ||
| 281 | // Default comparison is case sensitive | ||
| 282 | try testing.expect(null == map_rt.get("NOTHING")); | ||
| 283 | } | ||
| 284 | |||
| 285 | test "array of structs" { | ||
| 286 | const slice = [_]TestKV{ | ||
| 287 | .{ "these", .D }, | ||
| 288 | .{ "have", .A }, | ||
| 289 | .{ "nothing", .B }, | ||
| 290 | .{ "incommon", .C }, | ||
| 291 | .{ "samelen", .E }, | ||
| 292 | }; | ||
| 293 | |||
| 294 | try testMap(TestMap.initComptime(slice)); | ||
| 295 | } | ||
| 296 | |||
| 297 | test "slice of structs" { | ||
| 298 | const slice = [_]TestKV{ | ||
| 299 | .{ "these", .D }, | ||
| 300 | .{ "have", .A }, | ||
| 301 | .{ "nothing", .B }, | ||
| 302 | .{ "incommon", .C }, | ||
| 303 | .{ "samelen", .E }, | ||
| 304 | }; | ||
| 305 | |||
| 306 | try testMap(TestMap.initComptime(slice)); | ||
| 307 | } | ||
| 308 | |||
| 309 | fn testMap(map: anytype) !void { | ||
| 310 | try testing.expectEqual(TestEnum.A, map.get("have").?); | ||
| 311 | try testing.expectEqual(TestEnum.B, map.get("nothing").?); | ||
| 312 | try testing.expect(null == map.get("missing")); | ||
| 313 | try testing.expectEqual(TestEnum.D, map.get("these").?); | ||
| 314 | try testing.expectEqual(TestEnum.E, map.get("samelen").?); | ||
| 315 | |||
| 316 | try testing.expect(!map.has("missing")); | ||
| 317 | try testing.expect(map.has("these")); | ||
| 318 | |||
| 319 | try testing.expect(null == map.get("")); | ||
| 320 | try testing.expect(null == map.get("averylongstringthathasnomatches")); | ||
| 321 | } | ||
| 322 | |||
| 323 | test "void value type, slice of structs" { | ||
| 324 | const slice = [_]TestKVVoid{ | ||
| 325 | .{"these"}, | ||
| 326 | .{"have"}, | ||
| 327 | .{"nothing"}, | ||
| 328 | .{"incommon"}, | ||
| 329 | .{"samelen"}, | ||
| 330 | }; | ||
| 331 | const map = TestMapVoid.initComptime(slice); | ||
| 332 | try testSet(map); | ||
| 333 | // Default comparison is case sensitive | ||
| 334 | try testing.expect(null == map.get("NOTHING")); | ||
| 335 | } | ||
| 336 | |||
| 337 | test "void value type, list literal of list literals" { | ||
| 338 | const slice = [_]TestKVVoid{ | ||
| 339 | .{"these"}, | ||
| 340 | .{"have"}, | ||
| 341 | .{"nothing"}, | ||
| 342 | .{"incommon"}, | ||
| 343 | .{"samelen"}, | ||
| 344 | }; | ||
| 345 | |||
| 346 | try testSet(TestMapVoid.initComptime(slice)); | ||
| 347 | } | ||
| 348 | |||
| 349 | fn testSet(map: TestMapVoid) !void { | ||
| 350 | try testing.expectEqual({}, map.get("have").?); | ||
| 351 | try testing.expectEqual({}, map.get("nothing").?); | ||
| 352 | try testing.expect(null == map.get("missing")); | ||
| 353 | try testing.expectEqual({}, map.get("these").?); | ||
| 354 | try testing.expectEqual({}, map.get("samelen").?); | ||
| 355 | |||
| 356 | try testing.expect(!map.has("missing")); | ||
| 357 | try testing.expect(map.has("these")); | ||
| 358 | |||
| 359 | try testing.expect(null == map.get("")); | ||
| 360 | try testing.expect(null == map.get("averylongstringthathasnomatches")); | ||
| 361 | } | ||
| 362 | |||
| 363 | fn testStaticStringMapWithEql(map: TestMapWithEql) !void { | ||
| 364 | try testMap(map); | ||
| 365 | try testing.expectEqual(TestEnum.A, map.get("HAVE").?); | ||
| 366 | try testing.expectEqual(TestEnum.E, map.get("SameLen").?); | ||
| 367 | try testing.expect(null == map.get("SameLength")); | ||
| 368 | try testing.expect(map.has("ThESe")); | ||
| 369 | } | ||
| 370 | |||
| 371 | test "StaticStringMapWithEql" { | ||
| 372 | const slice = [_]TestKV{ | ||
| 373 | .{ "these", .D }, | ||
| 374 | .{ "have", .A }, | ||
| 375 | .{ "nothing", .B }, | ||
| 376 | .{ "incommon", .C }, | ||
| 377 | .{ "samelen", .E }, | ||
| 378 | }; | ||
| 379 | |||
| 380 | try testStaticStringMapWithEql(TestMapWithEql.initComptime(slice)); | ||
| 381 | } | ||
| 382 | |||
| 383 | test "empty" { | ||
| 384 | const m1 = StaticStringMap(usize).initComptime(.{}); | ||
| 385 | try testing.expect(null == m1.get("anything")); | ||
| 386 | |||
| 387 | const m2 = StaticStringMapWithEql(usize, eqlAsciiIgnoreCase).initComptime(.{}); | ||
| 388 | try testing.expect(null == m2.get("anything")); | ||
| 389 | |||
| 390 | const m3 = try StaticStringMap(usize).init(.{}, test_alloc); | ||
| 391 | try testing.expect(null == m3.get("anything")); | ||
| 392 | |||
| 393 | const m4 = try StaticStringMapWithEql(usize, eqlAsciiIgnoreCase).init(.{}, test_alloc); | ||
| 394 | try testing.expect(null == m4.get("anything")); | ||
| 395 | } | ||
| 396 | |||
| 397 | test "redundant entries" { | ||
| 398 | const slice = [_]TestKV{ | ||
| 399 | .{ "redundant", .D }, | ||
| 400 | .{ "theNeedle", .A }, | ||
| 401 | .{ "redundant", .B }, | ||
| 402 | .{ "re" ++ "dundant", .C }, | ||
| 403 | .{ "redun" ++ "dant", .E }, | ||
| 404 | }; | ||
| 405 | const map = TestMap.initComptime(slice); | ||
| 406 | |||
| 407 | // No promises about which one you get: | ||
| 408 | try testing.expect(null != map.get("redundant")); | ||
| 409 | |||
| 410 | // Default map is not case sensitive: | ||
| 411 | try testing.expect(null == map.get("REDUNDANT")); | ||
| 412 | |||
| 413 | try testing.expectEqual(TestEnum.A, map.get("theNeedle").?); | ||
| 414 | } | ||
| 415 | |||
| 416 | test "redundant insensitive" { | ||
| 417 | const slice = [_]TestKV{ | ||
| 418 | .{ "redundant", .D }, | ||
| 419 | .{ "theNeedle", .A }, | ||
| 420 | .{ "redundanT", .B }, | ||
| 421 | .{ "RE" ++ "dundant", .C }, | ||
| 422 | .{ "redun" ++ "DANT", .E }, | ||
| 423 | }; | ||
| 424 | |||
| 425 | const map = TestMapWithEql.initComptime(slice); | ||
| 426 | |||
| 427 | // No promises about which result you'll get ... | ||
| 428 | try testing.expect(null != map.get("REDUNDANT")); | ||
| 429 | try testing.expect(null != map.get("ReDuNdAnT")); | ||
| 430 | try testing.expectEqual(TestEnum.A, map.get("theNeedle").?); | ||
| 431 | } | ||
| 432 | |||
| 433 | test "comptime-only value" { | ||
| 434 | const map = StaticStringMap(type).initComptime(.{ | ||
| 435 | .{ "a", struct { | ||
| 436 | pub const foo = 1; | ||
| 437 | } }, | ||
| 438 | .{ "b", struct { | ||
| 439 | pub const foo = 2; | ||
| 440 | } }, | ||
| 441 | .{ "c", struct { | ||
| 442 | pub const foo = 3; | ||
| 443 | } }, | ||
| 444 | }); | ||
| 445 | |||
| 446 | try testing.expect(map.get("a").?.foo == 1); | ||
| 447 | try testing.expect(map.get("b").?.foo == 2); | ||
| 448 | try testing.expect(map.get("c").?.foo == 3); | ||
| 449 | try testing.expect(map.get("d") == null); | ||
| 450 | } | ||
| 451 | |||
| 452 | test "getLongestPrefix" { | ||
| 453 | const slice = [_]TestKV{ | ||
| 454 | .{ "a", .A }, | ||
| 455 | .{ "aa", .B }, | ||
| 456 | .{ "aaa", .C }, | ||
| 457 | .{ "aaaa", .D }, | ||
| 458 | }; | ||
| 459 | |||
| 460 | const map = TestMap.initComptime(slice); | ||
| 461 | |||
| 462 | try testing.expectEqual(null, map.getLongestPrefix("")); | ||
| 463 | try testing.expectEqual(null, map.getLongestPrefix("bar")); | ||
| 464 | try testing.expectEqualStrings("aaaa", map.getLongestPrefix("aaaabar").?.key); | ||
| 465 | try testing.expectEqualStrings("aaa", map.getLongestPrefix("aaabar").?.key); | ||
| 466 | } | ||
| 467 | |||
| 468 | test "getLongestPrefix2" { | ||
| 469 | const slice = [_]struct { []const u8, u8 }{ | ||
| 470 | .{ "one", 1 }, | ||
| 471 | .{ "two", 2 }, | ||
| 472 | .{ "three", 3 }, | ||
| 473 | .{ "four", 4 }, | ||
| 474 | .{ "five", 5 }, | ||
| 475 | .{ "six", 6 }, | ||
| 476 | .{ "seven", 7 }, | ||
| 477 | .{ "eight", 8 }, | ||
| 478 | .{ "nine", 9 }, | ||
| 479 | }; | ||
| 480 | const map = StaticStringMap(u8).initComptime(slice); | ||
| 481 | |||
| 482 | try testing.expectEqual(1, map.get("one")); | ||
| 483 | try testing.expectEqual(null, map.get("o")); | ||
| 484 | try testing.expectEqual(null, map.get("onexxx")); | ||
| 485 | try testing.expectEqual(9, map.get("nine")); | ||
| 486 | try testing.expectEqual(null, map.get("n")); | ||
| 487 | try testing.expectEqual(null, map.get("ninexxx")); | ||
| 488 | try testing.expectEqual(null, map.get("xxx")); | ||
| 489 | |||
| 490 | try testing.expectEqual(1, map.getLongestPrefix("one").?.value); | ||
| 491 | try testing.expectEqual(1, map.getLongestPrefix("onexxx").?.value); | ||
| 492 | try testing.expectEqual(null, map.getLongestPrefix("o")); | ||
| 493 | try testing.expectEqual(null, map.getLongestPrefix("on")); | ||
| 494 | try testing.expectEqual(9, map.getLongestPrefix("nine").?.value); | ||
| 495 | try testing.expectEqual(9, map.getLongestPrefix("ninexxx").?.value); | ||
| 496 | try testing.expectEqual(null, map.getLongestPrefix("n")); | ||
| 497 | try testing.expectEqual(null, map.getLongestPrefix("xxx")); | ||
| 498 | } | ||
| 499 | |||
| 500 | test "long kvs_list doesn't exceed @setEvalBranchQuota" { | ||
| 501 | _ = TestMapVoid.initComptime([1]TestKVVoid{.{"x"}} ** 1_000); | ||
| 502 | } | ||
lib/std/std.zig+3-3| ... | @@ -16,8 +16,8 @@ pub const BufMap = @import("buf_map.zig").BufMap; | ... | @@ -16,8 +16,8 @@ pub const BufMap = @import("buf_map.zig").BufMap; |
| 16 | pub const BufSet = @import("buf_set.zig").BufSet; | 16 | pub const BufSet = @import("buf_set.zig").BufSet; |
| 17 | /// Deprecated: use `process.Child`. | 17 | /// Deprecated: use `process.Child`. |
| 18 | pub const ChildProcess = @import("child_process.zig").ChildProcess; | 18 | pub const ChildProcess = @import("child_process.zig").ChildProcess; |
| 19 | pub const ComptimeStringMap = comptime_string_map.ComptimeStringMap; | 19 | pub const StaticStringMap = static_string_map.StaticStringMap; |
| 20 | pub const ComptimeStringMapWithEql = comptime_string_map.ComptimeStringMapWithEql; | 20 | pub const StaticStringMapWithEql = static_string_map.StaticStringMapWithEql; |
| 21 | pub const DoublyLinkedList = @import("linked_list.zig").DoublyLinkedList; | 21 | pub const DoublyLinkedList = @import("linked_list.zig").DoublyLinkedList; |
| 22 | pub const DynLib = @import("dynamic_library.zig").DynLib; | 22 | pub const DynLib = @import("dynamic_library.zig").DynLib; |
| 23 | pub const DynamicBitSet = bit_set.DynamicBitSet; | 23 | pub const DynamicBitSet = bit_set.DynamicBitSet; |
| ... | @@ -62,7 +62,7 @@ pub const builtin = @import("builtin.zig"); | ... | @@ -62,7 +62,7 @@ pub const builtin = @import("builtin.zig"); |
| 62 | pub const c = @import("c.zig"); | 62 | pub const c = @import("c.zig"); |
| 63 | pub const coff = @import("coff.zig"); | 63 | pub const coff = @import("coff.zig"); |
| 64 | pub const compress = @import("compress.zig"); | 64 | pub const compress = @import("compress.zig"); |
| 65 | pub const comptime_string_map = @import("comptime_string_map.zig"); | 65 | pub const static_string_map = @import("static_string_map.zig"); |
| 66 | pub const crypto = @import("crypto.zig"); | 66 | pub const crypto = @import("crypto.zig"); |
| 67 | pub const debug = @import("debug.zig"); | 67 | pub const debug = @import("debug.zig"); |
| 68 | pub const dwarf = @import("dwarf.zig"); | 68 | pub const dwarf = @import("dwarf.zig"); |
lib/std/zig/AstGen.zig+7-7| ... | @@ -10125,7 +10125,7 @@ fn calleeExpr( | ... | @@ -10125,7 +10125,7 @@ fn calleeExpr( |
| 10125 | } | 10125 | } |
| 10126 | } | 10126 | } |
| 10127 | 10127 | ||
| 10128 | const primitive_instrs = std.ComptimeStringMap(Zir.Inst.Ref, .{ | 10128 | const primitive_instrs = std.StaticStringMap(Zir.Inst.Ref).initComptime(.{ |
| 10129 | .{ "anyerror", .anyerror_type }, | 10129 | .{ "anyerror", .anyerror_type }, |
| 10130 | .{ "anyframe", .anyframe_type }, | 10130 | .{ "anyframe", .anyframe_type }, |
| 10131 | .{ "anyopaque", .anyopaque_type }, | 10131 | .{ "anyopaque", .anyopaque_type }, |
| ... | @@ -10173,14 +10173,14 @@ const primitive_instrs = std.ComptimeStringMap(Zir.Inst.Ref, .{ | ... | @@ -10173,14 +10173,14 @@ const primitive_instrs = std.ComptimeStringMap(Zir.Inst.Ref, .{ |
| 10173 | comptime { | 10173 | comptime { |
| 10174 | // These checks ensure that std.zig.primitives stays in sync with the primitive->Zir map. | 10174 | // These checks ensure that std.zig.primitives stays in sync with the primitive->Zir map. |
| 10175 | const primitives = std.zig.primitives; | 10175 | const primitives = std.zig.primitives; |
| 10176 | for (primitive_instrs.kvs) |kv| { | 10176 | for (primitive_instrs.keys(), primitive_instrs.values()) |key, value| { |
| 10177 | if (!primitives.isPrimitive(kv.key)) { | 10177 | if (!primitives.isPrimitive(key)) { |
| 10178 | @compileError("std.zig.isPrimitive() is not aware of Zir instr '" ++ @tagName(kv.value) ++ "'"); | 10178 | @compileError("std.zig.isPrimitive() is not aware of Zir instr '" ++ @tagName(value) ++ "'"); |
| 10179 | } | 10179 | } |
| 10180 | } | 10180 | } |
| 10181 | for (primitives.names.kvs) |kv| { | 10181 | for (primitives.names.keys()) |key| { |
| 10182 | if (primitive_instrs.get(kv.key) == null) { | 10182 | if (primitive_instrs.get(key) == null) { |
| 10183 | @compileError("std.zig.primitives entry '" ++ kv.key ++ "' does not have a corresponding Zir instr"); | 10183 | @compileError("std.zig.primitives entry '" ++ key ++ "' does not have a corresponding Zir instr"); |
| 10184 | } | 10184 | } |
| 10185 | } | 10185 | } |
| 10186 | } | 10186 | } |
lib/std/zig/BuiltinFn.zig+1-1| ... | @@ -160,7 +160,7 @@ param_count: ?u8, | ... | @@ -160,7 +160,7 @@ param_count: ?u8, |
| 160 | 160 | ||
| 161 | pub const list = list: { | 161 | pub const list = list: { |
| 162 | @setEvalBranchQuota(3000); | 162 | @setEvalBranchQuota(3000); |
| 163 | break :list std.ComptimeStringMap(@This(), .{ | 163 | break :list std.StaticStringMap(@This()).initComptime(.{ |
| 164 | .{ | 164 | .{ |
| 165 | "@addWithOverflow", | 165 | "@addWithOverflow", |
| 166 | .{ | 166 | .{ |
lib/std/zig/primitives.zig+1-1| ... | @@ -2,7 +2,7 @@ const std = @import("std"); | ... | @@ -2,7 +2,7 @@ const std = @import("std"); |
| 2 | 2 | ||
| 3 | /// Set of primitive type and value names. | 3 | /// Set of primitive type and value names. |
| 4 | /// Does not include `_` or integer type names. | 4 | /// Does not include `_` or integer type names. |
| 5 | pub const names = std.ComptimeStringMap(void, .{ | 5 | pub const names = std.StaticStringMap(void).initComptime(.{ |
| 6 | .{"anyerror"}, | 6 | .{"anyerror"}, |
| 7 | .{"anyframe"}, | 7 | .{"anyframe"}, |
| 8 | .{"anyopaque"}, | 8 | .{"anyopaque"}, |
lib/std/zig/render.zig+4-4| ... | @@ -2886,11 +2886,11 @@ fn renderIdentifier(r: *Render, token_index: Ast.TokenIndex, space: Space, quote | ... | @@ -2886,11 +2886,11 @@ fn renderIdentifier(r: *Render, token_index: Ast.TokenIndex, space: Space, quote |
| 2886 | // If we read the whole thing, we have to do further checks. | 2886 | // If we read the whole thing, we have to do further checks. |
| 2887 | const longest_keyword_or_primitive_len = comptime blk: { | 2887 | const longest_keyword_or_primitive_len = comptime blk: { |
| 2888 | var longest = 0; | 2888 | var longest = 0; |
| 2889 | for (primitives.names.kvs) |kv| { | 2889 | for (primitives.names.keys()) |key| { |
| 2890 | if (kv.key.len > longest) longest = kv.key.len; | 2890 | if (key.len > longest) longest = key.len; |
| 2891 | } | 2891 | } |
| 2892 | for (std.zig.Token.keywords.kvs) |kv| { | 2892 | for (std.zig.Token.keywords.keys()) |key| { |
| 2893 | if (kv.key.len > longest) longest = kv.key.len; | 2893 | if (key.len > longest) longest = key.len; |
| 2894 | } | 2894 | } |
| 2895 | break :blk longest; | 2895 | break :blk longest; |
| 2896 | }; | 2896 | }; |
lib/std/zig/tokenizer.zig+1-1| ... | @@ -9,7 +9,7 @@ pub const Token = struct { | ... | @@ -9,7 +9,7 @@ pub const Token = struct { |
| 9 | end: usize, | 9 | end: usize, |
| 10 | }; | 10 | }; |
| 11 | 11 | ||
| 12 | pub const keywords = std.ComptimeStringMap(Tag, .{ | 12 | pub const keywords = std.StaticStringMap(Tag).initComptime(.{ |
| 13 | .{ "addrspace", .keyword_addrspace }, | 13 | .{ "addrspace", .keyword_addrspace }, |
| 14 | .{ "align", .keyword_align }, | 14 | .{ "align", .keyword_align }, |
| 15 | .{ "allowzero", .keyword_allowzero }, | 15 | .{ "allowzero", .keyword_allowzero }, |
src/Compilation.zig+1-1| ... | @@ -265,7 +265,7 @@ pub const CRTFile = struct { | ... | @@ -265,7 +265,7 @@ pub const CRTFile = struct { |
| 265 | 265 | ||
| 266 | /// Supported languages for "zig clang -x <lang>". | 266 | /// Supported languages for "zig clang -x <lang>". |
| 267 | /// Loosely based on llvm-project/clang/include/clang/Driver/Types.def | 267 | /// Loosely based on llvm-project/clang/include/clang/Driver/Types.def |
| 268 | pub const LangToExt = std.ComptimeStringMap(FileExt, .{ | 268 | pub const LangToExt = std.StaticStringMap(FileExt).initComptime(.{ |
| 269 | .{ "c", .c }, | 269 | .{ "c", .c }, |
| 270 | .{ "c-header", .h }, | 270 | .{ "c-header", .h }, |
| 271 | .{ "c++", .cpp }, | 271 | .{ "c++", .cpp }, |
src/codegen/c.zig+1-1| ... | @@ -116,7 +116,7 @@ const ValueRenderLocation = enum { | ... | @@ -116,7 +116,7 @@ const ValueRenderLocation = enum { |
| 116 | 116 | ||
| 117 | const BuiltinInfo = enum { none, bits }; | 117 | const BuiltinInfo = enum { none, bits }; |
| 118 | 118 | ||
| 119 | const reserved_idents = std.ComptimeStringMap(void, .{ | 119 | const reserved_idents = std.StaticStringMap(void).initComptime(.{ |
| 120 | // C language | 120 | // C language |
| 121 | .{ "alignas", { | 121 | .{ "alignas", { |
| 122 | @setEvalBranchQuota(4000); | 122 | @setEvalBranchQuota(4000); |
src/link/Wasm/types.zig+1-1| ... | @@ -244,7 +244,7 @@ pub const Feature = struct { | ... | @@ -244,7 +244,7 @@ pub const Feature = struct { |
| 244 | } | 244 | } |
| 245 | }; | 245 | }; |
| 246 | 246 | ||
| 247 | pub const known_features = std.ComptimeStringMap(Feature.Tag, .{ | 247 | pub const known_features = std.StaticStringMap(Feature.Tag).initComptime(.{ |
| 248 | .{ "atomics", .atomics }, | 248 | .{ "atomics", .atomics }, |
| 249 | .{ "bulk-memory", .bulk_memory }, | 249 | .{ "bulk-memory", .bulk_memory }, |
| 250 | .{ "exception-handling", .exception_handling }, | 250 | .{ "exception-handling", .exception_handling }, |
src/translate_c.zig+1-1| ... | @@ -671,7 +671,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co | ... | @@ -671,7 +671,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co |
| 671 | return addTopLevelDecl(c, var_name, node); | 671 | return addTopLevelDecl(c, var_name, node); |
| 672 | } | 672 | } |
| 673 | 673 | ||
| 674 | const builtin_typedef_map = std.ComptimeStringMap([]const u8, .{ | 674 | const builtin_typedef_map = std.StaticStringMap([]const u8).initComptime(.{ |
| 675 | .{ "uint8_t", "u8" }, | 675 | .{ "uint8_t", "u8" }, |
| 676 | .{ "int8_t", "i8" }, | 676 | .{ "int8_t", "i8" }, |
| 677 | .{ "uint16_t", "u16" }, | 677 | .{ "uint16_t", "u16" }, |
test/src/Cases.zig+1-1| ... | @@ -993,7 +993,7 @@ const TestManifest = struct { | ... | @@ -993,7 +993,7 @@ const TestManifest = struct { |
| 993 | config_map: std.StringHashMap([]const u8), | 993 | config_map: std.StringHashMap([]const u8), |
| 994 | trailing_bytes: []const u8 = "", | 994 | trailing_bytes: []const u8 = "", |
| 995 | 995 | ||
| 996 | const valid_keys = std.ComptimeStringMap(void, .{ | 996 | const valid_keys = std.StaticStringMap(void).initComptime(.{ |
| 997 | .{ "is_test", {} }, | 997 | .{ "is_test", {} }, |
| 998 | .{ "output_mode", {} }, | 998 | .{ "output_mode", {} }, |
| 999 | .{ "target", {} }, | 999 | .{ "target", {} }, |
tools/gen_spirv_spec.zig+1-1| ... | @@ -45,7 +45,7 @@ const OperandKindMap = std.ArrayHashMap(StringPair, OperandKind, StringPairConte | ... | @@ -45,7 +45,7 @@ const OperandKindMap = std.ArrayHashMap(StringPair, OperandKind, StringPairConte |
| 45 | /// Khronos made it so that these names are not defined explicitly, so | 45 | /// Khronos made it so that these names are not defined explicitly, so |
| 46 | /// we need to hardcode it (like they did). | 46 | /// we need to hardcode it (like they did). |
| 47 | /// See https://github.com/KhronosGroup/SPIRV-Registry/ | 47 | /// See https://github.com/KhronosGroup/SPIRV-Registry/ |
| 48 | const set_names = std.ComptimeStringMap([]const u8, .{ | 48 | const set_names = std.StaticStringMap([]const u8).initComptime(.{ |
| 49 | .{ "opencl.std.100", "OpenCL.std" }, | 49 | .{ "opencl.std.100", "OpenCL.std" }, |
| 50 | .{ "glsl.std.450", "GLSL.std.450" }, | 50 | .{ "glsl.std.450", "GLSL.std.450" }, |
| 51 | .{ "opencl.debuginfo.100", "OpenCL.DebugInfo.100" }, | 51 | .{ "opencl.debuginfo.100", "OpenCL.DebugInfo.100" }, |
tools/generate_linux_syscalls.zig+1-1| ... | @@ -9,7 +9,7 @@ const fmt = std.fmt; | ... | @@ -9,7 +9,7 @@ const fmt = std.fmt; |
| 9 | const zig = std.zig; | 9 | const zig = std.zig; |
| 10 | const fs = std.fs; | 10 | const fs = std.fs; |
| 11 | 11 | ||
| 12 | const stdlib_renames = std.ComptimeStringMap([]const u8, .{ | 12 | const stdlib_renames = std.StaticStringMap([]const u8).initComptime(.{ |
| 13 | // Most 64-bit archs. | 13 | // Most 64-bit archs. |
| 14 | .{ "newfstatat", "fstatat64" }, | 14 | .{ "newfstatat", "fstatat64" }, |
| 15 | // POWER. | 15 | // POWER. |