Commit 41654a318d

Yusuf Bham <ybham6@gmail.com>
2022-04-17 17:43:45
std.mem: add concatWithSentinel
1 parent 6d0283e
Changed files (1)
lib
lib/std/mem.zig
@@ -1941,13 +1941,29 @@ test "joinZ" {
 
 /// Copies each T from slices into a new slice that exactly holds all the elements.
 pub fn concat(allocator: Allocator, comptime T: type, slices: []const []const T) ![]T {
-    if (slices.len == 0) return &[0]T{};
+    return concatMaybeSentinel(allocator, T, slices, null);
+}
+
+/// Copies each T from slices into a new slice that exactly holds all the elements.
+pub fn concatWithSentinel(allocator: Allocator, comptime T: type, slices: []const []const T, comptime s: T) ![:s]T {
+    const ret = try concatMaybeSentinel(allocator, T, slices, s);
+    return ret[0 .. ret.len - 1 :s];
+}
+
+/// Copies each T from slices into a new slice that exactly holds all the elements as well as the sentinel.
+pub fn concatMaybeSentinel(allocator: Allocator, comptime T: type, slices: []const []const T, comptime s: ?T) ![]T {
+    if (slices.len == 0) return if (s) |sentinel| try allocator.dupe(T, &[1]T{sentinel}) else &[0]T{};
 
     const total_len = blk: {
         var sum: usize = 0;
         for (slices) |slice| {
             sum += slice.len;
         }
+
+        if (s) |_| {
+            sum += 1;
+        }
+
         break :blk sum;
     };
 
@@ -1960,6 +1976,10 @@ pub fn concat(allocator: Allocator, comptime T: type, slices: []const []const T)
         buf_index += slice.len;
     }
 
+    if (s) |sentinel| {
+        buf[buf.len - 1] = sentinel;
+    }
+
     // No need for shrink since buf is exactly the correct size.
     return buf;
 }
@@ -1980,6 +2000,26 @@ test "concat" {
         defer testing.allocator.free(str);
         try testing.expect(eql(u32, str, &[_]u32{ 0, 1, 2, 3, 4, 5 }));
     }
+    {
+        const str = try concatWithSentinel(testing.allocator, u8, &[_][]const u8{ "abc", "def", "ghi" }, 0);
+        defer testing.allocator.free(str);
+        try testing.expectEqualSentinel(u8, 0, str, "abcdefghi");
+    }
+    {
+        const slice = try concatWithSentinel(testing.allocator, u8, &[_][]const u8{}, 0);
+        defer testing.allocator.free(slice);
+        try testing.expectEqualSentinel(u8, 0, slice, &[_:0]u8{});
+    }
+    {
+        const slice = try concatWithSentinel(testing.allocator, u32, &[_][]const u32{
+            &[_]u32{ 0, 1 },
+            &[_]u32{ 2, 3, 4 },
+            &[_]u32{},
+            &[_]u32{5},
+        }, 2);
+        defer testing.allocator.free(slice);
+        try testing.expectEqualSentinel(u32, 2, slice, &[_:2]u32{ 0, 1, 2, 3, 4, 5 });
+    }
 }
 
 test "testStringEquality" {