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 {...@@ -856,31 +856,65 @@ pub const TokenIterator = struct {
856 }856 }
857};857};
858858
859pub const SplitIterator = struct {859/// Naively combines a series of strings with a separator.
860 buffer: []const u8,860/// Allocates memory for the result, which must be freed by the caller.
861 index: ?usize,861pub fn join(allocator: *Allocator, sep: u8, strings: []const []const u8) ![]u8 {
862 delimiter: []const u8,862 assert(strings.len >= 1);
863863 var total_strings_len: usize = strings.len; // 1 sep per string
864 /// Returns a slice of the next field, or null if splitting is complete.864 {
865 pub fn next(self: *SplitIterator) ?[]const u8 {865 var string_i: usize = 0;
866 const start = self.index orelse return null;866 while (string_i < strings.len) : (string_i += 1) {
867 const end = if (indexOfPos(u8, self.buffer, start, self.delimiter)) |delim_start| blk: {867 const arg = ([]const u8)(strings[string_i]);
868 self.index = delim_start + self.delimiter.len;868 total_strings_len += arg.len;
869 break :blk delim_start;869 }
870 } else blk: {
871 self.index = null;
872 break :blk self.buffer.len;
873 };
874 return self.buffer[start..end];
875 }870 }
876871
877 /// Returns a slice of the remaining bytes. Does not affect iterator state.872 const buf = try allocator.alloc(u8, total_strings_len);
878 pub fn rest(self: SplitIterator) []const u8 {873 errdefer allocator.free(buf);
879 const end = self.buffer.len;874
880 const start = self.index orelse end;875 var buf_index: usize = 0;
881 return self.buffer[start..end];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;
882 }885 }
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
885/// Naively combines a series of slices with a separator.919/// Naively combines a series of slices with a separator.
886/// Allocates memory for the result, which must be freed by the caller.920/// 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...@@ -897,22 +931,26 @@ pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []cons
897 const buf = try allocator.alloc(u8, total_len);931 const buf = try allocator.alloc(u8, total_len);
898 errdefer allocator.free(buf);932 errdefer allocator.free(buf);
899933
900 copy(u8, buf, slices[0]);934 var buf_index: usize = 0;
901 var buf_index: usize = slices[0].len;935 comptime var string_i = 0;
902 for (slices[1..]) |slice| {936 inline while (true) {
903 copy(u8, buf[buf_index..], separator);937 const arg = ([]const u8)(strings[string_i]);
904 buf_index += separator.len;938 string_i += 1;
905 copy(u8, buf[buf_index..], slice);939 copy(u8, buf[buf_index..], arg);
906 buf_index += slice.len;940 buf_index += arg.len;
941 if (string_i >= strings.len) break;
942 buf[buf_index] = sep;
943 buf_index += 1;
907 }944 }
908945
909 // No need for shrink since buf is exactly the correct size.946 // No need for shrink since buf is exactly the correct size.
910 return buf;947 return buf;
911}948}
912949
913test "mem.join" {950test "mem.joinInline" {
914 assert(eql(u8, try join(debug.global_allocator, ",", [][]const u8{ "a", "b", "c" }), "a,b,c"));951 assert(eql(u8, try joinInline(debug.global_allocator, ',', "a", "b", "c"), "a,b,c"));
915 assert(eql(u8, try join(debug.global_allocator, ",", [][]const u8{"a"}), "a"));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"));
916}954}
917955
918test "testStringEquality" {956test "testStringEquality" {