authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-04-21 21:56:00 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-04-21 21:56:00 -07:00
log220ea9f68ae2fadb0ec3985228259467e001ba94
tree3803c317c760ab1fbc5d17413d276fb35f86c78d
parent487852c217fd23097a0dba82efa6edfaed13a9d4
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

Tree: replace children with MultiArrayList to enable binary search in get

only sort folders with more than 1000 entries the speedup to search has to be worth the time to sort

1 files changed, 38 insertions(+), 14 deletions(-)

git.zig+38-14
......@@ -270,15 +270,19 @@ fn parseTreeMode(input: string) !Tree.Object.Mode {
270270}
271271
272272pub const Tree = struct {
273 children: []const Object,
273 children: std.MultiArrayList(Object).Slice,
274274
275275 pub fn get(self: Tree, name: string) ?Object {
276 for (self.children) |item| {
277 if (std.mem.eql(u8, item.name, name)) {
278 return item;
276 if (self.children.len <= 1000) {
277 for (self.children.items(.name), 0..) |a_name, i| {
278 if (std.mem.eql(u8, a_name, name)) {
279 return self.children.get(i);
280 }
279281 }
282 return null;
280283 }
281 return null;
284 const i = std.sort.binarySearch([]const u8, self.children.items(.name), name, extras.compareFnSlice(u8)) orelse return null;
285 return self.children.get(i);
282286 }
283287
284288 pub fn getBlob(self: Tree, name: string) ?Object {
......@@ -288,9 +292,9 @@ pub const Tree = struct {
288292 }
289293
290294 pub fn find(self: Tree, name: string) ?Object {
291 for (self.children) |item| {
292 if (std.ascii.eqlIgnoreCase(item.name, name)) {
293 return item;
295 for (self.children.items(.name), 0..) |item, i| {
296 if (std.ascii.eqlIgnoreCase(item, name)) {
297 return self.children.get(i);
294298 }
295299 }
296300 return null;
......@@ -860,7 +864,7 @@ pub const Repository = struct {
860864 for (r.pack_content.values()) |v| nfs.munmap(v);
861865 r.pack_content.deinit(r.gpa);
862866 r.commits.deinit(r.gpa);
863 for (r.trees.values()) |v| r.gpa.free(v.children);
867 for (r.trees.values()) |*v| v.children.deinit(r.gpa);
864868 r.trees.deinit(r.gpa);
865869 r.tags.deinit(r.gpa);
866870 }
......@@ -1192,8 +1196,9 @@ pub const Repository = struct {
11921196 }
11931197 if (try r.getObject(arena, id.id)) |obj| {
11941198 if (obj.type == .tree) {
1195 var children = std.ArrayList(Tree.Object).init(r.gpa);
1196 errdefer children.deinit();
1199 var children: std.MultiArrayList(Tree.Object) = .empty;
1200 errdefer children.deinit(r.gpa);
1201 try children.ensureUnusedCapacity(r.gpa, 33);
11971202 var i: usize = 0;
11981203 while (i < obj.content.len) {
11991204 const mode_end = std.mem.indexOfScalar(u8, obj.content[i..], ' ').?;
......@@ -1213,7 +1218,7 @@ pub const Repository = struct {
12131218 @memcpy(mode_buf[6 - mode.len ..], mode);
12141219 const mode_real = try parseTreeMode(&mode_buf);
12151220
1216 try children.append(.{
1221 try children.append(r.gpa, .{
12171222 .mode = mode_real,
12181223 .name = name,
12191224 .id = switch (mode_real.type) {
......@@ -1225,7 +1230,26 @@ pub const Repository = struct {
12251230 },
12261231 });
12271232 }
1228 const tree: Tree = .{ .children = try children.toOwnedSlice() };
1233
1234 const S = struct {
1235 list: *std.MultiArrayList(Tree.Object),
1236
1237 pub fn lessThan(s: @This(), a: usize, b: usize) bool {
1238 const items = s.list.items(.name);
1239 return std.mem.order(u8, items[a], items[b]) == .lt;
1240 }
1241 pub fn swap(s: @This(), a: usize, b: usize) void {
1242 // Remove after updating to Zig 0.17. Ref: https://codeberg.org/ziglang/zig/pulls/32016
1243 inline for (@typeInfo(Tree.Object).@"struct".fields) |field| {
1244 const its = s.list.items(@field(std.MultiArrayList(Tree.Object).Field, field.name));
1245 std.mem.swap(@FieldType(Tree.Object, field.name), &its[a], &its[b]);
1246 }
1247 }
1248 };
1249 if (children.len > 1000) std.mem.sortContext(0, children.len, S{ .list = &children });
1250
1251 var tree: Tree = .{ .children = children.toOwnedSlice() };
1252 errdefer tree.children.deinit(r.gpa);
12291253 try r.trees.put(r.gpa, id.id, tree);
12301254 return .{ id, tree };
12311255 }
......@@ -1342,7 +1366,7 @@ pub const Repository = struct {
13421366 var found: usize = 0;
13431367 var result: std.StringArrayHashMapUnmanaged(CommitId) = .empty;
13441368 defer result.deinit(r.gpa);
1345 for (base_tree.children) |item| try result.put(r.gpa, item.name, undefined);
1369 for (base_tree.children.items(.name)) |name| try result.put(r.gpa, name, undefined);
13461370
13471371 var set: std.bit_set.DynamicBitSetUnmanaged = try .initEmpty(r.gpa, total);
13481372 defer set.deinit(r.gpa);