Skip to content

Commit

Permalink
Optimize StaticStringMap, add StaticArrayMap. Remove runtime .init()
Browse files Browse the repository at this point in the history
StaticArrayMap and StaticArrayMapWithEql are more alternatives to
StaticStringMap and StaticStringMapWithEql, the difference being that
they can have an array of any type of uniquely represented data as the
key, rather than just an array of u8.

StaticStringMapIgnoreCase has been added to provide a case-insensitive
definition of StaticArrayMap. While you *can* use StaticArrayMapWithEql,
StaticStringMapIgnoreCase is a common usecase of StaticStringMap while
also being optimized with SIMD.

The construction of StaticStringMap (provided by StaticArrayMap) has
changed to be comptime-only. This change allows us to greatly improve
the generated machine code through sorting the keys by length and
comparing multiple bytes at the same time. The breaking changes include:
- StaticStringMapWithEql interface has changed - specifically, take a
  look at the function interface of the eql function, which now takes a
  comptime-time known length, a comptime-time known array of an expected
  key, a runtime-known array of the recieved key, and returns a boolean
  indicating whether the two classify as matching.
- The getLongestPrefix and getLongestPrefixIndex functions have been
  removed. They did not see much use.

As a result of these changes, performance is greatly improved. If you
have been using a runtime initialization of a StaticStringMap, consider
using comptime initialization or std.StaticStringMap.

Many test cases depended on getLongestPrefix, getLongestPrefixIndex, or
runtime initialization. Those test cases have been removed, as they are
no longer testing existing code.
  • Loading branch information
RetroDev256 committed Dec 26, 2024
1 parent 42dac40 commit 86bf50c
Show file tree
Hide file tree
Showing 8 changed files with 518 additions and 638 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ set(ZIG_STAGE2_SOURCES
lib/std/process/Child.zig
lib/std/sort.zig
lib/std/start.zig
lib/std/static_string_map.zig
lib/std/static_array_map.zig
lib/std/std.zig
lib/std/time.zig
lib/std/treap.zig
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler/resinator/lang.zig
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ test tagToId {
}

test "exhaustive tagToId" {
inline for (@typeInfo(LanguageId).Enum.fields) |field| {
inline for (@typeInfo(LanguageId).@"enum".fields) |field| {
const id = tagToId(field.name) catch |err| {
std.debug.print("tag: {s}\n", .{field.name});
return err;
Expand Down
65 changes: 13 additions & 52 deletions lib/compiler/resinator/rc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,7 @@ pub const Resource = enum {
fontdir_num,
manifest_num,

const map = std.StaticStringMapWithEql(
Resource,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
const map = std.StaticStringMapIgnoreCase(Resource).initComptime(.{
.{ "ACCELERATORS", .accelerators },
.{ "BITMAP", .bitmap },
.{ "CURSOR", .cursor },
Expand Down Expand Up @@ -160,19 +157,13 @@ pub const OptionalStatements = enum {
menu,
style,

pub const map = std.StaticStringMapWithEql(
OptionalStatements,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(OptionalStatements).initComptime(.{
.{ "CHARACTERISTICS", .characteristics },
.{ "LANGUAGE", .language },
.{ "VERSION", .version },
});

pub const dialog_map = std.StaticStringMapWithEql(
OptionalStatements,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const dialog_map = std.StaticStringMapIgnoreCase(OptionalStatements).initComptime(.{
.{ "CAPTION", .caption },
.{ "CLASS", .class },
.{ "EXSTYLE", .exstyle },
Expand Down Expand Up @@ -206,10 +197,7 @@ pub const Control = enum {
state3,
userbutton,

pub const map = std.StaticStringMapWithEql(
Control,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(Control).initComptime(.{
.{ "AUTO3STATE", .auto3state },
.{ "AUTOCHECKBOX", .autocheckbox },
.{ "AUTORADIOBUTTON", .autoradiobutton },
Expand Down Expand Up @@ -243,10 +231,7 @@ pub const Control = enum {
};

pub const ControlClass = struct {
pub const map = std.StaticStringMapWithEql(
res.ControlClass,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(res.ControlClass).initComptime(.{
.{ "BUTTON", .button },
.{ "EDIT", .edit },
.{ "STATIC", .static },
Expand Down Expand Up @@ -295,10 +280,7 @@ pub const MenuItem = enum {
menuitem,
popup,

pub const map = std.StaticStringMapWithEql(
MenuItem,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(MenuItem).initComptime(.{
.{ "MENUITEM", .menuitem },
.{ "POPUP", .popup },
});
Expand All @@ -315,10 +297,7 @@ pub const MenuItem = enum {
menubarbreak,
menubreak,

pub const map = std.StaticStringMapWithEql(
Option,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(Option).initComptime(.{
.{ "CHECKED", .checked },
.{ "GRAYED", .grayed },
.{ "HELP", .help },
Expand All @@ -333,10 +312,7 @@ pub const ToolbarButton = enum {
button,
separator,

pub const map = std.StaticStringMapWithEql(
ToolbarButton,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(ToolbarButton).initComptime(.{
.{ "BUTTON", .button },
.{ "SEPARATOR", .separator },
});
Expand All @@ -351,10 +327,7 @@ pub const VersionInfo = enum {
file_type,
file_subtype,

pub const map = std.StaticStringMapWithEql(
VersionInfo,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(VersionInfo).initComptime(.{
.{ "FILEVERSION", .file_version },
.{ "PRODUCTVERSION", .product_version },
.{ "FILEFLAGSMASK", .file_flags_mask },
Expand All @@ -369,10 +342,7 @@ pub const VersionBlock = enum {
block,
value,

pub const map = std.StaticStringMapWithEql(
VersionBlock,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(VersionBlock).initComptime(.{
.{ "BLOCK", .block },
.{ "VALUE", .value },
});
Expand All @@ -386,10 +356,7 @@ pub const TopLevelKeywords = enum {
characteristics,
stringtable,

pub const map = std.StaticStringMapWithEql(
TopLevelKeywords,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(TopLevelKeywords).initComptime(.{
.{ "LANGUAGE", .language },
.{ "VERSION", .version },
.{ "CHARACTERISTICS", .characteristics },
Expand All @@ -408,10 +375,7 @@ pub const CommonResourceAttributes = enum {
shared,
nonshared,

pub const map = std.StaticStringMapWithEql(
CommonResourceAttributes,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(CommonResourceAttributes).initComptime(.{
.{ "PRELOAD", .preload },
.{ "LOADONCALL", .loadoncall },
.{ "FIXED", .fixed },
Expand All @@ -432,10 +396,7 @@ pub const AcceleratorTypeAndOptions = enum {
shift,
control,

pub const map = std.StaticStringMapWithEql(
AcceleratorTypeAndOptions,
std.static_string_map.eqlAsciiIgnoreCase,
).initComptime(.{
pub const map = std.StaticStringMapIgnoreCase(AcceleratorTypeAndOptions).initComptime(.{
.{ "VIRTKEY", .virtkey },
.{ "ASCII", .ascii },
.{ "NOINVERT", .noinvert },
Expand Down
5 changes: 2 additions & 3 deletions lib/std/meta.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@ pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
// - https://github.com/ziglang/zig/issues/4055
// - https://github.com/ziglang/zig/issues/3863
if (@typeInfo(T).@"enum".fields.len <= 100) {
const kvs = comptime build_kvs: {
const map = comptime build_kvs: {
const EnumKV = struct { []const u8, T };
var kvs_array: [@typeInfo(T).@"enum".fields.len]EnumKV = undefined;
for (@typeInfo(T).@"enum".fields, 0..) |enumField, i| {
kvs_array[i] = .{ enumField.name, @field(T, enumField.name) };
}
break :build_kvs kvs_array[0..];
break :build_kvs std.StaticStringMap(T).initComptime(kvs_array);
};
const map = std.StaticStringMap(T).initComptime(kvs);
return map.get(str);
} else {
inline for (@typeInfo(T).@"enum".fields) |enumField| {
Expand Down
Loading

0 comments on commit 86bf50c

Please sign in to comment.