authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-04 13:29:17-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-04 13:29:17-05:00
logf44ce7836a2f1d29e4f4718d45d6dca3c44ed919
tree14cfe8adf9dfeeb0f8f6a9171604fbad02a2e4ca
parentdfbc063f79dc1358208216b466c1bf8c44baa430
parentff1b2889f3819610aee17ddbecdf716eb573ca2f
signature Commit is signed but in an unrecognized format.

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


2 files changed, 122 insertions(+), 15 deletions(-)

std/mem.zig+114-9
...@@ -692,11 +692,15 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {...@@ -692,11 +692,15 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {
692/// any of the bytes in `split_bytes`.692/// any of the bytes in `split_bytes`.
693/// split(" abc def ghi ", " ")693/// split(" abc def ghi ", " ")
694/// Will return slices for "abc", "def", "ghi", null, in that order.694/// Will return slices for "abc", "def", "ghi", null, in that order.
695/// If `split_bytes` does not exist in buffer,
696/// the iterator will return `buffer`, null, in that order.
695pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {697pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
696 return SplitIterator{698 return SplitIterator{
697 .index = 0,699 .index = 0,
698 .buffer = buffer,700 .buffer = buffer,
699 .split_bytes = split_bytes,701 .split_bytes = split_bytes,
702 .glob = true,
703 .spun = false,
700 };704 };
701}705}
702706
...@@ -706,6 +710,95 @@ test "mem.split" {...@@ -706,6 +710,95 @@ test "mem.split" {
706 assert(eql(u8, it.next().?, "def"));710 assert(eql(u8, it.next().?, "def"));
707 assert(eql(u8, it.next().?, "ghi"));711 assert(eql(u8, it.next().?, "ghi"));
708 assert(it.next() == null);712 assert(it.next() == null);
713
714 it = split("..\\bob", "\\");
715 assert(eql(u8, it.next().?, ".."));
716 assert(eql(u8, "..", "..\\bob"[0..it.index]));
717 assert(eql(u8, it.next().?, "bob"));
718 assert(it.next() == null);
719
720 it = split("//a/b", "/");
721 assert(eql(u8, it.next().?, "a"));
722 assert(eql(u8, it.next().?, "b"));
723 assert(eql(u8, "//a/b", "//a/b"[0..it.index]));
724 assert(it.next() == null);
725
726 it = split("|", "|");
727 assert(it.next() == null);
728
729 it = split("", "|");
730 assert(eql(u8, it.next().?, ""));
731 assert(it.next() == null);
732
733 it = split("hello", "");
734 assert(eql(u8, it.next().?, "hello"));
735 assert(it.next() == null);
736
737 it = split("hello", " ");
738 assert(eql(u8, it.next().?, "hello"));
739 assert(it.next() == null);
740}
741
742test "mem.split (multibyte)" {
743 var it = split("a|b,c/d e", " /,|");
744 assert(eql(u8, it.next().?, "a"));
745 assert(eql(u8, it.next().?, "b"));
746 assert(eql(u8, it.next().?, "c"));
747 assert(eql(u8, it.next().?, "d"));
748 assert(eql(u8, it.next().?, "e"));
749 assert(it.next() == null);
750}
751
752/// Returns an iterator that iterates over the slices of `buffer` that
753/// seperates by bytes in `delimiter`.
754/// separate("abc|def||ghi", "|")
755/// Will return slices for "abc", "def", "", "ghi", null, in that order.
756/// If `delimiter` does not exist in buffer,
757/// the iterator will return `buffer`, null, in that order.
758pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator {
759 return SplitIterator{
760 .index = 0,
761 .buffer = buffer,
762 .split_bytes = delimiter,
763 .glob = false,
764 .spun = false,
765 };
766}
767
768test "mem.separate" {
769 var it = separate("abc|def||ghi", "|");
770 assert(eql(u8, it.next().?, "abc"));
771 assert(eql(u8, it.next().?, "def"));
772 assert(eql(u8, it.next().?, ""));
773 assert(eql(u8, it.next().?, "ghi"));
774 assert(it.next() == null);
775
776 it = separate("", "|");
777 assert(eql(u8, it.next().?, ""));
778 assert(it.next() == null);
779
780 it = separate("|", "|");
781 assert(eql(u8, it.next().?, ""));
782 assert(eql(u8, it.next().?, ""));
783 assert(it.next() == null);
784
785 it = separate("hello", "");
786 assert(eql(u8, it.next().?, "hello"));
787 assert(it.next() == null);
788
789 it = separate("hello", " ");
790 assert(eql(u8, it.next().?, "hello"));
791 assert(it.next() == null);
792}
793
794test "mem.separate (multibyte)" {
795 var it = separate("a|b,c/d e", " /,|");
796 assert(eql(u8, it.next().?, "a"));
797 assert(eql(u8, it.next().?, "b"));
798 assert(eql(u8, it.next().?, "c"));
799 assert(eql(u8, it.next().?, "d"));
800 assert(eql(u8, it.next().?, "e"));
801 assert(it.next() == null);
709}802}
710803
711pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {804pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
...@@ -730,20 +823,32 @@ pub const SplitIterator = struct {...@@ -730,20 +823,32 @@ pub const SplitIterator = struct {
730 buffer: []const u8,823 buffer: []const u8,
731 split_bytes: []const u8,824 split_bytes: []const u8,
732 index: usize,825 index: usize,
826 glob: bool,
827 spun: bool,
733828
829 /// Iterates and returns null or optionally a slice the next split segment
734 pub fn next(self: *SplitIterator) ?[]const u8 {830 pub fn next(self: *SplitIterator) ?[]const u8 {
735 // move to beginning of token831 if (self.spun) {
736 while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}832 if (self.index + 1 > self.buffer.len) return null;
737 const start = self.index;833 self.index += 1;
738 if (start == self.buffer.len) {
739 return null;
740 }834 }
741835
742 // move to end of token836 self.spun = true;
743 while (self.index < self.buffer.len and !self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}837
744 const end = self.index;838 if (self.glob) {
839 while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
840 }
841
842 var cursor = self.index;
843 while (cursor < self.buffer.len and !self.isSplitByte(self.buffer[cursor])) : (cursor += 1) {}
844
845 defer self.index = cursor;
846
847 if (cursor == self.buffer.len) {
848 return if (self.glob and self.index == cursor and self.index > 0) null else self.buffer[self.index..];
849 }
745850
746 return self.buffer[start..end];851 return self.buffer[self.index..cursor];
747 }852 }
748853
749 /// Returns a slice of the remaining bytes. Does not affect iterator state.854 /// Returns a slice of the remaining bytes. Does not affect iterator state.
std/os/path.zig+8-6
...@@ -967,12 +967,14 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)...@@ -967,12 +967,14 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)
967 // shave off the trailing slash967 // shave off the trailing slash
968 result_index -= 1;968 result_index -= 1;
969969
970 var rest_it = mem.split(to_rest, "/\\");970 if (to_rest.len > 0) {
971 while (rest_it.next()) |to_component| {971 var rest_it = mem.split(to_rest, "/\\");
972 result[result_index] = '\\';972 while (rest_it.next()) |to_component| {
973 result_index += 1;973 result[result_index] = '\\';
974 mem.copy(u8, result[result_index..], to_component);974 result_index += 1;
975 result_index += to_component.len;975 mem.copy(u8, result[result_index..], to_component);
976 result_index += to_component.len;
977 }
976 }978 }
977979
978 return result[0..result_index];980 return result[0..result_index];