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`.
/// split(" abc def ghi ", " ")
/// 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 {
return SplitIterator{
.index = 0,
.buffer = buffer,
.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().?, "ghi"));
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 {
@ -730,20 +823,32 @@ pub const SplitIterator = struct {
buffer: []const u8,
split_bytes: []const u8,
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 {
// move to beginning of token
while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
const start = self.index;
if (start == self.buffer.len) {
return null;
if (self.spun) {
if (self.index + 1 > self.buffer.len) return null;
self.index += 1;
}
// move to end of token
while (self.index < self.buffer.len and !self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
const end = self.index;
self.spun = true;
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.

View File

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