| ... | ... | @@ -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 { |