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

master
Andrew Kelley 2019-02-04 13:29:17 -05:00
commit f44ce7836a
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 122 additions and 15 deletions

View File

@ -692,11 +692,15 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {
/// any of the bytes in `split_bytes`. /// any of the bytes in `split_bytes`.
/// split(" abc def ghi ", " ") /// split(" abc def ghi ", " ")
/// Will return slices for "abc", "def", "ghi", null, in that order. /// Will return slices for "abc", "def", "ghi", null, in that order.
/// If `split_bytes` does not exist in buffer,
/// the iterator will return `buffer`, null, in that order.
pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator { pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {
return SplitIterator{ return SplitIterator{
.index = 0, .index = 0,
.buffer = buffer, .buffer = buffer,
.split_bytes = split_bytes, .split_bytes = split_bytes,
.glob = true,
.spun = false,
}; };
} }
@ -706,6 +710,95 @@ test "mem.split" {
assert(eql(u8, it.next().?, "def")); assert(eql(u8, it.next().?, "def"));
assert(eql(u8, it.next().?, "ghi")); assert(eql(u8, it.next().?, "ghi"));
assert(it.next() == null); assert(it.next() == null);
it = split("..\\bob", "\\");
assert(eql(u8, it.next().?, ".."));
assert(eql(u8, "..", "..\\bob"[0..it.index]));
assert(eql(u8, it.next().?, "bob"));
assert(it.next() == null);
it = split("//a/b", "/");
assert(eql(u8, it.next().?, "a"));
assert(eql(u8, it.next().?, "b"));
assert(eql(u8, "//a/b", "//a/b"[0..it.index]));
assert(it.next() == null);
it = split("|", "|");
assert(it.next() == null);
it = split("", "|");
assert(eql(u8, it.next().?, ""));
assert(it.next() == null);
it = split("hello", "");
assert(eql(u8, it.next().?, "hello"));
assert(it.next() == null);
it = split("hello", " ");
assert(eql(u8, it.next().?, "hello"));
assert(it.next() == null);
}
test "mem.split (multibyte)" {
var it = split("a|b,c/d e", " /,|");
assert(eql(u8, it.next().?, "a"));
assert(eql(u8, it.next().?, "b"));
assert(eql(u8, it.next().?, "c"));
assert(eql(u8, it.next().?, "d"));
assert(eql(u8, it.next().?, "e"));
assert(it.next() == null);
}
/// Returns an iterator that iterates over the slices of `buffer` that
/// seperates by bytes in `delimiter`.
/// separate("abc|def||ghi", "|")
/// Will return slices for "abc", "def", "", "ghi", null, in that order.
/// If `delimiter` does not exist in buffer,
/// the iterator will return `buffer`, null, in that order.
pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator {
return SplitIterator{
.index = 0,
.buffer = buffer,
.split_bytes = delimiter,
.glob = false,
.spun = false,
};
}
test "mem.separate" {
var it = separate("abc|def||ghi", "|");
assert(eql(u8, it.next().?, "abc"));
assert(eql(u8, it.next().?, "def"));
assert(eql(u8, it.next().?, ""));
assert(eql(u8, it.next().?, "ghi"));
assert(it.next() == null);
it = separate("", "|");
assert(eql(u8, it.next().?, ""));
assert(it.next() == null);
it = separate("|", "|");
assert(eql(u8, it.next().?, ""));
assert(eql(u8, it.next().?, ""));
assert(it.next() == null);
it = separate("hello", "");
assert(eql(u8, it.next().?, "hello"));
assert(it.next() == null);
it = separate("hello", " ");
assert(eql(u8, it.next().?, "hello"));
assert(it.next() == null);
}
test "mem.separate (multibyte)" {
var it = separate("a|b,c/d e", " /,|");
assert(eql(u8, it.next().?, "a"));
assert(eql(u8, it.next().?, "b"));
assert(eql(u8, it.next().?, "c"));
assert(eql(u8, it.next().?, "d"));
assert(eql(u8, it.next().?, "e"));
assert(it.next() == null);
} }
pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
@ -730,20 +823,32 @@ pub const SplitIterator = struct {
buffer: []const u8, buffer: []const u8,
split_bytes: []const u8, split_bytes: []const u8,
index: usize, index: usize,
glob: bool,
spun: bool,
/// Iterates and returns null or optionally a slice the next split segment
pub fn next(self: *SplitIterator) ?[]const u8 { pub fn next(self: *SplitIterator) ?[]const u8 {
// move to beginning of token if (self.spun) {
while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} if (self.index + 1 > self.buffer.len) return null;
const start = self.index; self.index += 1;
if (start == self.buffer.len) {
return null;
} }
// move to end of token self.spun = true;
while (self.index < self.buffer.len and !self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
const end = self.index;
return self.buffer[start..end]; if (self.glob) {
while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
}
var cursor = self.index;
while (cursor < self.buffer.len and !self.isSplitByte(self.buffer[cursor])) : (cursor += 1) {}
defer self.index = cursor;
if (cursor == self.buffer.len) {
return if (self.glob and self.index == cursor and self.index > 0) null else self.buffer[self.index..];
}
return self.buffer[self.index..cursor];
} }
/// Returns a slice of the remaining bytes. Does not affect iterator state. /// Returns a slice of the remaining bytes. Does not affect iterator state.

View File

@ -967,12 +967,14 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)
// shave off the trailing slash // shave off the trailing slash
result_index -= 1; result_index -= 1;
var rest_it = mem.split(to_rest, "/\\"); if (to_rest.len > 0) {
while (rest_it.next()) |to_component| { var rest_it = mem.split(to_rest, "/\\");
result[result_index] = '\\'; while (rest_it.next()) |to_component| {
result_index += 1; result[result_index] = '\\';
mem.copy(u8, result[result_index..], to_component); result_index += 1;
result_index += to_component.len; mem.copy(u8, result[result_index..], to_component);
result_index += to_component.len;
}
} }
return result[0..result_index]; return result[0..result_index];