input: change our binding set to use array hash map

This is recommended for ongoing performance: 
https://github.com/ziglang/zig/issues/17851

Likely not an issue for this particular use case which is why it never
bit us; we don't actively modify this map much once it is created. But,
its still good hygiene and ArrayHashMap made some of the API usage
nicer.
This commit is contained in:
Mitchell Hashimoto
2026-01-09 08:46:35 -08:00
parent 201198c74a
commit 0e9ce7e450
2 changed files with 29 additions and 22 deletions

View File

@@ -6830,7 +6830,7 @@ pub const Keybinds = struct {
/// Like formatEntry but has an option to include docs.
pub fn formatEntryDocs(self: Keybinds, formatter: formatterpkg.EntryFormatter, docs: bool) !void {
if (self.set.bindings.size == 0 and self.tables.count() == 0) {
if (self.set.bindings.count() == 0 and self.tables.count() == 0) {
try formatter.formatEntry(void, {});
return;
}
@@ -6932,8 +6932,8 @@ pub const Keybinds = struct {
// Note they turn into translated keys because they match
// their ASCII mapping.
const want =
\\keybind = ctrl+z>2=goto_tab:2
\\keybind = ctrl+z>1=goto_tab:1
\\keybind = ctrl+z>2=goto_tab:2
\\
;
try std.testing.expectEqualStrings(want, buf.written());
@@ -6957,9 +6957,9 @@ pub const Keybinds = struct {
// NB: This does not currently retain the order of the keybinds.
const want =
\\a = ctrl+a>ctrl+c>t=new_tab
\\a = ctrl+a>ctrl+b>w=close_window
\\a = ctrl+a>ctrl+b>n=new_window
\\a = ctrl+a>ctrl+b>w=close_window
\\a = ctrl+a>ctrl+c>t=new_tab
\\a = ctrl+b>ctrl+d>a=previous_tab
\\
;

View File

@@ -1998,18 +1998,18 @@ pub const Trigger = struct {
/// The use case is that this will be called on EVERY key input to look
/// for an associated action so it must be fast.
pub const Set = struct {
const HashMap = std.HashMapUnmanaged(
const HashMap = std.ArrayHashMapUnmanaged(
Trigger,
Value,
Context(Trigger),
std.hash_map.default_max_load_percentage,
true,
);
const ReverseMap = std.HashMapUnmanaged(
const ReverseMap = std.ArrayHashMapUnmanaged(
Action,
Trigger,
Context(Action),
std.hash_map.default_max_load_percentage,
true,
);
/// The set of bindings.
@@ -2503,11 +2503,10 @@ pub const Set = struct {
// update the reverse mapping to remove the old action.
.leaf => if (track_reverse) {
const t_hash = t.hash();
var it = self.reverse.iterator();
while (it.next()) |reverse_entry| it: {
if (t_hash == reverse_entry.value_ptr.hash()) {
self.reverse.removeByPtr(reverse_entry.key_ptr);
break :it;
for (0.., self.reverse.values()) |i, *value| {
if (t_hash == value.hash()) {
self.reverse.swapRemoveAt(i);
break;
}
}
},
@@ -2523,7 +2522,7 @@ pub const Set = struct {
.action = action,
.flags = flags,
} };
errdefer _ = self.bindings.remove(t);
errdefer _ = self.bindings.swapRemove(t);
if (track_reverse) try self.reverse.put(alloc, action, t);
errdefer if (track_reverse) self.reverse.remove(action);
@@ -2663,7 +2662,7 @@ pub const Set = struct {
self.chain_parent = null;
var entry = self.bindings.get(t) orelse return;
_ = self.bindings.remove(t);
_ = self.bindings.swapRemove(t);
switch (entry) {
// For a leader removal, we need to deallocate our child set.
@@ -2733,7 +2732,7 @@ pub const Set = struct {
// No other trigger points to this action so we remove
// the reverse mapping completely.
_ = self.reverse.remove(action);
_ = self.reverse.swapRemove(action);
}
/// Deep clone the set.
@@ -2766,9 +2765,8 @@ pub const Set = struct {
// We need to clone the action keys in the reverse map since
// they may contain allocated values.
{
var it = result.reverse.keyIterator();
while (it.next()) |action| action.* = try action.clone(alloc);
for (result.reverse.keys()) |*action| {
action.* = try action.clone(alloc);
}
return result;
@@ -2778,13 +2776,22 @@ pub const Set = struct {
/// gets the hash key and checks for equality.
fn Context(comptime KeyType: type) type {
return struct {
pub fn hash(ctx: @This(), k: KeyType) u64 {
pub fn hash(ctx: @This(), k: KeyType) u32 {
_ = ctx;
return k.hash();
// This seems crazy at first glance but this is also how
// the Zig standard library handles hashing for array
// hash maps!
return @truncate(k.hash());
}
pub fn eql(ctx: @This(), a: KeyType, b: KeyType) bool {
pub fn eql(
ctx: @This(),
a: KeyType,
b: KeyType,
b_index: usize,
) bool {
_ = ctx;
_ = b_index;
return a.bindingSetEqual(b);
}
};