| ... | @@ -607,11 +607,15 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { | ... | @@ -607,11 +607,15 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { |
| 607 | /// any of the bytes in `split_bytes`. | 607 | /// any of the bytes in `split_bytes`. |
| 608 | /// split(" abc def ghi ", " ") | 608 | /// split(" abc def ghi ", " ") |
| 609 | /// Will return slices for "abc", "def", "ghi", null, in that order. | 609 | /// Will return slices for "abc", "def", "ghi", null, in that order. |
| | 610 | /// If `split_bytes` does not exist in buffer, |
| | 611 | /// the iterator will return `buffer`, null, in that order. |
| 610 | pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator { | 612 | pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator { |
| 611 | return SplitIterator{ | 613 | return SplitIterator{ |
| 612 | .index = 0, | 614 | .index = 0, |
| 613 | .buffer = buffer, | 615 | .buffer = buffer, |
| 614 | .split_bytes = split_bytes, | 616 | .split_bytes = split_bytes, |
| | 617 | .glob = true, |
| | 618 | .spun = false, |
| 615 | }; | 619 | }; |
| 616 | } | 620 | } |
| 617 | | 621 | |
| ... | @@ -621,6 +625,76 @@ test "mem.split" { | ... | @@ -621,6 +625,76 @@ test "mem.split" { |
| 621 | assert(eql(u8, it.next().?, "def")); | 625 | assert(eql(u8, it.next().?, "def")); |
| 622 | assert(eql(u8, it.next().?, "ghi")); | 626 | assert(eql(u8, it.next().?, "ghi")); |
| 623 | assert(it.next() == null); | 627 | assert(it.next() == null); |
| | 628 | |
| | 629 | it = split("..\\bob", "\\"); |
| | 630 | assert(eql(u8, it.next().?, "..")); |
| | 631 | assert(eql(u8, "..", "..\\bob"[0..it.index])); |
| | 632 | assert(eql(u8, it.next().?, "bob")); |
| | 633 | assert(it.next() == null); |
| | 634 | |
| | 635 | it = split("//a/b", "/"); |
| | 636 | assert(eql(u8, it.next().?, "a")); |
| | 637 | assert(eql(u8, it.next().?, "b")); |
| | 638 | assert(eql(u8, "//a/b", "//a/b"[0..it.index])); |
| | 639 | assert(it.next() == null); |
| | 640 | |
| | 641 | it = split("|", "|"); |
| | 642 | assert(it.next() == null); |
| | 643 | |
| | 644 | it = split("", "|"); |
| | 645 | assert(eql(u8, it.next().?, "")); |
| | 646 | assert(it.next() == null); |
| | 647 | |
| | 648 | it = split("hello", ""); |
| | 649 | assert(eql(u8, it.next().?, "hello")); |
| | 650 | assert(it.next() == null); |
| | 651 | |
| | 652 | it = split("hello", " "); |
| | 653 | assert(eql(u8, it.next().?, "hello")); |
| | 654 | assert(it.next() == null); |
| | 655 | } |
| | 656 | |
| | 657 | /// Returns an iterator that iterates over the slices of `buffer` that |
| | 658 | /// seperates by bytes in `delimiter`. |
| | 659 | /// separate("abc|def||ghi", "|") |
| | 660 | /// Will return slices for "abc", "def", "", "ghi", null, in that order. |
| | 661 | /// If `delimiter` does not exist in buffer, |
| | 662 | /// the iterator will return `buffer`, null, in that order. |
| | 663 | pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator { |
| | 664 | return SplitIterator{ |
| | 665 | .index = 0, |
| | 666 | .buffer = buffer, |
| | 667 | .split_bytes = delimiter, |
| | 668 | .glob = false, |
| | 669 | .spun = false, |
| | 670 | }; |
| | 671 | } |
| | 672 | |
| | 673 | test "mem.separate" { |
| | 674 | var it = separate("abc|def||ghi", "|"); |
| | 675 | assert(eql(u8, it.next().?, "abc")); |
| | 676 | assert(eql(u8, it.next().?, "def")); |
| | 677 | assert(eql(u8, it.next().?, "")); |
| | 678 | assert(eql(u8, it.next().?, "ghi")); |
| | 679 | assert(it.next() == null); |
| | 680 | |
| | 681 | it = separate("", "|"); |
| | 682 | assert(eql(u8, it.next().?, "")); |
| | 683 | assert(it.next() == null); |
| | 684 | |
| | 685 | it = separate("|", "|"); |
| | 686 | assert(eql(u8, it.next().?, "")); |
| | 687 | assert(eql(u8, it.next().?, "")); |
| | 688 | assert(it.next() == null); |
| | 689 | |
| | 690 | it = separate("hello", ""); |
| | 691 | assert(eql(u8, it.next().?, "hello")); |
| | 692 | assert(it.next() == null); |
| | 693 | |
| | 694 | it = separate("hello", " "); |
| | 695 | assert(eql(u8, it.next().?, "hello")); |
| | 696 | assert(it.next() == null); |
| | 697 | |
| 624 | } | 698 | } |
| 625 | | 699 | |
| 626 | pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { | 700 | pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { |
| ... | @@ -645,20 +719,32 @@ pub const SplitIterator = struct { | ... | @@ -645,20 +719,32 @@ pub const SplitIterator = struct { |
| 645 | buffer: []const u8, | 719 | buffer: []const u8, |
| 646 | split_bytes: []const u8, | 720 | split_bytes: []const u8, |
| 647 | index: usize, | 721 | index: usize, |
| | 722 | glob: bool, |
| | 723 | spun: bool, |
| 648 | | 724 | |
| | 725 | /// Iterates and returns null or optionally a slice the next split segment |
| 649 | pub fn next(self: *SplitIterator) ?[]const u8 { | 726 | pub fn next(self: *SplitIterator) ?[]const u8 { |
| 650 | // move to beginning of token | 727 | if (self.spun) { |
| 651 | while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} | 728 | if (self.index + 1 > self.buffer.len) return null; |
| 652 | const start = self.index; | 729 | self.index += 1; |
| 653 | if (start == self.buffer.len) { | 730 | } |
| 654 | return null; | 731 | |
| | 732 | self.spun = true; |
| | 733 | |
| | 734 | if (self.glob) { |
| | 735 | while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} |
| 655 | } | 736 | } |
| 656 | | 737 | |
| 657 | // move to end of token | 738 | var cursor = self.index; |
| 658 | while (self.index < self.buffer.len and !self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} | 739 | while (cursor < self.buffer.len and !self.isSplitByte(self.buffer[cursor])) : (cursor += 1) {} |
| 659 | const end = self.index; | 740 | |
| | 741 | defer self.index = cursor; |
| | 742 | |
| | 743 | if (cursor == self.buffer.len) { |
| | 744 | return if (self.glob and self.index == cursor and self.index > 0) null else self.buffer[self.index..]; |
| | 745 | } |
| 660 | | 746 | |
| 661 | return self.buffer[start..end]; | 747 | return self.buffer[self.index..cursor]; |
| 662 | } | 748 | } |
| 663 | | 749 | |
| 664 | /// Returns a slice of the remaining bytes. Does not affect iterator state. | 750 | /// Returns a slice of the remaining bytes. Does not affect iterator state. |