authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2020-07-08 23:07:44+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-12 22:17:40+00:00
logef17af1270155e803a77955c9f37175dd09c43d4
tree6acbd18cdd280d95e10f45b75df45da7cdb704cf
parent5b570bceb531656c320684fbe42a87feff710a3b

std: add mem.joinZ

currently the only options are doing a second allocation and copying or implementing this yourself.

1 files changed, 36 insertions(+), 2 deletions(-)

lib/std/mem.zig+36-2
...@@ -1674,12 +1674,23 @@ pub const SplitIterator = struct {...@@ -1674,12 +1674,23 @@ pub const SplitIterator = struct {
1674/// Naively combines a series of slices with a separator.1674/// Naively combines a series of slices with a separator.
1675/// Allocates memory for the result, which must be freed by the caller.1675/// Allocates memory for the result, which must be freed by the caller.
1676pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []const u8) ![]u8 {1676pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []const u8) ![]u8 {
1677 return joinMaybeZ(allocator, separator, slices, false);
1678}
1679
1680/// Naively combines a series of slices with a separator and null terminator.
1681/// Allocates memory for the result, which must be freed by the caller.
1682pub fn joinZ(allocator: *Allocator, separator: []const u8, slices: []const []const u8) ![:0]u8 {
1683 const out = try joinMaybeZ(allocator, separator, slices, true);
1684 return out[0 .. out.len - 1 :0];
1685}
1686
1687fn joinMaybeZ(allocator: *Allocator, separator: []const u8, slices: []const []const u8, zero: bool) ![]u8 {
1677 if (slices.len == 0) return &[0]u8{};1688 if (slices.len == 0) return &[0]u8{};
16781689
1679 const total_len = blk: {1690 const total_len = blk: {
1680 var sum: usize = separator.len * (slices.len - 1);1691 var sum: usize = separator.len * (slices.len - 1);
1681 for (slices) |slice|1692 for (slices) |slice| sum += slice.len;
1682 sum += slice.len;1693 if (zero) sum += 1;
1683 break :blk sum;1694 break :blk sum;
1684 };1695 };
16851696
...@@ -1695,6 +1706,8 @@ pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []cons...@@ -1695,6 +1706,8 @@ pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []cons
1695 buf_index += slice.len;1706 buf_index += slice.len;
1696 }1707 }
16971708
1709 if (zero) buf[buf.len - 1] = 0;
1710
1698 // No need for shrink since buf is exactly the correct size.1711 // No need for shrink since buf is exactly the correct size.
1699 return buf;1712 return buf;
1700}1713}
...@@ -1717,6 +1730,27 @@ test "mem.join" {...@@ -1717,6 +1730,27 @@ test "mem.join" {
1717 }1730 }
1718}1731}
17191732
1733test "mem.joinZ" {
1734 {
1735 const str = try joinZ(testing.allocator, ",", &[_][]const u8{ "a", "b", "c" });
1736 defer testing.allocator.free(str);
1737 testing.expect(eql(u8, str, "a,b,c"));
1738 testing.expectEqual(str[str.len], 0);
1739 }
1740 {
1741 const str = try joinZ(testing.allocator, ",", &[_][]const u8{"a"});
1742 defer testing.allocator.free(str);
1743 testing.expect(eql(u8, str, "a"));
1744 testing.expectEqual(str[str.len], 0);
1745 }
1746 {
1747 const str = try joinZ(testing.allocator, ",", &[_][]const u8{ "a", "", "b", "", "c" });
1748 defer testing.allocator.free(str);
1749 testing.expect(eql(u8, str, "a,,b,,c"));
1750 testing.expectEqual(str[str.len], 0);
1751 }
1752}
1753
1720/// Copies each T from slices into a new slice that exactly holds all the elements.1754/// Copies each T from slices into a new slice that exactly holds all the elements.
1721pub fn concat(allocator: *Allocator, comptime T: type, slices: []const []const T) ![]T {1755pub fn concat(allocator: *Allocator, comptime T: type, slices: []const []const T) ![]T {
1722 if (slices.len == 0) return &[0]T{};1756 if (slices.len == 0) return &[0]T{};