authorgravatar for kris.tate+github@gmail.comkristopher tate <kris.tate+github@gmail.com> 2018-11-26 01:09:12+09:00
committergravatar for kris.tate+github@gmail.comkristopher tate <kris.tate+github@gmail.com> 2018-11-26 02:02:17+09:00
log0f7de58b642539ad6a71368940f43f59a41e71b2
tree085adcf08f542bd6937e80545b8910fb1fa23511
parentf6cd02be6551f3ca702b76b7ca2ab7567effe680
signature Commit is signed but in an unrecognized format.

std.mem: add new separate method and rework SplitIterator;


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

std/mem.zig+95-9
......@@ -607,11 +607,15 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {
607607/// any of the bytes in `split_bytes`.
608608/// split(" abc def ghi ", " ")
609609/// Will return slices for "abc", "def", "ghi", null, in that order.
610/// If `split_bytes` does not exist in buffer,
611/// the iterator will return `buffer`, null, in that order.
610612pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
611613 return SplitIterator{
612614 .index = 0,
613615 .buffer = buffer,
614616 .split_bytes = split_bytes,
617 .glob = true,
618 .spun = false,
615619 };
616620}
617621
......@@ -621,6 +625,76 @@ test "mem.split" {
621625 assert(eql(u8, it.next().?, "def"));
622626 assert(eql(u8, it.next().?, "ghi"));
623627 assert(it.next() == null);
628
629 it = split("..\\bob", "\\");
630 assert(eql(u8, it.next().?, ".."));
631 assert(eql(u8, "..", "..\\bob"[0..it.index]));
632 assert(eql(u8, it.next().?, "bob"));
633 assert(it.next() == null);
634
635 it = split("//a/b", "/");
636 assert(eql(u8, it.next().?, "a"));
637 assert(eql(u8, it.next().?, "b"));
638 assert(eql(u8, "//a/b", "//a/b"[0..it.index]));
639 assert(it.next() == null);
640
641 it = split("|", "|");
642 assert(it.next() == null);
643
644 it = split("", "|");
645 assert(eql(u8, it.next().?, ""));
646 assert(it.next() == null);
647
648 it = split("hello", "");
649 assert(eql(u8, it.next().?, "hello"));
650 assert(it.next() == null);
651
652 it = split("hello", " ");
653 assert(eql(u8, it.next().?, "hello"));
654 assert(it.next() == null);
655}
656
657/// Returns an iterator that iterates over the slices of `buffer` that
658/// seperates by bytes in `delimiter`.
659/// separate("abc|def||ghi", "|")
660/// Will return slices for "abc", "def", "", "ghi", null, in that order.
661/// If `delimiter` does not exist in buffer,
662/// the iterator will return `buffer`, null, in that order.
663pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator {
664 return SplitIterator{
665 .index = 0,
666 .buffer = buffer,
667 .split_bytes = delimiter,
668 .glob = false,
669 .spun = false,
670 };
671}
672
673test "mem.separate" {
674 var it = separate("abc|def||ghi", "|");
675 assert(eql(u8, it.next().?, "abc"));
676 assert(eql(u8, it.next().?, "def"));
677 assert(eql(u8, it.next().?, ""));
678 assert(eql(u8, it.next().?, "ghi"));
679 assert(it.next() == null);
680
681 it = separate("", "|");
682 assert(eql(u8, it.next().?, ""));
683 assert(it.next() == null);
684
685 it = separate("|", "|");
686 assert(eql(u8, it.next().?, ""));
687 assert(eql(u8, it.next().?, ""));
688 assert(it.next() == null);
689
690 it = separate("hello", "");
691 assert(eql(u8, it.next().?, "hello"));
692 assert(it.next() == null);
693
694 it = separate("hello", " ");
695 assert(eql(u8, it.next().?, "hello"));
696 assert(it.next() == null);
697
624698}
625699
626700pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
......@@ -645,20 +719,32 @@ pub const SplitIterator = struct {
645719 buffer: []const u8,
646720 split_bytes: []const u8,
647721 index: usize,
722 glob: bool,
723 spun: bool,
648724
725 /// Iterates and returns null or optionally a slice the next split segment
649726 pub fn next(self: *SplitIterator) ?[]const u8 {
650 // move to beginning of token
651 while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
652 const start = self.index;
653 if (start == self.buffer.len) {
654 return null;
727 if (self.spun) {
728 if (self.index + 1 > self.buffer.len) return null;
729 self.index += 1;
730 }
731
732 self.spun = true;
733
734 if (self.glob) {
735 while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
655736 }
656737
657 // move to end of token
658 while (self.index < self.buffer.len and !self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
659 const end = self.index;
738 var cursor = self.index;
739 while (cursor < self.buffer.len and !self.isSplitByte(self.buffer[cursor])) : (cursor += 1) {}
740
741 defer self.index = cursor;
742
743 if (cursor == self.buffer.len) {
744 return if (self.glob and self.index == cursor and self.index > 0) null else self.buffer[self.index..];
745 }
660746
661 return self.buffer[start..end];
747 return self.buffer[self.index..cursor];
662748 }
663749
664750 /// 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)
967967 // shave off the trailing slash
968968 result_index -= 1;
969969
970 var rest_it = mem.split(to_rest, "/\\");
971 while (rest_it.next()) |to_component| {
972 result[result_index] = '\\';
973 result_index += 1;
974 mem.copy(u8, result[result_index..], to_component);
975 result_index += to_component.len;
970 if (to_rest.len > 0) {
971 var rest_it = mem.split(to_rest, "/\\");
972 while (rest_it.next()) |to_component| {
973 result[result_index] = '\\';
974 result_index += 1;
975 mem.copy(u8, result[result_index..], to_component);
976 result_index += to_component.len;
977 }
976978 }
977979
978980 return result[0..result_index];