authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-07 10:43:14-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-07 10:43:14-05:00
log130f42274230ed380c730fcc658c565f443be540
tree9831b1ec06a144bc1c4eba67c488e77a5fdf893c
parent7fc99c33bde54e3f4bc946e7e00351bf594daa37
parent6a1a2898b1e44d7cd799286fb8b6fda06e3803da
signature Commit is signed but in an unrecognized format.

Merge branch 'zig-backport-std.mem.join' of https://github.com/kristate/zig into kristate-zig-backport-std.mem.join


1 files changed, 70 insertions(+), 32 deletions(-)

std/mem.zig+70-32
......@@ -856,31 +856,65 @@ pub const TokenIterator = struct {
856856 }
857857};
858858
859pub const SplitIterator = struct {
860 buffer: []const u8,
861 index: ?usize,
862 delimiter: []const u8,
863
864 /// Returns a slice of the next field, or null if splitting is complete.
865 pub fn next(self: *SplitIterator) ?[]const u8 {
866 const start = self.index orelse return null;
867 const end = if (indexOfPos(u8, self.buffer, start, self.delimiter)) |delim_start| blk: {
868 self.index = delim_start + self.delimiter.len;
869 break :blk delim_start;
870 } else blk: {
871 self.index = null;
872 break :blk self.buffer.len;
873 };
874 return self.buffer[start..end];
859/// Naively combines a series of strings with a separator.
860/// Allocates memory for the result, which must be freed by the caller.
861pub fn join(allocator: *Allocator, sep: u8, strings: []const []const u8) ![]u8 {
862 assert(strings.len >= 1);
863 var total_strings_len: usize = strings.len; // 1 sep per string
864 {
865 var string_i: usize = 0;
866 while (string_i < strings.len) : (string_i += 1) {
867 const arg = ([]const u8)(strings[string_i]);
868 total_strings_len += arg.len;
869 }
875870 }
876871
877 /// Returns a slice of the remaining bytes. Does not affect iterator state.
878 pub fn rest(self: SplitIterator) []const u8 {
879 const end = self.buffer.len;
880 const start = self.index orelse end;
881 return self.buffer[start..end];
872 const buf = try allocator.alloc(u8, total_strings_len);
873 errdefer allocator.free(buf);
874
875 var buf_index: usize = 0;
876 var string_i: usize = 0;
877 while (true) {
878 const arg = ([]const u8)(strings[string_i]);
879 string_i += 1;
880 copy(u8, buf[buf_index..], arg);
881 buf_index += arg.len;
882 if (string_i >= strings.len) break;
883 buf[buf_index] = sep;
884 buf_index += 1;
882885 }
883};
886
887 return allocator.shrink(u8, buf, buf_index);
888}
889
890test "mem.join" {
891 var str: []u8 = try join(debug.global_allocator, ',', [][]const u8{ "a", "b", "c" });
892 errdefer debug.global_allocator.free(str);
893 assert(eql(u8, str, "a,b,c"));
894 debug.global_allocator.free(str);
895
896 str = try join(debug.global_allocator, ',', [][]const u8{"a"});
897 assert(eql(u8, str, "a"));
898 debug.global_allocator.free(str);
899
900 str = try join(debug.global_allocator, ',', [][]const u8{ "a", ([]const u8)(""), "b", ([]const u8)(""), "c" });
901 assert(eql(u8, str, "a,,b,,c"));
902 debug.global_allocator.free(str);
903}
904
905/// Naively combines a series of strings with a separator inline.
906/// Allocates memory for the result, which must be freed by the caller.
907pub fn joinInline(allocator: *Allocator, sep: u8, strings: ...) ![]u8 {
908 comptime assert(strings.len >= 1);
909 var total_strings_len: usize = strings.len; // 1 sep per string
910 {
911 comptime var string_i = 0;
912 inline while (string_i < strings.len) : (string_i += 1) {
913 const arg = ([]const u8)(strings[string_i]);
914 total_strings_len += arg.len;
915 }
916 }
917}
884918
885919/// Naively combines a series of slices with a separator.
886920/// Allocates memory for the result, which must be freed by the caller.
......@@ -897,22 +931,26 @@ pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []cons
897931 const buf = try allocator.alloc(u8, total_len);
898932 errdefer allocator.free(buf);
899933
900 copy(u8, buf, slices[0]);
901 var buf_index: usize = slices[0].len;
902 for (slices[1..]) |slice| {
903 copy(u8, buf[buf_index..], separator);
904 buf_index += separator.len;
905 copy(u8, buf[buf_index..], slice);
906 buf_index += slice.len;
934 var buf_index: usize = 0;
935 comptime var string_i = 0;
936 inline while (true) {
937 const arg = ([]const u8)(strings[string_i]);
938 string_i += 1;
939 copy(u8, buf[buf_index..], arg);
940 buf_index += arg.len;
941 if (string_i >= strings.len) break;
942 buf[buf_index] = sep;
943 buf_index += 1;
907944 }
908945
909946 // No need for shrink since buf is exactly the correct size.
910947 return buf;
911948}
912949
913test "mem.join" {
914 assert(eql(u8, try join(debug.global_allocator, ",", [][]const u8{ "a", "b", "c" }), "a,b,c"));
915 assert(eql(u8, try join(debug.global_allocator, ",", [][]const u8{"a"}), "a"));
950test "mem.joinInline" {
951 assert(eql(u8, try joinInline(debug.global_allocator, ',', "a", "b", "c"), "a,b,c"));
952 assert(eql(u8, try joinInline(debug.global_allocator, ',', "a", "b", ([]const u8)(""), "c"), "a,b,,c"));
953 assert(eql(u8, try joinInline(debug.global_allocator, ',', "a"), "a"));
916954}
917955
918956test "testStringEquality" {