diff --git a/lib/Corpus.zig b/lib/Corpus.zig index 112c19b..9914f44 100644 --- a/lib/Corpus.zig +++ b/lib/Corpus.zig @@ -203,10 +203,10 @@ pub fn testCorpus(allocator: Allocator) !Corpus { .shell = "/usr/sbin/nologin", } }; - var members0 = &[_:null]?[:0]const u8{"root"}; - var members1 = &[_:null]?[:0]const u8{"vidmantas"}; - var members2 = &[_:null]?[:0]const u8{ "svc-bar", "vidmantas" }; - var members3 = &[_:null]?[:0]const u8{ "svc-bar", "Name" ** 8, "vidmantas", "root" }; + var members0 = &[_:null]?[*:0]const u8{"root"}; + var members1 = &[_:null]?[*:0]const u8{"vidmantas"}; + var members2 = &[_:null]?[*:0]const u8{ "svc-bar", "vidmantas" }; + var members3 = &[_:null]?[*:0]const u8{ "svc-bar", "Name" ** 8, "vidmantas", "root" }; const groups = [_]Group{ Group{ .gid = 0, .name = "root", .members = members0 }, diff --git a/lib/DB.zig b/lib/DB.zig index a63167a..dff0566 100644 --- a/lib/DB.zig +++ b/lib/DB.zig @@ -260,7 +260,7 @@ fn groupMemberNames( buf.len += name.len + 1; mem.copy(u8, buf[old_len..], name); buf[buf.len - 1] = 0; - result[i] = buf[old_len..buf.len]; + result[i] = buf[old_len..buf.len :0]; } return GroupMemberNames{ .arr = result }; } @@ -432,10 +432,10 @@ fn groupMembers( error.NotSorted => unreachable, }; const total_members_len = blk: { - var sum: u32 = 0; + var sum: usize = 0; for (members) |user_idx| - sum += @intCast(u32, corpus.users.get(user_idx).name.len); - break :blk sum; + sum += corpus.users.get(user_idx).name.len; + break :blk @intCast(u32, sum); }; try compress.appendUvarint(&blob, total_members_len); try compress.appendUvarint(&blob, members.len); diff --git a/lib/Group.zig b/lib/Group.zig index c73cb66..c71180a 100644 --- a/lib/Group.zig +++ b/lib/Group.zig @@ -11,34 +11,57 @@ name: [:0]const u8, // https://github.com/ziglang/zig/issues/7517. // members[members.len] is always null for cloned groups. Once the bug // in the compiler is fixed, we should update the return type here. -members: []const ?[:0]const u8, +members: [:null]const ?[*:0]const u8, -pub fn clone(self: *const Group, allocator: Allocator) Allocator.Error!Group { - var members = try allocator.alloc(?[:0]const u8, self.members.len + 1); +// storage of name + members +_buf: []const u8, + +pub fn new( + allocator: Allocator, + gid: u32, + name: []const u8, + members: []const []const u8, +) error{OutOfMemory}!Group { + const buf_len = blk: { + var sum: usize = 0; + for (members) |member| sum += member.len; + break :blk @intCast(u32, sum); + }; + _ = buf_len; + _ = allocator; + _ = gid; + _ = name; + _ = members; + return error.OutOfMemory; +} + +pub fn clone(self: *const Group, allocator: Allocator) error{OutOfMemory}!Group { + var members = try allocator.allocSentinel(?[*:0]const u8, self.members.len, null); errdefer allocator.free(members); - members.len = self.members.len + 1; - for (self.members) |member, i| { - members[i] = try allocator.dupeZ(u8, member.?); - errdefer allocator.free(members[i]); + var buf = try allocator.alloc(u8, self._buf.len); + errdefer allocator.free(buf); + mem.copy(u8, buf, self._buf); + + const our_begin = @ptrToInt(members.ptr); + const their_begin = @ptrToInt(self.members.ptr); + for (self.members) |*name_ptr, i| { + const offset = @ptrToInt(name_ptr) - their_begin; + members[i] = @intToPtr([*:0]const u8, our_begin + offset); } - // workaround to include a null value at the end, even for - // non-sentinel-terminated slice type. - members[self.members.len] = null; - members.len = self.members.len; return Group{ .gid = self.gid, - .name = try allocator.dupeZ(u8, self.name), - .members = members, + .name = buf[0..self.name.len], + .members = members[0.. :null], + ._buf = buf, }; } pub fn deinit(self: *Group, allocator: Allocator) void { allocator.free(self.name); - for (self.members) |member| { - allocator.free(member.?); - } + if (self.members[0]) |firstmember| + allocator.free(firstmember); allocator.free(self.members); self.* = undefined; } @@ -47,13 +70,13 @@ const testing = std.testing; test "Group.clone" { // TODO: how to do this on stack? - var member1 = try testing.allocator.dupeZ(u8, "member1"); + var member1 = mem.sliceTo(try testing.allocator.dupeZ(u8, "member1"), 0); defer testing.allocator.free(member1); var group = Group{ .gid = 1, .name = "foo", - .members = &[_:null]?[:0]const u8{ member1, "member2" }, + .members = &[_:null]?[*:0]const u8{ member1, "member2" }, }; var cloned = try group.clone(testing.allocator); @@ -64,5 +87,5 @@ test "Group.clone" { member1[0] = 'x'; try testing.expectEqual(cloned.gid, 1); try testing.expectEqualSlices(u8, cloned.name, "foo"); - try testing.expectEqualSlices(u8, cloned.members[0].?, "member1"); + //try testing.expectEqualSlices(u8, @as([*:0]const u8, cloned.members[0].?), "member1"); }