aboutsummaryrefslogtreecommitdiff
path: root/core/bufio
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-06-26 23:45:45 +0100
committergingerBill <bill@gingerbill.org>2021-06-26 23:45:45 +0100
commitabda75feeeed1bbda87a7a9e54bc8794eefc54e6 (patch)
tree96488e260818451d0f30c717fc242da88b1bbf26 /core/bufio
parenta779cb2798c374caa54a350ef3091787894329c1 (diff)
Add `bufio.Lookahead_Reader`
Diffstat (limited to 'core/bufio')
-rw-r--r--core/bufio/lookahead_reader.odin83
1 files changed, 83 insertions, 0 deletions
diff --git a/core/bufio/lookahead_reader.odin b/core/bufio/lookahead_reader.odin
new file mode 100644
index 000000000..04ce2fb6b
--- /dev/null
+++ b/core/bufio/lookahead_reader.odin
@@ -0,0 +1,83 @@
+package bufio
+
+import "core:io"
+
+// Loadahead_Reader provides io lookahead.
+// This is useful for tokenizers/parsers.
+// Loadahead_Reader is similar to bufio.Reader, but unlike bufio.Reader, Loadahead_Reader's buffer size
+// will EXACTLY match the specified size, whereas bufio.Reader's buffer size may differ from the specified size.
+// This makes sure that the buffer will not be accidentally read beyond the expected size.
+Loadahead_Reader :: struct {
+ r: io.Reader,
+ buf: []byte,
+ n: int,
+}
+
+lookahead_reader_init :: proc(lr: ^Loadahead_Reader, r: io.Reader, buf: []byte) -> ^Loadahead_Reader {
+ lr.r = r;
+ lr.buf = buf;
+ lr.n = 0;
+ return lr;
+}
+
+lookahead_reader_buffer :: proc(lr: ^Loadahead_Reader) -> []byte {
+ return lr.buf[:lr.n];
+}
+
+
+// lookahead_reader_peek returns a slice of the Lookahead_Reader which holds n bytes
+// If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
+// NOTE: The returned buffer is not a copy of the underlying buffer
+lookahead_reader_peek :: proc(lr: ^Loadahead_Reader, n: int) -> ([]byte, io.Error) {
+ switch {
+ case n < 0:
+ return nil, .Negative_Read;
+ case n > len(lr.buf):
+ return nil, .Buffer_Full;
+ }
+
+ n := n;
+ err: io.Error;
+ read_count: int;
+
+ if lr.n < n {
+ read_count, err = io.read_at_least(lr.r, lr.buf[lr.n:], n-lr.n);
+ if err == .Unexpected_EOF {
+ err = .EOF;
+ }
+ }
+
+ lr.n += read_count;
+
+ if n > lr.n {
+ n = lr.n;
+ }
+ return lr.buf[:n], err;
+}
+
+// lookahead_reader_peek_all returns a slice of the Lookahead_Reader populating the full buffer
+// If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
+// NOTE: The returned buffer is not a copy of the underlying buffer
+lookahead_reader_peek_all :: proc(lr: ^Loadahead_Reader) -> ([]byte, io.Error) {
+ return lookahead_reader_peek(lr, len(lr.buf));
+}
+
+
+// lookahead_reader_consume drops the first n populated bytes from the Lookahead_Reader.
+lookahead_reader_consume :: proc(lr: ^Loadahead_Reader, n: int) -> io.Error {
+ switch {
+ case n == 0:
+ return nil;
+ case n < 0:
+ return .Negative_Read;
+ case lr.n < n:
+ return .Short_Buffer;
+ }
+ copy(lr.buf, lr.buf[n:lr.n]);
+ lr.n -= n;
+ return nil;
+}
+
+lookahead_reader_consume_all :: proc(lr: ^Loadahead_Reader) -> io.Error {
+ return lookahead_reader_consume(lr, lr.n);
+}