| ... | ... | @@ -1910,72 +1910,117 @@ test "byteSwapAllFields" { |
| 1910 | 1910 | }, s); |
| 1911 | 1911 | } |
| 1912 | 1912 | |
| 1913 | /// Deprecated: use `tokenizeAny`, `tokenizeFull`, or `tokenizeScalar` |
| 1914 | pub const tokenize = tokenizeAny; |
| 1915 | |
| 1913 | 1916 | /// Returns an iterator that iterates over the slices of `buffer` that are not |
| 1914 | | /// any of the bytes in `delimiter_bytes`. |
| 1917 | /// any of the items in `delimiters`. |
| 1915 | 1918 | /// |
| 1916 | | /// `tokenize(u8, " abc def ghi ", " ")` will return slices |
| 1919 | /// `tokenizeAny(u8, " abc|def || ghi ", " |")` will return slices |
| 1917 | 1920 | /// for "abc", "def", "ghi", null, in that order. |
| 1918 | 1921 | /// |
| 1919 | 1922 | /// If `buffer` is empty, the iterator will return null. |
| 1920 | | /// If `delimiter_bytes` does not exist in buffer, |
| 1923 | /// If none of `delimiters` exist in buffer, |
| 1924 | /// the iterator will return `buffer`, null, in that order. |
| 1925 | /// |
| 1926 | /// See also: `tokenizeFull`, `tokenizeScalar`, |
| 1927 | /// `splitFull`,`splitAny`, `splitScalar`, |
| 1928 | /// `splitBackwardsFull`, `splitBackwardsAny`, and `splitBackwardsScalar` |
| 1929 | pub fn tokenizeAny(comptime T: type, buffer: []const T, delimiters: []const T) TokenIterator(T, .any) { |
| 1930 | return .{ |
| 1931 | .index = 0, |
| 1932 | .buffer = buffer, |
| 1933 | .delimiter = delimiters, |
| 1934 | }; |
| 1935 | } |
| 1936 | |
| 1937 | /// Returns an iterator that iterates over the slices of `buffer` that are not |
| 1938 | /// the sequence in `delimiter`. |
| 1939 | /// |
| 1940 | /// `tokenizeFull(u8, "<>abc><def<><>ghi", "<>")` will return slices |
| 1941 | /// for "abc><def", "ghi", null, in that order. |
| 1942 | /// |
| 1943 | /// If `buffer` is empty, the iterator will return null. |
| 1944 | /// If `delimiter` does not exist in buffer, |
| 1921 | 1945 | /// the iterator will return `buffer`, null, in that order. |
| 1946 | /// The delimiter length must not be zero. |
| 1922 | 1947 | /// |
| 1923 | | /// See also: `split` and `splitBackwards`. |
| 1924 | | pub fn tokenize(comptime T: type, buffer: []const T, delimiter_bytes: []const T) TokenIterator(T) { |
| 1948 | /// See also: `tokenizeAny`, `tokenizeScalar`, |
| 1949 | /// `splitFull`,`splitAny`, and `splitScalar` |
| 1950 | /// `splitBackwardsFull`, `splitBackwardsAny`, and `splitBackwardsScalar` |
| 1951 | pub fn tokenizeFull(comptime T: type, buffer: []const T, delimiter: []const T) TokenIterator(T, .full) { |
| 1952 | assert(delimiter.len != 0); |
| 1925 | 1953 | return .{ |
| 1926 | 1954 | .index = 0, |
| 1927 | 1955 | .buffer = buffer, |
| 1928 | | .delimiter_bytes = delimiter_bytes, |
| 1956 | .delimiter = delimiter, |
| 1929 | 1957 | }; |
| 1930 | 1958 | } |
| 1931 | 1959 | |
| 1932 | | test "tokenize" { |
| 1933 | | var it = tokenize(u8, " abc def ghi ", " "); |
| 1960 | /// Returns an iterator that iterates over the slices of `buffer` that are not |
| 1961 | /// `delimiter`. |
| 1962 | /// |
| 1963 | /// `tokenizeScalar(u8, " abc def ghi ", ' ')` will return slices |
| 1964 | /// for "abc", "def", "ghi", null, in that order. |
| 1965 | /// |
| 1966 | /// If `buffer` is empty, the iterator will return null. |
| 1967 | /// If `delimiter` does not exist in buffer, |
| 1968 | /// the iterator will return `buffer`, null, in that order. |
| 1969 | /// |
| 1970 | /// See also: `tokenizeAny`, `tokenizeFull`, |
| 1971 | /// `splitFull`,`splitAny`, and `splitScalar` |
| 1972 | /// `splitBackwardsFull`, `splitBackwardsAny`, and `splitBackwardsScalar` |
| 1973 | pub fn tokenizeScalar(comptime T: type, buffer: []const T, delimiter: T) TokenIterator(T, .scalar) { |
| 1974 | return .{ |
| 1975 | .index = 0, |
| 1976 | .buffer = buffer, |
| 1977 | .delimiter = delimiter, |
| 1978 | }; |
| 1979 | } |
| 1980 | |
| 1981 | test "tokenizeScalar" { |
| 1982 | var it = tokenizeScalar(u8, " abc def ghi ", ' '); |
| 1934 | 1983 | try testing.expect(eql(u8, it.next().?, "abc")); |
| 1935 | 1984 | try testing.expect(eql(u8, it.peek().?, "def")); |
| 1936 | 1985 | try testing.expect(eql(u8, it.next().?, "def")); |
| 1937 | 1986 | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 1938 | 1987 | try testing.expect(it.next() == null); |
| 1939 | 1988 | |
| 1940 | | it = tokenize(u8, "..\\bob", "\\"); |
| 1989 | it = tokenizeScalar(u8, "..\\bob", '\\'); |
| 1941 | 1990 | try testing.expect(eql(u8, it.next().?, "..")); |
| 1942 | 1991 | try testing.expect(eql(u8, "..", "..\\bob"[0..it.index])); |
| 1943 | 1992 | try testing.expect(eql(u8, it.next().?, "bob")); |
| 1944 | 1993 | try testing.expect(it.next() == null); |
| 1945 | 1994 | |
| 1946 | | it = tokenize(u8, "//a/b", "/"); |
| 1995 | it = tokenizeScalar(u8, "//a/b", '/'); |
| 1947 | 1996 | try testing.expect(eql(u8, it.next().?, "a")); |
| 1948 | 1997 | try testing.expect(eql(u8, it.next().?, "b")); |
| 1949 | 1998 | try testing.expect(eql(u8, "//a/b", "//a/b"[0..it.index])); |
| 1950 | 1999 | try testing.expect(it.next() == null); |
| 1951 | 2000 | |
| 1952 | | it = tokenize(u8, "|", "|"); |
| 2001 | it = tokenizeScalar(u8, "|", '|'); |
| 1953 | 2002 | try testing.expect(it.next() == null); |
| 1954 | 2003 | try testing.expect(it.peek() == null); |
| 1955 | 2004 | |
| 1956 | | it = tokenize(u8, "", "|"); |
| 2005 | it = tokenizeScalar(u8, "", '|'); |
| 1957 | 2006 | try testing.expect(it.next() == null); |
| 1958 | 2007 | try testing.expect(it.peek() == null); |
| 1959 | 2008 | |
| 1960 | | it = tokenize(u8, "hello", ""); |
| 1961 | | try testing.expect(eql(u8, it.next().?, "hello")); |
| 1962 | | try testing.expect(it.next() == null); |
| 1963 | | |
| 1964 | | it = tokenize(u8, "hello", " "); |
| 2009 | it = tokenizeScalar(u8, "hello", ' '); |
| 1965 | 2010 | try testing.expect(eql(u8, it.next().?, "hello")); |
| 1966 | 2011 | try testing.expect(it.next() == null); |
| 1967 | 2012 | |
| 1968 | | var it16 = tokenize( |
| 2013 | var it16 = tokenizeScalar( |
| 1969 | 2014 | u16, |
| 1970 | 2015 | std.unicode.utf8ToUtf16LeStringLiteral("hello"), |
| 1971 | | std.unicode.utf8ToUtf16LeStringLiteral(" "), |
| 2016 | ' ', |
| 1972 | 2017 | ); |
| 1973 | 2018 | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("hello"))); |
| 1974 | 2019 | try testing.expect(it16.next() == null); |
| 1975 | 2020 | } |
| 1976 | 2021 | |
| 1977 | | test "tokenize (multibyte)" { |
| 1978 | | var it = tokenize(u8, "a|b,c/d e", " /,|"); |
| 2022 | test "tokenizeAny (multibyte)" { |
| 2023 | var it = tokenizeAny(u8, "a|b,c/d e", " /,|"); |
| 1979 | 2024 | try testing.expect(eql(u8, it.next().?, "a")); |
| 1980 | 2025 | try testing.expect(eql(u8, it.peek().?, "b")); |
| 1981 | 2026 | try testing.expect(eql(u8, it.next().?, "b")); |
| ... | ... | @@ -1985,7 +2030,11 @@ test "tokenize (multibyte)" { |
| 1985 | 2030 | try testing.expect(it.next() == null); |
| 1986 | 2031 | try testing.expect(it.peek() == null); |
| 1987 | 2032 | |
| 1988 | | var it16 = tokenize( |
| 2033 | it = tokenizeAny(u8, "hello", ""); |
| 2034 | try testing.expect(eql(u8, it.next().?, "hello")); |
| 2035 | try testing.expect(it.next() == null); |
| 2036 | |
| 2037 | var it16 = tokenizeAny( |
| 1989 | 2038 | u16, |
| 1990 | 2039 | std.unicode.utf8ToUtf16LeStringLiteral("a|b,c/d e"), |
| 1991 | 2040 | std.unicode.utf8ToUtf16LeStringLiteral(" /,|"), |
| ... | ... | @@ -1998,18 +2047,68 @@ test "tokenize (multibyte)" { |
| 1998 | 2047 | try testing.expect(it16.next() == null); |
| 1999 | 2048 | } |
| 2000 | 2049 | |
| 2050 | test "tokenizeFull" { |
| 2051 | var it = tokenizeFull(u8, "a<>b<><>c><>d><", "<>"); |
| 2052 | try testing.expectEqualStrings("a", it.next().?); |
| 2053 | try testing.expectEqualStrings("b", it.peek().?); |
| 2054 | try testing.expectEqualStrings("b", it.next().?); |
| 2055 | try testing.expectEqualStrings("c>", it.next().?); |
| 2056 | try testing.expectEqualStrings("d><", it.next().?); |
| 2057 | try testing.expect(it.next() == null); |
| 2058 | try testing.expect(it.peek() == null); |
| 2059 | |
| 2060 | var it16 = tokenizeFull( |
| 2061 | u16, |
| 2062 | std.unicode.utf8ToUtf16LeStringLiteral("a<>b<><>c><>d><"), |
| 2063 | std.unicode.utf8ToUtf16LeStringLiteral("<>"), |
| 2064 | ); |
| 2065 | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a"))); |
| 2066 | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b"))); |
| 2067 | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c>"))); |
| 2068 | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d><"))); |
| 2069 | try testing.expect(it16.next() == null); |
| 2070 | } |
| 2071 | |
| 2001 | 2072 | test "tokenize (reset)" { |
| 2002 | | var it = tokenize(u8, " abc def ghi ", " "); |
| 2003 | | try testing.expect(eql(u8, it.next().?, "abc")); |
| 2004 | | try testing.expect(eql(u8, it.next().?, "def")); |
| 2005 | | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 2073 | { |
| 2074 | var it = tokenizeAny(u8, " abc def ghi ", " "); |
| 2075 | try testing.expect(eql(u8, it.next().?, "abc")); |
| 2076 | try testing.expect(eql(u8, it.next().?, "def")); |
| 2077 | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 2006 | 2078 | |
| 2007 | | it.reset(); |
| 2079 | it.reset(); |
| 2008 | 2080 | |
| 2009 | | try testing.expect(eql(u8, it.next().?, "abc")); |
| 2010 | | try testing.expect(eql(u8, it.next().?, "def")); |
| 2011 | | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 2012 | | try testing.expect(it.next() == null); |
| 2081 | try testing.expect(eql(u8, it.next().?, "abc")); |
| 2082 | try testing.expect(eql(u8, it.next().?, "def")); |
| 2083 | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 2084 | try testing.expect(it.next() == null); |
| 2085 | } |
| 2086 | { |
| 2087 | var it = tokenizeFull(u8, "<><>abc<>def<><>ghi<>", "<>"); |
| 2088 | try testing.expect(eql(u8, it.next().?, "abc")); |
| 2089 | try testing.expect(eql(u8, it.next().?, "def")); |
| 2090 | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 2091 | |
| 2092 | it.reset(); |
| 2093 | |
| 2094 | try testing.expect(eql(u8, it.next().?, "abc")); |
| 2095 | try testing.expect(eql(u8, it.next().?, "def")); |
| 2096 | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 2097 | try testing.expect(it.next() == null); |
| 2098 | } |
| 2099 | { |
| 2100 | var it = tokenizeScalar(u8, " abc def ghi ", ' '); |
| 2101 | try testing.expect(eql(u8, it.next().?, "abc")); |
| 2102 | try testing.expect(eql(u8, it.next().?, "def")); |
| 2103 | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 2104 | |
| 2105 | it.reset(); |
| 2106 | |
| 2107 | try testing.expect(eql(u8, it.next().?, "abc")); |
| 2108 | try testing.expect(eql(u8, it.next().?, "def")); |
| 2109 | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 2110 | try testing.expect(it.next() == null); |
| 2111 | } |
| 2013 | 2112 | } |
| 2014 | 2113 | |
| 2015 | 2114 | /// Deprecated: use `splitFull`, `splitAny`, or `splitScalar` |
| ... | ... | @@ -2026,8 +2125,8 @@ pub const split = splitFull; |
| 2026 | 2125 | /// The delimiter length must not be zero. |
| 2027 | 2126 | /// |
| 2028 | 2127 | /// See also: `splitAny`, `splitScalar`, `splitBackwardsFull`, |
| 2029 | | /// `splitBackwardsAny`,`splitBackwardsScalar`, and |
| 2030 | | /// `tokenize`. |
| 2128 | /// `splitBackwardsAny`,`splitBackwardsScalar`, |
| 2129 | /// `tokenizeAny`, `tokenizeFull`, and `tokenizeScalar`. |
| 2031 | 2130 | pub fn splitFull(comptime T: type, buffer: []const T, delimiter: []const T) SplitIterator(T, .full) { |
| 2032 | 2131 | assert(delimiter.len != 0); |
| 2033 | 2132 | return .{ |
| ... | ... | @@ -2047,8 +2146,8 @@ pub fn splitFull(comptime T: type, buffer: []const T, delimiter: []const T) Spli |
| 2047 | 2146 | /// the iterator will return `buffer`, null, in that order. |
| 2048 | 2147 | /// |
| 2049 | 2148 | /// See also: `splitFull`, `splitScalar`, `splitBackwardsFull`, |
| 2050 | | /// `splitBackwardsAny`,`splitBackwardsScalar`, and |
| 2051 | | /// `tokenize`. |
| 2149 | /// `splitBackwardsAny`,`splitBackwardsScalar`, |
| 2150 | /// `tokenizeAny`, `tokenizeFull`, and `tokenizeScalar`. |
| 2052 | 2151 | pub fn splitAny(comptime T: type, buffer: []const T, delimiters: []const T) SplitIterator(T, .any) { |
| 2053 | 2152 | return .{ |
| 2054 | 2153 | .index = 0, |
| ... | ... | @@ -2067,8 +2166,8 @@ pub fn splitAny(comptime T: type, buffer: []const T, delimiters: []const T) Spli |
| 2067 | 2166 | /// the iterator will return `buffer`, null, in that order. |
| 2068 | 2167 | /// |
| 2069 | 2168 | /// See also: `splitFull`, `splitAny`, `splitBackwardsFull`, |
| 2070 | | /// `splitBackwardsAny`,`splitBackwardsScalar`, and |
| 2071 | | /// `tokenize`. |
| 2169 | /// `splitBackwardsAny`,`splitBackwardsScalar`, |
| 2170 | /// `tokenizeAny`, `tokenizeFull`, and `tokenizeScalar`. |
| 2072 | 2171 | pub fn splitScalar(comptime T: type, buffer: []const T, delimiter: T) SplitIterator(T, .scalar) { |
| 2073 | 2172 | return .{ |
| 2074 | 2173 | .index = 0, |
| ... | ... | @@ -2224,8 +2323,8 @@ pub const splitBackwards = splitBackwardsFull; |
| 2224 | 2323 | /// The delimiter length must not be zero. |
| 2225 | 2324 | /// |
| 2226 | 2325 | /// See also: `splitBackwardsAny`, `splitBackwardsScalar`, |
| 2227 | | /// `splitFull`, `splitAny`,`splitScalar`, and |
| 2228 | | /// `tokenize`. |
| 2326 | /// `splitFull`, `splitAny`,`splitScalar`, |
| 2327 | /// `tokenizeAny`, `tokenizeFull`, and `tokenizeScalar`. |
| 2229 | 2328 | pub fn splitBackwardsFull(comptime T: type, buffer: []const T, delimiter: []const T) SplitBackwardsIterator(T, .full) { |
| 2230 | 2329 | assert(delimiter.len != 0); |
| 2231 | 2330 | return .{ |
| ... | ... | @@ -2245,8 +2344,8 @@ pub fn splitBackwardsFull(comptime T: type, buffer: []const T, delimiter: []cons |
| 2245 | 2344 | /// the iterator will return `buffer`, null, in that order. |
| 2246 | 2345 | /// |
| 2247 | 2346 | /// See also: `splitBackwardsFull`, `splitBackwardsScalar`, |
| 2248 | | /// `splitFull`, `splitAny`,`splitScalar`, and |
| 2249 | | /// `tokenize`. |
| 2347 | /// `splitFull`, `splitAny`,`splitScalar`, |
| 2348 | /// `tokenizeAny`, `tokenizeFull`, and `tokenizeScalar`. |
| 2250 | 2349 | pub fn splitBackwardsAny(comptime T: type, buffer: []const T, delimiters: []const T) SplitBackwardsIterator(T, .any) { |
| 2251 | 2350 | return .{ |
| 2252 | 2351 | .index = buffer.len, |
| ... | ... | @@ -2265,8 +2364,8 @@ pub fn splitBackwardsAny(comptime T: type, buffer: []const T, delimiters: []cons |
| 2265 | 2364 | /// the iterator will return `buffer`, null, in that order. |
| 2266 | 2365 | /// |
| 2267 | 2366 | /// See also: `splitBackwardsFull`, `splitBackwardsAny`, |
| 2268 | | /// `splitFull`, `splitAny`,`splitScalar`, and |
| 2269 | | /// `tokenize`. |
| 2367 | /// `splitFull`, `splitAny`,`splitScalar`, |
| 2368 | /// `tokenizeAny`, `tokenizeFull`, and `tokenizeScalar`. |
| 2270 | 2369 | pub fn splitBackwardsScalar(comptime T: type, buffer: []const T, delimiter: T) SplitBackwardsIterator(T, .scalar) { |
| 2271 | 2370 | return .{ |
| 2272 | 2371 | .index = buffer.len, |
| ... | ... | @@ -2596,10 +2695,13 @@ test "endsWith" { |
| 2596 | 2695 | |
| 2597 | 2696 | pub const DelimiterType = enum { full, any, scalar }; |
| 2598 | 2697 | |
| 2599 | | pub fn TokenIterator(comptime T: type) type { |
| 2698 | pub fn TokenIterator(comptime T: type, comptime delimiter_type: DelimiterType) type { |
| 2600 | 2699 | return struct { |
| 2601 | 2700 | buffer: []const T, |
| 2602 | | delimiter_bytes: []const T, |
| 2701 | delimiter: switch (delimiter_type) { |
| 2702 | .full, .any => []const T, |
| 2703 | .scalar => T, |
| 2704 | }, |
| 2603 | 2705 | index: usize, |
| 2604 | 2706 | |
| 2605 | 2707 | const Self = @This(); |
| ... | ... | @@ -2616,7 +2718,10 @@ pub fn TokenIterator(comptime T: type) type { |
| 2616 | 2718 | /// complete. Does not advance to the next token. |
| 2617 | 2719 | pub fn peek(self: *Self) ?[]const T { |
| 2618 | 2720 | // move to beginning of token |
| 2619 | | while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} |
| 2721 | while (self.index < self.buffer.len and self.isDelimiter(self.index)) : (self.index += switch (delimiter_type) { |
| 2722 | .full => self.delimiter.len, |
| 2723 | .any, .scalar => 1, |
| 2724 | }) {} |
| 2620 | 2725 | const start = self.index; |
| 2621 | 2726 | if (start == self.buffer.len) { |
| 2622 | 2727 | return null; |
| ... | ... | @@ -2624,7 +2729,7 @@ pub fn TokenIterator(comptime T: type) type { |
| 2624 | 2729 | |
| 2625 | 2730 | // move to end of token |
| 2626 | 2731 | var end = start; |
| 2627 | | while (end < self.buffer.len and !self.isSplitByte(self.buffer[end])) : (end += 1) {} |
| 2732 | while (end < self.buffer.len and !self.isDelimiter(end)) : (end += 1) {} |
| 2628 | 2733 | |
| 2629 | 2734 | return self.buffer[start..end]; |
| 2630 | 2735 | } |
| ... | ... | @@ -2633,7 +2738,10 @@ pub fn TokenIterator(comptime T: type) type { |
| 2633 | 2738 | pub fn rest(self: Self) []const T { |
| 2634 | 2739 | // move to beginning of token |
| 2635 | 2740 | var index: usize = self.index; |
| 2636 | | while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {} |
| 2741 | while (index < self.buffer.len and self.isDelimiter(index)) : (index += switch (delimiter_type) { |
| 2742 | .full => self.delimiter.len, |
| 2743 | .any, .scalar => 1, |
| 2744 | }) {} |
| 2637 | 2745 | return self.buffer[index..]; |
| 2638 | 2746 | } |
| 2639 | 2747 | |
| ... | ... | @@ -2642,13 +2750,20 @@ pub fn TokenIterator(comptime T: type) type { |
| 2642 | 2750 | self.index = 0; |
| 2643 | 2751 | } |
| 2644 | 2752 | |
| 2645 | | fn isSplitByte(self: Self, byte: T) bool { |
| 2646 | | for (self.delimiter_bytes) |delimiter_byte| { |
| 2647 | | if (byte == delimiter_byte) { |
| 2648 | | return true; |
| 2649 | | } |
| 2753 | fn isDelimiter(self: Self, index: usize) bool { |
| 2754 | switch (delimiter_type) { |
| 2755 | .full => return startsWith(T, self.buffer[index..], self.delimiter), |
| 2756 | .any => { |
| 2757 | const item = self.buffer[index]; |
| 2758 | for (self.delimiter) |delimiter_item| { |
| 2759 | if (item == delimiter_item) { |
| 2760 | return true; |
| 2761 | } |
| 2762 | } |
| 2763 | return false; |
| 2764 | }, |
| 2765 | .scalar => return self.buffer[index] == self.delimiter, |
| 2650 | 2766 | } |
| 2651 | | return false; |
| 2652 | 2767 | } |
| 2653 | 2768 | }; |
| 2654 | 2769 | } |