authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-24 20:50:21-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-24 20:53:36-04:00
log13076d5f225cf8ca2cddf1b67478baebabe8b13f
treeda52b17d27dd6a70a758ea5d1064da15bd72dcdb
parent0501e066b51b659371739008c20e80642532497a

std.mem: add more slice manipulation functions

* add std.mem.trimLeft * add std.mem.trimRight * add std.mem.trimRight * add std.mem.lastIndexOfScalar * add std.mem.lastIndexOfAny * add std.mem.lastIndexOf * add std.mem.endsWith closes #944 Thanks Braedon Wooding for the original PR

1 files changed, 82 insertions(+), 2 deletions(-)

std/mem.zig+82-2
......@@ -20,7 +20,7 @@ pub const Allocator = struct {
2020 /// * alignment >= alignment of old_mem.ptr
2121 ///
2222 /// If `new_byte_count <= old_mem.len`:
23 /// * this function must return successfully.
23 /// * this function must return successfully.
2424 /// * alignment <= alignment of old_mem.ptr
2525 ///
2626 /// The returned newly allocated memory is undefined.
......@@ -174,6 +174,20 @@ pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T {
174174 return new_buf;
175175}
176176
177/// Remove values from the beginning of a slice.
178pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
179 var begin: usize = 0;
180 while (begin < slice.len and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
181 return slice[begin..];
182}
183
184/// Remove values from the end of a slice.
185pub fn trimRight(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
186 var end: usize = slice.len;
187 while (end > 0 and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
188 return slice[0..end];
189}
190
177191/// Remove values from the beginning and end of a slice.
178192pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
179193 var begin: usize = 0;
......@@ -184,6 +198,8 @@ pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []co
184198}
185199
186200test "mem.trim" {
201 assert(eql(u8, trimLeft(u8, " foo\n ", " \n"), "foo\n "));
202 assert(eql(u8, trimRight(u8, " foo\n ", " \n"), " foo"));
187203 assert(eql(u8, trim(u8, " foo\n ", " \n"), "foo"));
188204 assert(eql(u8, trim(u8, "foo", " \n"), "foo"));
189205}
......@@ -193,6 +209,17 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
193209 return indexOfScalarPos(T, slice, 0, value);
194210}
195211
212/// Linear search for the last index of a scalar value inside a slice.
213pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
214 var i: usize = slice.len;
215 while (i != 0) {
216 i -= 1;
217 if (slice[i] == value)
218 return i;
219 }
220 return null;
221}
222
196223pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
197224 var i: usize = start_index;
198225 while (i < slice.len) : (i += 1) {
......@@ -206,6 +233,18 @@ pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize
206233 return indexOfAnyPos(T, slice, 0, values);
207234}
208235
236pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {
237 var i: usize = slice.len;
238 while (i != 0) {
239 i -= 1;
240 for (values) |value| {
241 if (slice[i] == value)
242 return i;
243 }
244 }
245 return null;
246}
247
209248pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
210249 var i: usize = start_index;
211250 while (i < slice.len) : (i += 1) {
......@@ -221,6 +260,22 @@ pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
221260 return indexOfPos(T, haystack, 0, needle);
222261}
223262
263/// Find the index in a slice of a sub-slice, searching from the end backwards.
264/// To start looking at a different index, slice the haystack first.
265/// TODO is there even a better algorithm for this?
266pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
267 if (needle.len > haystack.len)
268 return null;
269
270 var i: usize = haystack.len - needle.len;
271 while (true) : (i -= 1) {
272 if (mem.eql(T, haystack[i..i+needle.len], needle))
273 return i;
274 if (i == 0)
275 return null;
276 }
277}
278
224279// TODO boyer-moore algorithm
225280pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
226281 if (needle.len > haystack.len)
......@@ -237,9 +292,19 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee
237292
238293test "mem.indexOf" {
239294 assert(??indexOf(u8, "one two three four", "four") == 14);
295 assert(??lastIndexOf(u8, "one two three two four", "two") == 14);
240296 assert(indexOf(u8, "one two three four", "gour") == null);
297 assert(lastIndexOf(u8, "one two three four", "gour") == null);
241298 assert(??indexOf(u8, "foo", "foo") == 0);
299 assert(??lastIndexOf(u8, "foo", "foo") == 0);
242300 assert(indexOf(u8, "foo", "fool") == null);
301 assert(lastIndexOf(u8, "foo", "lfoo") == null);
302 assert(lastIndexOf(u8, "foo", "fool") == null);
303
304 assert(??indexOf(u8, "foo foo", "foo") == 0);
305 assert(??lastIndexOf(u8, "foo foo", "foo") == 4);
306 assert(??lastIndexOfAny(u8, "boo, cat", "abo") == 6);
307 assert(??lastIndexOfScalar(u8, "boo", 'o') == 2);
243308}
244309
245310/// Reads an integer from memory with size equal to bytes.len.
......@@ -359,9 +424,24 @@ pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool
359424 return if (needle.len > haystack.len) false else eql(T, haystack[0 .. needle.len], needle);
360425}
361426
427test "mem.startsWith" {
428 assert(startsWith(u8, "Bob", "Bo"));
429 assert(!startsWith(u8, "Needle in haystack", "haystack"));
430}
431
432pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
433 return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len ..], needle);
434}
435
436
437test "mem.endsWith" {
438 assert(endsWith(u8, "Needle in haystack", "haystack"));
439 assert(!endsWith(u8, "Bob", "Bo"));
440}
441
362442pub const SplitIterator = struct {
363443 buffer: []const u8,
364 split_bytes: []const u8,
444 split_bytes: []const u8,
365445 index: usize,
366446
367447 pub fn next(self: &SplitIterator) ?[]const u8 {