| ... | ... | @@ -681,7 +681,53 @@ pub const SplitIterator = struct { |
| 681 | 681 | |
| 682 | 682 | /// Naively combines a series of strings with a separator. |
| 683 | 683 | /// Allocates memory for the result, which must be freed by the caller. |
| 684 | | pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { |
| 684 | pub fn join(allocator: *Allocator, sep: u8, strings: []const []const u8) ![]u8 { |
| 685 | assert(strings.len >= 1); |
| 686 | var total_strings_len: usize = strings.len; // 1 sep per string |
| 687 | { |
| 688 | var string_i: usize = 0; |
| 689 | while (string_i < strings.len) : (string_i += 1) { |
| 690 | const arg = ([]const u8)(strings[string_i]); |
| 691 | total_strings_len += arg.len; |
| 692 | } |
| 693 | } |
| 694 | |
| 695 | const buf = try allocator.alloc(u8, total_strings_len); |
| 696 | errdefer allocator.free(buf); |
| 697 | |
| 698 | var buf_index: usize = 0; |
| 699 | var string_i: usize = 0; |
| 700 | while (true) { |
| 701 | const arg = ([]const u8)(strings[string_i]); |
| 702 | string_i += 1; |
| 703 | copy(u8, buf[buf_index..], arg); |
| 704 | buf_index += arg.len; |
| 705 | if (string_i >= strings.len) break; |
| 706 | buf[buf_index] = sep; |
| 707 | buf_index += 1; |
| 708 | } |
| 709 | |
| 710 | return allocator.shrink(u8, buf, buf_index); |
| 711 | } |
| 712 | |
| 713 | test "mem.join" { |
| 714 | var str: []u8 = try join(debug.global_allocator, ',', [][]const u8{"a", "b", "c"} ); |
| 715 | errdefer debug.global_allocator.free( str ); |
| 716 | assert(eql(u8, str, "a,b,c")); |
| 717 | debug.global_allocator.free( str ); |
| 718 | |
| 719 | str = try join(debug.global_allocator, ',', [][]const u8{"a"}); |
| 720 | assert(eql(u8, str, "a")); |
| 721 | debug.global_allocator.free( str ); |
| 722 | |
| 723 | str = try join(debug.global_allocator, ',', [][]const u8{"a", ([]const u8)(""), "b", ([]const u8)(""), "c"}); |
| 724 | assert(eql(u8, str, "a,,b,,c")); |
| 725 | debug.global_allocator.free( str ); |
| 726 | } |
| 727 | |
| 728 | /// Naively combines a series of strings with a separator inline. |
| 729 | /// Allocates memory for the result, which must be freed by the caller. |
| 730 | pub fn joinInline(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { |
| 685 | 731 | comptime assert(strings.len >= 1); |
| 686 | 732 | var total_strings_len: usize = strings.len; // 1 sep per string |
| 687 | 733 | { |
| ... | ... | @@ -703,18 +749,17 @@ pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { |
| 703 | 749 | copy(u8, buf[buf_index..], arg); |
| 704 | 750 | buf_index += arg.len; |
| 705 | 751 | if (string_i >= strings.len) break; |
| 706 | | if (buf[buf_index - 1] != sep) { |
| 707 | | buf[buf_index] = sep; |
| 708 | | buf_index += 1; |
| 709 | | } |
| 752 | buf[buf_index] = sep; |
| 753 | buf_index += 1; |
| 710 | 754 | } |
| 711 | 755 | |
| 712 | 756 | return allocator.shrink(u8, buf, buf_index); |
| 713 | 757 | } |
| 714 | 758 | |
| 715 | | test "mem.join" { |
| 716 | | assert(eql(u8, try join(debug.global_allocator, ',', "a", "b", "c"), "a,b,c")); |
| 717 | | assert(eql(u8, try join(debug.global_allocator, ',', "a"), "a")); |
| 759 | test "mem.joinInline" { |
| 760 | assert(eql(u8, try joinInline(debug.global_allocator, ',', "a", "b", "c"), "a,b,c")); |
| 761 | assert(eql(u8, try joinInline(debug.global_allocator, ',', "a", "b", ([]const u8)(""), "c"), "a,b,,c")); |
| 762 | assert(eql(u8, try joinInline(debug.global_allocator, ',', "a"), "a")); |
| 718 | 763 | } |
| 719 | 764 | |
| 720 | 765 | test "testStringEquality" { |