@@ -20,7 +20,7 @@ pub const Allocator = struct {
20
20
/// * alignment >= alignment of old_mem.ptr
21
21
///
22
22
/// If `new_byte_count <= old_mem.len`:
23
- /// * this function must return successfully.
23
+ /// * this function must return successfully.
24
24
/// * alignment <= alignment of old_mem.ptr
25
25
///
26
26
/// The returned newly allocated memory is undefined.
@@ -174,6 +174,20 @@ pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T {
174
174
return new_buf ;
175
175
}
176
176
177
+ /// Remove values from the beginning of a slice.
178
+ pub 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.
185
+ pub 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
+
177
191
/// Remove values from the beginning and end of a slice.
178
192
pub fn trim (comptime T : type , slice : []const T , values_to_strip : []const T ) []const T {
179
193
var begin : usize = 0 ;
@@ -184,6 +198,8 @@ pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []co
184
198
}
185
199
186
200
test "mem.trim" {
201
+ assert (eql (u8 , trimLeft (u8 , " foo\n " , " \n " ), "foo\n " ));
202
+ assert (eql (u8 , trimRight (u8 , " foo\n " , " \n " ), " foo" ));
187
203
assert (eql (u8 , trim (u8 , " foo\n " , " \n " ), "foo" ));
188
204
assert (eql (u8 , trim (u8 , "foo" , " \n " ), "foo" ));
189
205
}
@@ -193,6 +209,17 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
193
209
return indexOfScalarPos (T , slice , 0 , value );
194
210
}
195
211
212
+ /// Linear search for the last index of a scalar value inside a slice.
213
+ pub 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
+
196
223
pub fn indexOfScalarPos (comptime T : type , slice : []const T , start_index : usize , value : T ) ? usize {
197
224
var i : usize = start_index ;
198
225
while (i < slice .len ) : (i += 1 ) {
@@ -206,6 +233,18 @@ pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize
206
233
return indexOfAnyPos (T , slice , 0 , values );
207
234
}
208
235
236
+ pub 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
+
209
248
pub fn indexOfAnyPos (comptime T : type , slice : []const T , start_index : usize , values : []const T ) ? usize {
210
249
var i : usize = start_index ;
211
250
while (i < slice .len ) : (i += 1 ) {
@@ -221,6 +260,22 @@ pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
221
260
return indexOfPos (T , haystack , 0 , needle );
222
261
}
223
262
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?
266
+ pub 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
+
224
279
// TODO boyer-moore algorithm
225
280
pub fn indexOfPos (comptime T : type , haystack : []const T , start_index : usize , needle : []const T ) ? usize {
226
281
if (needle .len > haystack .len )
@@ -237,9 +292,19 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee
237
292
238
293
test "mem.indexOf" {
239
294
assert (?? indexOf (u8 , "one two three four" , "four" ) == 14 );
295
+ assert (?? lastIndexOf (u8 , "one two three two four" , "two" ) == 14 );
240
296
assert (indexOf (u8 , "one two three four" , "gour" ) == null );
297
+ assert (lastIndexOf (u8 , "one two three four" , "gour" ) == null );
241
298
assert (?? indexOf (u8 , "foo" , "foo" ) == 0 );
299
+ assert (?? lastIndexOf (u8 , "foo" , "foo" ) == 0 );
242
300
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 );
243
308
}
244
309
245
310
/// 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
359
424
return if (needle .len > haystack .len ) false else eql (T , haystack [0 .. needle .len ], needle );
360
425
}
361
426
427
+ test "mem.startsWith" {
428
+ assert (startsWith (u8 , "Bob" , "Bo" ));
429
+ assert (! startsWith (u8 , "Needle in haystack" , "haystack" ));
430
+ }
431
+
432
+ pub 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
+
437
+ test "mem.endsWith" {
438
+ assert (endsWith (u8 , "Needle in haystack" , "haystack" ));
439
+ assert (! endsWith (u8 , "Bob" , "Bo" ));
440
+ }
441
+
362
442
pub const SplitIterator = struct {
363
443
buffer : []const u8 ,
364
- split_bytes : []const u8 ,
444
+ split_bytes : []const u8 ,
365
445
index : usize ,
366
446
367
447
pub fn next (self : & SplitIterator ) ? []const u8 {
0 commit comments