| ... | @@ -1941,13 +1941,29 @@ test "joinZ" { | ... | @@ -1941,13 +1941,29 @@ test "joinZ" { |
| 1941 | | 1941 | |
| 1942 | /// Copies each T from slices into a new slice that exactly holds all the elements. | 1942 | /// Copies each T from slices into a new slice that exactly holds all the elements. |
| 1943 | pub fn concat(allocator: Allocator, comptime T: type, slices: []const []const T) ![]T { | 1943 | pub fn concat(allocator: Allocator, comptime T: type, slices: []const []const T) ![]T { |
| 1944 | if (slices.len == 0) return &[0]T{}; | 1944 | return concatMaybeSentinel(allocator, T, slices, null); |
| | 1945 | } |
| | 1946 | |
| | 1947 | /// Copies each T from slices into a new slice that exactly holds all the elements. |
| | 1948 | pub fn concatWithSentinel(allocator: Allocator, comptime T: type, slices: []const []const T, comptime s: T) ![:s]T { |
| | 1949 | const ret = try concatMaybeSentinel(allocator, T, slices, s); |
| | 1950 | return ret[0 .. ret.len - 1 :s]; |
| | 1951 | } |
| | 1952 | |
| | 1953 | /// Copies each T from slices into a new slice that exactly holds all the elements as well as the sentinel. |
| | 1954 | pub fn concatMaybeSentinel(allocator: Allocator, comptime T: type, slices: []const []const T, comptime s: ?T) ![]T { |
| | 1955 | if (slices.len == 0) return if (s) |sentinel| try allocator.dupe(T, &[1]T{sentinel}) else &[0]T{}; |
| 1945 | | 1956 | |
| 1946 | const total_len = blk: { | 1957 | const total_len = blk: { |
| 1947 | var sum: usize = 0; | 1958 | var sum: usize = 0; |
| 1948 | for (slices) |slice| { | 1959 | for (slices) |slice| { |
| 1949 | sum += slice.len; | 1960 | sum += slice.len; |
| 1950 | } | 1961 | } |
| | 1962 | |
| | 1963 | if (s) |_| { |
| | 1964 | sum += 1; |
| | 1965 | } |
| | 1966 | |
| 1951 | break :blk sum; | 1967 | break :blk sum; |
| 1952 | }; | 1968 | }; |
| 1953 | | 1969 | |
| ... | @@ -1960,6 +1976,10 @@ pub fn concat(allocator: Allocator, comptime T: type, slices: []const []const T) | ... | @@ -1960,6 +1976,10 @@ pub fn concat(allocator: Allocator, comptime T: type, slices: []const []const T) |
| 1960 | buf_index += slice.len; | 1976 | buf_index += slice.len; |
| 1961 | } | 1977 | } |
| 1962 | | 1978 | |
| | 1979 | if (s) |sentinel| { |
| | 1980 | buf[buf.len - 1] = sentinel; |
| | 1981 | } |
| | 1982 | |
| 1963 | // No need for shrink since buf is exactly the correct size. | 1983 | // No need for shrink since buf is exactly the correct size. |
| 1964 | return buf; | 1984 | return buf; |
| 1965 | } | 1985 | } |
| ... | @@ -1980,6 +2000,26 @@ test "concat" { | ... | @@ -1980,6 +2000,26 @@ test "concat" { |
| 1980 | defer testing.allocator.free(str); | 2000 | defer testing.allocator.free(str); |
| 1981 | try testing.expect(eql(u32, str, &[_]u32{ 0, 1, 2, 3, 4, 5 })); | 2001 | try testing.expect(eql(u32, str, &[_]u32{ 0, 1, 2, 3, 4, 5 })); |
| 1982 | } | 2002 | } |
| | 2003 | { |
| | 2004 | const str = try concatWithSentinel(testing.allocator, u8, &[_][]const u8{ "abc", "def", "ghi" }, 0); |
| | 2005 | defer testing.allocator.free(str); |
| | 2006 | try testing.expectEqualSentinel(u8, 0, str, "abcdefghi"); |
| | 2007 | } |
| | 2008 | { |
| | 2009 | const slice = try concatWithSentinel(testing.allocator, u8, &[_][]const u8{}, 0); |
| | 2010 | defer testing.allocator.free(slice); |
| | 2011 | try testing.expectEqualSentinel(u8, 0, slice, &[_:0]u8{}); |
| | 2012 | } |
| | 2013 | { |
| | 2014 | const slice = try concatWithSentinel(testing.allocator, u32, &[_][]const u32{ |
| | 2015 | &[_]u32{ 0, 1 }, |
| | 2016 | &[_]u32{ 2, 3, 4 }, |
| | 2017 | &[_]u32{}, |
| | 2018 | &[_]u32{5}, |
| | 2019 | }, 2); |
| | 2020 | defer testing.allocator.free(slice); |
| | 2021 | try testing.expectEqualSentinel(u32, 2, slice, &[_:2]u32{ 0, 1, 2, 3, 4, 5 }); |
| | 2022 | } |
| 1983 | } | 2023 | } |
| 1984 | | 2024 | |
| 1985 | test "testStringEquality" { | 2025 | test "testStringEquality" { |