diff --git a/src/sections.zig b/src/sections.zig index 56acbed..5eac4ff 100644 --- a/src/sections.zig +++ b/src/sections.zig @@ -38,7 +38,7 @@ const Corpus = struct { name2user: StringHashMap(u32), name2group: StringHashMap(u32), group2users: []const []const u32, - username2groups: StringHashMap([]u32), + user2groups: []const []const u32, pub fn init( baseAllocator: Allocator, @@ -88,10 +88,9 @@ const Corpus = struct { // uses baseAllocator, because it will be freed before // returning from this function. This keeps the arena clean. - var username2groups = StringHashMap( - ArrayListUnmanaged(u32), - ).init(baseAllocator); - defer username2groups.deinit(); + var user2groups = try baseAllocator.alloc(ArrayListUnmanaged(u32), users.len); + defer baseAllocator.free(user2groups); + mem.set(ArrayListUnmanaged(u32), user2groups, ArrayListUnmanaged(u32){}); for (groups) |*group, i| { var members = try allocator.alloc(u32, group.members.count()); @@ -99,36 +98,27 @@ const Corpus = struct { var it = group.members.iterator(); while (it.next()) |memberName| { - if (name2user.get(memberName.*)) |idx| { + if (name2user.get(memberName.*)) |user_idx| { members.len += 1; - members[members.len - 1] = idx; + members[members.len - 1] = user_idx; + try user2groups[user_idx].append(allocator, @intCast(u32, i)); } else { return error.NotFound; } - - var groupsOfMember = try username2groups.getOrPut(memberName.*); - if (!groupsOfMember.found_existing) - groupsOfMember.value_ptr.* = ArrayListUnmanaged(u32){}; - try groupsOfMember.value_ptr.*.append(allocator, @intCast(u32, i)); } group2users[i] = members; } - for (group2users) |*groupUsers| { - sort.sort(u32, groupUsers.*, {}, comptime sort.asc(u32)); + for (group2users) |*groupusers| { + sort.sort(u32, groupusers.*, {}, comptime sort.asc(u32)); } - var it2 = username2groups.valueIterator(); - while (it2.next()) |userGroups| - sort.sort(u32, userGroups.items, {}, comptime sort.asc(u32)); - - var username2groups_final = StringHashMap([]u32).init(allocator); - var it = username2groups.iterator(); - while (it.next()) |elem| { - const username = elem.key_ptr.*; - const usergroups = elem.value_ptr.*.toOwnedSlice(allocator); - try username2groups_final.put(username, usergroups); + var user2groups_final = try allocator.alloc([]const u32, users.len); + user2groups_final.len = users.len; + for (user2groups) |*usergroups, i| { + sort.sort(u32, usergroups.items, {}, comptime sort.asc(u32)); + user2groups_final[i] = usergroups.toOwnedSlice(allocator); } return Corpus{ @@ -140,7 +130,7 @@ const Corpus = struct { .name2user = name2user, .name2group = name2group, .group2users = group2users, - .username2groups = username2groups_final, + .user2groups = user2groups_final, }; } @@ -216,23 +206,24 @@ pub fn userGids( var scratch = try allocator.alloc(u32, 256); defer allocator.free(scratch); - for (corpus.users) |user, user_idx| { - if (corpus.username2groups.get(user.name)) |usergroups| { - idx2offset[user_idx] = blob.items.len; - scratch = try allocator.realloc(scratch, usergroups.len); - scratch.len = usergroups.len; - for (usergroups) |group_idx, i| - scratch[i] = corpus.groups[group_idx].gid; - compress.deltaCompress(u32, scratch) catch |err| switch (err) { - error.NotSorted => unreachable, - }; - try compress.appendUvarint(&blob, usergroups.len); - for (scratch) |gid| - try compress.appendUvarint(&blob, gid); - try pad.arrayList(&blob, userGidsPaddingBits); - } else { + for (corpus.users) |_, user_idx| { + const usergroups = corpus.user2groups[user_idx]; + if (usergroups.len == 0) { idx2offset[user_idx] = 0; + continue; } + idx2offset[user_idx] = blob.items.len; + scratch = try allocator.realloc(scratch, usergroups.len); + scratch.len = usergroups.len; + for (usergroups) |group_idx, i| + scratch[i] = corpus.groups[group_idx].gid; + compress.deltaCompress(u32, scratch) catch |err| switch (err) { + error.NotSorted => unreachable, + }; + try compress.appendUvarint(&blob, usergroups.len); + for (scratch) |gid| + try compress.appendUvarint(&blob, gid); + try pad.arrayList(&blob, userGidsPaddingBits); } return UserGids{ @@ -510,12 +501,10 @@ test "test corpus" { try testing.expectEqual(membersOfAll[1], svc_bar); try testing.expectEqual(membersOfAll[2], vidmantas); - const groupsOfVidmantas = corpus.username2groups.get("vidmantas").?; + const groupsOfVidmantas = corpus.user2groups[vidmantas]; try testing.expectEqual(groupsOfVidmantas[0], g_service_account); try testing.expectEqual(groupsOfVidmantas[1], g_vidmantas); try testing.expectEqual(groupsOfVidmantas[2], g_all); - try testing.expectEqual(corpus.username2groups.get("nobody"), null); - try testing.expectEqual(corpus.username2groups.get("doesnotexist"), null); } test "test sections" { @@ -535,19 +524,19 @@ test "userGids" { var user_gids = try userGids(allocator, &corpus); defer user_gids.deinit(allocator); - for (corpus.users) |user, userIdx| { - const groups = corpus.username2groups.get(user.name); + for (corpus.users) |_, userIdx| { + const groups = corpus.user2groups[userIdx]; const offset = user_gids.idx2offset[userIdx]; - if (groups == null) { + if (groups.len == 0) { try testing.expect(offset == 0); continue; } var vit = try compress.VarintSliceIterator(user_gids.blob[offset..]); var it = compress.DeltaDecompressionIterator(&vit); - try testing.expectEqual(it.remaining(), groups.?.len); + try testing.expectEqual(it.remaining(), groups.len); var i: u64 = 0; while (try it.next()) |gid| : (i += 1) { - try testing.expectEqual(gid, corpus.groups[groups.?[i]].gid); + try testing.expectEqual(gid, corpus.groups[groups[i]].gid); } } }