summaryrefslogtreecommitdiff
path: root/src/code_point.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/code_point.zig')
-rw-r--r--src/code_point.zig55
1 files changed, 46 insertions, 9 deletions
diff --git a/src/code_point.zig b/src/code_point.zig
index ed5fede..5aa12b7 100644
--- a/src/code_point.zig
+++ b/src/code_point.zig
@@ -42,7 +42,7 @@ pub fn decode(bytes: []const u8, offset: u32) ?CodePoint {
42 .offset = offset, 42 .offset = offset,
43 }; 43 };
44 44
45 // Return replacement if we don' have a complete codepoint remaining. Consumes only one byte 45 // Return replacement if we don't have a complete codepoint remaining. Consumes only one byte.
46 if (cp.len > bytes.len) { 46 if (cp.len > bytes.len) {
47 // Unicode replacement code point. 47 // Unicode replacement code point.
48 return .{ 48 return .{
@@ -76,21 +76,30 @@ pub const Iterator = struct {
76 bytes: []const u8, 76 bytes: []const u8,
77 i: u32 = 0, 77 i: u32 = 0,
78 78
79 pub fn next(self: *Iterator) ?CodePoint { 79 pub fn next(iter: *Iterator) ?CodePoint {
80 if (self.i >= self.bytes.len) return null; 80 if (iter.i >= iter.bytes.len) return null;
81 81
82 const res = decode(self.bytes[self.i..], self.i); 82 const res = decode(iter.bytes[iter.i..], iter.i);
83 if (res) |cp| { 83 if (res) |cp| {
84 self.i += cp.len; 84 iter.i += cp.len;
85 } 85 }
86 86
87 return res; 87 return res;
88 } 88 }
89 89
90 pub fn peek(self: *Iterator) ?CodePoint { 90 pub fn peek(iter: *Iterator) ?CodePoint {
91 const saved_i = self.i; 91 const saved_i = iter.i;
92 defer self.i = saved_i; 92 defer iter.i = saved_i;
93 return self.next(); 93 return iter.next();
94 }
95
96 /// Create a backward iterator at this point. It will repeat
97 /// the last CodePoint seen.
98 pub fn reverseIterator(iter: *Iterator) ReverseIterator {
99 if (iter.i == iter.bytes.len) {
100 return .init(iter.bytes);
101 }
102 return .{ .i = iter.i, .bytes = iter.bytes };
94 } 103 }
95}; 104};
96 105
@@ -127,6 +136,17 @@ pub const ReverseIterator = struct {
127 defer iter.i = saved_i; 136 defer iter.i = saved_i;
128 return iter.prev(); 137 return iter.prev();
129 } 138 }
139
140 /// Create a forward iterator at this point. It will repeat the
141 /// last CodePoint seen.
142 pub fn forwardIterator(iter: *ReverseIterator) Iterator {
143 if (iter.i) |i| {
144 var fwd: Iterator = .{ .i = i, .bytes = iter.bytes };
145 _ = fwd.next();
146 return fwd;
147 }
148 return .{ .i = 0, .bytes = iter.bytes };
149 }
130}; 150};
131 151
132inline fn followbyte(b: u8) bool { 152inline fn followbyte(b: u8) bool {
@@ -182,6 +202,23 @@ test ReverseIterator {
182 try testing.expectEqual(@as(?CodePoint, null), r_iter.prev()); 202 try testing.expectEqual(@as(?CodePoint, null), r_iter.prev());
183 try testing.expectEqual(@as(?CodePoint, null), r_iter.prev()); 203 try testing.expectEqual(@as(?CodePoint, null), r_iter.prev());
184 } 204 }
205 {
206 var r_iter: ReverseIterator = .init("123");
207 try testing.expectEqual(@as(u21, '3'), r_iter.prev().?.code);
208 try testing.expectEqual(@as(u21, '2'), r_iter.prev().?.code);
209 try testing.expectEqual(@as(u21, '1'), r_iter.prev().?.code);
210 var iter = r_iter.forwardIterator();
211 try testing.expectEqual(@as(u21, '1'), iter.next().?.code);
212 try testing.expectEqual(@as(u21, '2'), iter.next().?.code);
213 try testing.expectEqual(@as(u21, '3'), iter.next().?.code);
214 r_iter = iter.reverseIterator();
215 try testing.expectEqual(@as(u21, '3'), r_iter.prev().?.code);
216 try testing.expectEqual(@as(u21, '2'), r_iter.prev().?.code);
217 iter = r_iter.forwardIterator();
218 r_iter = iter.reverseIterator();
219 try testing.expectEqual(@as(u21, '2'), iter.next().?.code);
220 try testing.expectEqual(@as(u21, '2'), r_iter.prev().?.code);
221 }
185} 222}
186 223
187const testing = std.testing; 224const testing = std.testing;