From abda75feeeed1bbda87a7a9e54bc8794eefc54e6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Jun 2021 23:45:45 +0100 Subject: [PATCH] Add `bufio.Lookahead_Reader` --- core/bufio/lookahead_reader.odin | 83 ++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 core/bufio/lookahead_reader.odin 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); +}