| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- package bufio
- import "core:io"
- import "core:mem"
- import "core:unicode/utf8"
- import "core:bytes"
- // Reader is a buffered wrapper for an io.Reader
- Reader :: struct {
- buf: []byte,
- buf_allocator: mem.Allocator,
- rd: io.Reader, // reader
- r, w: int, // read and write positions for buf
- err: io.Error,
- last_byte: int, // last byte read, invalid is -1
- last_rune_size: int, // size of last rune read, invalid is -1
- max_consecutive_empty_reads: int,
- }
- DEFAULT_BUF_SIZE :: 4096;
- @(private)
- MIN_READ_BUFFER_SIZE :: 16;
- @(private)
- DEFAULT_MAX_CONSECUTIVE_EMPTY_READS :: 128;
- reader_init :: proc(b: ^Reader, rd: io.Reader, size: int = DEFAULT_BUF_SIZE, allocator := context.allocator) {
- size := size;
- size = max(size, MIN_READ_BUFFER_SIZE);
- reader_reset(b, rd);
- b.buf_allocator = allocator;
- b.buf = make([]byte, size, allocator);
- }
- reader_init_with_buf :: proc(b: ^Reader, rd: io.Reader, buf: []byte) {
- reader_reset(b, rd);
- b.buf_allocator = {};
- b.buf = buf;
- }
- // reader_destroy destroys the underlying buffer with its associated allocator IFF that allocator has been set
- reader_destroy :: proc(b: ^Reader) {
- delete(b.buf, b.buf_allocator);
- b^ = {};
- }
- reader_size :: proc(b: ^Reader) -> int {
- return len(b.buf);
- }
- reader_reset :: proc(b: ^Reader, r: io.Reader) {
- b.rd = r;
- b.r, b.w = 0, 0;
- b.err = nil;
- b.last_byte = -1;
- b.last_rune_size = -1;
- }
- @(private)
- _reader_read_new_chunk :: proc(b: ^Reader) -> io.Error {
- if b.r > 0 {
- copy(b.buf, b.buf[b.r:b.w]);
- b.w -= b.r;
- b.r = 0;
- }
- if b.w >= len(b.buf) {
- return .Buffer_Full;
- }
- if b.max_consecutive_empty_reads <= 0 {
- b.max_consecutive_empty_reads = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS;
- }
- // read new data, and try a limited number of times
- for i := b.max_consecutive_empty_reads; i > 0; i -= 1 {
- n, err := io.read(b.rd, b.buf[b.w:]);
- if n < 0 {
- return .Negative_Read;
- }
- b.w += n;
- if err != nil {
- b.err = err;
- return nil;
- }
- if n > 0 {
- return nil;
- }
- }
- b.err = .No_Progress;
- return nil;
- }
- @(private)
- _reader_consume_err :: proc(b: ^Reader) -> io.Error {
- err := b.err;
- b.err = nil;
- return err;
- }
- // reader_peek returns the next n bytes without advancing the reader
- // The bytes stop being valid on the next read call
- // If reader_peek returns fewer than n bytes, it also return an error
- // explaining why the read is short
- // The error will be .Buffer_Full if n is larger than the internal buffer size
- reader_peek :: proc(b: ^Reader, n: int) -> (data: []byte, err: io.Error) {
- n := n;
- if n < 0 {
- return nil, .Negative_Count;
- }
- b.last_byte = -1;
- b.last_rune_size = -1;
- for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
- if fill_err := _reader_read_new_chunk(b); fill_err != nil {
- return nil, fill_err;
- }
- }
- if n > len(b.buf) {
- return b.buf[b.r : b.w], .Buffer_Full;
- }
- if available := b.w - b.r; available < n {
- n = available;
- err = _reader_consume_err(b);
- if err == nil {
- err = .Buffer_Full;
- }
- }
- return b.buf[b.r : b.r+n], err;
- }
- // reader_buffered returns the number of bytes that can be read from the current buffer
- reader_buffered :: proc(b: ^Reader) -> int {
- return b.w - b.r;
- }
- // reader_discard skips the next n bytes, and returns the number of bytes that were discarded
- reader_discard :: proc(b: ^Reader, n: int) -> (discarded: int, err: io.Error) {
- if n < 0 {
- return 0, .Negative_Count;
- }
- if n == 0 {
- return;
- }
- remaining := n;
- for {
- skip := reader_buffered(b);
- if skip == 0 {
- if fill_err := _reader_read_new_chunk(b); fill_err != nil {
- return 0, fill_err;
- }
- skip = reader_buffered(b);
- }
- skip = min(skip, remaining);
- b.r += skip;
- remaining -= skip;
- if remaining == 0 {
- return n, nil;
- }
- if b.err != nil {
- return n - remaining, _reader_consume_err(b);
- }
- }
- return;
- }
- // reader_read reads data into p
- // The bytes are taken from at most one read on the underlying Reader, which means n may be less than len(p)
- reader_read :: proc(b: ^Reader, p: []byte) -> (n: int, err: io.Error) {
- n = len(p);
- if n == 0 {
- if reader_buffered(b) > 0 {
- return 0, nil;
- }
- return 0, _reader_consume_err(b);
- }
- if b.r == b.w {
- if b.err != nil {
- return 0, _reader_consume_err(b);
- }
- if len(p) >= len(b.buf) {
- n, b.err = io.read(b.rd, p);
- if n < 0 {
- return 0, .Negative_Read;
- }
- if n > 0 {
- b.last_byte = int(p[n-1]);
- b.last_rune_size = -1;
- }
- return n, _reader_consume_err(b);
- }
- b.r, b.w = 0, 0;
- n, b.err = io.read(b.rd, b.buf);
- if n < 0 {
- return 0, .Negative_Read;
- }
- if n == 0 {
- return 0, _reader_consume_err(b);
- }
- b.w += n;
- }
- n = copy(p, b.buf[b.r:b.w]);
- b.r += n;
- b.last_byte = int(b.buf[b.r-1]);
- b.last_rune_size = -1;
- return n, nil;
- }
- // reader_read_byte reads and returns a single byte
- // If no byte is available, it return an error
- reader_read_byte :: proc(b: ^Reader) -> (byte, io.Error) {
- b.last_rune_size = -1;
- for b.r == b.w {
- if b.err != nil {
- return 0, _reader_consume_err(b);
- }
- if err := _reader_read_new_chunk(b); err != nil {
- return 0, err;
- }
- }
- c := b.buf[b.r];
- b.r += 1;
- b.last_byte = int(c);
- return c, nil;
- }
- // reader_unread_byte unreads the last byte. Only the most recently read byte can be unread
- reader_unread_byte :: proc(b: ^Reader) -> io.Error {
- if b.last_byte < 0 || b.r == 0 && b.w > 0 {
- return .Invalid_Unread;
- }
- if b.r > 0 {
- b.r -= 1;
- } else {
- // b.r == 0 && b.w == 0
- b.w = 1;
- }
- b.buf[b.r] = byte(b.last_byte);
- b.last_byte = -1;
- b.last_rune_size = -1;
- return nil;
- }
- // reader_read_rune reads a single UTF-8 encoded unicode character
- // and returns the rune and its size in bytes
- // If the encoded rune is invalid, it consumes one byte and returns utf8.RUNE_ERROR (U+FFFD) with a size of 1
- reader_read_rune :: proc(b: ^Reader) -> (r: rune, size: int, err: io.Error) {
- for b.r+utf8.UTF_MAX > b.w &&
- !utf8.full_rune(b.buf[b.r:b.w]) &&
- b.err == nil &&
- b.w-b.w < len(b.buf) {
- if err = _reader_read_new_chunk(b); err != nil {
- return;
- }
- }
- b.last_rune_size = -1;
- if b.r == b.w {
- err = _reader_consume_err(b);
- return;
- }
- r, size = rune(b.buf[b.r]), 1;
- if r >= utf8.RUNE_SELF {
- r, size = utf8.decode_rune(b.buf[b.r : b.w]);
- }
- b.r += size;
- b.last_byte = int(b.buf[b.r-1]);
- b.last_rune_size = size;
- return;
- }
- // reader_unread_rune unreads the last rune. Only the most recently read rune can be unread
- reader_unread_rune :: proc(b: ^Reader) -> io.Error {
- if b.last_rune_size < 0 || b.r < b.last_rune_size {
- return .Invalid_Unread;
- }
- b.r -= b.last_rune_size;
- b.last_byte = -1;
- b.last_rune_size = -1;
- return nil;
- }
- reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
- write_buf :: proc(b: ^Reader, w: io.Writer) -> (i64, io.Error) {
- n, err := io.write(w, b.buf[b.r:b.w]);
- if n < 0 {
- return 0, .Negative_Write;
- }
- b.r += n;
- return i64(n), err;
- }
- n, err = write_buf(b, w);
- if err != nil {
- return;
- }
- m: i64;
- if nr, ok := io.to_writer_to(b.rd); ok {
- m, err = io.write_to(nr, w);
- n += m;
- return n, err;
- }
- if nw, ok := io.to_reader_from(w); ok {
- m, err = io.read_from(nw, b.rd);
- n += m;
- return n, err;
- }
- if b.w-b.r < len(b.buf) {
- if err = _reader_read_new_chunk(b); err != nil {
- return;
- }
- }
- for b.r < b.w {
- m, err = write_buf(b, w);
- n += m;
- if err != nil {
- return;
- }
- if err = _reader_read_new_chunk(b); err != nil {
- return;
- }
- }
- if b.err == .EOF {
- b.err = nil;
- }
- err = _reader_consume_err(b);
- return;
- }
- // reader_to_stream converts a Reader into an io.Stream
- reader_to_stream :: proc(b: ^Reader) -> (s: io.Stream) {
- s.stream_data = b;
- s.stream_vtable = _reader_vtable;
- return;
- }
- @(private)
- _reader_vtable := &io.Stream_VTable{
- impl_destroy = proc(s: io.Stream) -> io.Error {
- b := (^Reader)(s.stream_data);
- reader_destroy(b);
- return nil;
- },
- impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
- b := (^Reader)(s.stream_data);
- return reader_read(b, p);
- },
- impl_read_byte = proc(s: io.Stream) -> (c: byte, err: io.Error) {
- b := (^Reader)(s.stream_data);
- return reader_read_byte(b);
- },
- impl_unread_byte = proc(s: io.Stream) -> io.Error {
- b := (^Reader)(s.stream_data);
- return reader_unread_byte(b);
- },
- impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
- b := (^Reader)(s.stream_data);
- return reader_read_rune(b);
- },
- impl_unread_rune = proc(s: io.Stream) -> io.Error {
- b := (^Reader)(s.stream_data);
- return reader_unread_rune(b);
- },
- impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
- b := (^Reader)(s.stream_data);
- return reader_write_to(b, w);
- },
- };
- //
- // Utility procedures
- //
- // reader_read_slice reads until the first occurrence of delim from the reader
- // It returns a slice pointing at the bytes in the buffer
- // The bytes stop being valid at the next read
- // If reader_read_slice encounters an error before finding a delimiter
- // reader_read_slice fails with error .Buffer_Full if the buffer fills without a delim
- // Because the data returned from reader_read_slice will be overwritten on the
- // next IO operation, reader_read_bytes or reader_read_string is usually preferred
- //
- // reader_read_slice returns err != nil if and only if line does not end in delim
- //
- reader_read_slice :: proc(b: ^Reader, delim: byte) -> (line: []byte, err: io.Error) {
- s := 0;
- for {
- if i := bytes.index_byte(b.buf[b.r+s : b.w], delim); i >= 0 {
- i += s;
- line = b.buf[b.r:][:i+1];
- b.r += i + 1;
- break;
- }
- if b.err != nil {
- line = b.buf[b.r : b.w];
- b.r = b.w;
- err = _reader_consume_err(b);
- break;
- }
- if reader_buffered(b) >= len(b.buf) {
- b.r = b.w;
- line = b.buf;
- err = .Buffer_Full;
- break;
- }
- s = b.w - b.r;
- if err = _reader_read_new_chunk(b); err != nil {
- break;
- }
- }
- if i := len(line)-1; i >= 0 {
- b.last_byte = int(line[i]);
- b.last_rune_size = -1;
- }
- return;
- }
- // reader_read_bytes reads until the first occurrence of delim from the Reader
- // It returns an allocated slice containing the data up to and including the delimiter
- reader_read_bytes :: proc(b: ^Reader, delim: byte, allocator := context.allocator) -> (buf: []byte, err: io.Error) {
- full: [dynamic]byte;
- full.allocator = allocator;
- frag: []byte;
- for {
- e: io.Error;
- frag, e = reader_read_slice(b, delim);
- if e == nil {
- break;
- }
- if e != .Buffer_Full {
- err = e;
- break;
- }
- append(&full, ..frag);
- }
- append(&full, ..frag);
- return full[:], err;
- }
- // reader_read_string reads until the first occurrence of delim from the Reader
- // It returns an allocated string containing the data up to and including the delimiter
- reader_read_string :: proc(b: ^Reader, delim: byte, allocator := context.allocator) -> (string, io.Error) {
- buf, err := reader_read_bytes(b, delim, allocator);
- return string(buf), err;
- }
|