From 9b22583397037de55cae23d93a12025eddcb4f4a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 4 Dec 2020 20:18:41 +0000 Subject: Add `bytes.Buffer` --- core/bytes/buffer.odin | 331 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 core/bytes/buffer.odin (limited to 'core/bytes/buffer.odin') diff --git a/core/bytes/buffer.odin b/core/bytes/buffer.odin new file mode 100644 index 000000000..427fc7253 --- /dev/null +++ b/core/bytes/buffer.odin @@ -0,0 +1,331 @@ +package bytes + +import "core:io" +import "core:unicode/utf8" + +MIN_READ :: 512; + +@(private) +SMALL_BUFFER_SIZE :: 64; + +Buffer :: struct { + buf: [dynamic]byte, + off: int, + last_read: Read_Op, +} + +@(private) +Read_Op :: enum i8 { + Read = -1, + Invalid = 0, + Read_Rune1 = 1, + Read_Rune2 = 2, + Read_Rune3 = 3, + Read_Rune4 = 4, +} + + +buffer_init :: proc(b: ^Buffer, buf: []byte) { + resize(&b.buf, len(buf)); + copy(b.buf[:], buf); +} + +buffer_init_string :: proc(b: ^Buffer, s: string) { + resize(&b.buf, len(s)); + copy(b.buf[:], s); +} + + +buffer_destroy :: proc(b: ^Buffer) { + delete(b.buf); + buffer_reset(b); +} + +buffer_to_bytes :: proc(b: ^Buffer) -> []byte { + return b.buf[b.off:]; +} + +buffer_to_string :: proc(b: ^Buffer) -> string { + if b == nil { + return ""; + } + return string(b.buf[b.off:]); +} + +buffer_is_empty :: proc(b: ^Buffer) -> bool { + return len(b.buf) <= b.off; +} + +buffer_length :: proc(b: ^Buffer) -> int { + return len(b.buf) - b.off; +} + +buffer_capacity :: proc(b: ^Buffer) -> int { + return cap(b.buf); +} + +buffer_reset :: proc(b: ^Buffer) { + clear(&b.buf); + b.off = 0; + b.last_read = .Invalid; +} + + +buffer_truncate :: proc(b: ^Buffer, n: int) { + if n == 0 { + buffer_reset(b); + return; + } + b.last_read = .Invalid; + if n < 0 || n > buffer_length(b) { + panic("bytes.truncate: truncation out of range"); + } + resize(&b.buf, b.off+n); +} + +@(private) +_buffer_try_grow :: proc(b: ^Buffer, n: int) -> (int, bool) { + if l := len(b.buf); n <= cap(b.buf)-l { + resize(&b.buf, l+n); + return l, true; + } + return 0, false; +} + +@(private) +_buffer_grow :: proc(b: ^Buffer, n: int) -> int { + m := buffer_length(b); + if m == 0 && b.off != 0 { + buffer_reset(b); + } + if i, ok := _buffer_try_grow(b, n); ok { + return i; + } + if b.buf == nil && n <= SMALL_BUFFER_SIZE { + b.buf = make([dynamic]byte, n, SMALL_BUFFER_SIZE); + return 0; + } + + c := cap(b.buf); + if n <= c/2 - m { + copy(b.buf[:], b.buf[b.off:]); + } else if c > max(int) - c - n { + panic("bytes.Buffer: too large"); + } else { + resize(&b.buf, 2*c + n); + copy(b.buf[:], b.buf[b.off:]); + } + b.off = 0; + resize(&b.buf, m+n); + return m; +} + +buffer_grow :: proc(b: ^Buffer, n: int) { + if n < 0 { + panic("bytes.buffer_grow: negative count"); + } + m := _buffer_grow(b, n); + resize(&b.buf, m); +} + + +buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) { + b.last_read = .Invalid; + m, ok := _buffer_try_grow(b, len(p)); + if !ok { + m = _buffer_grow(b, len(p)); + } + return copy(b.buf[m:], p), nil; +} + +buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) { + b.last_read = .Invalid; + m, ok := _buffer_try_grow(b, len(s)); + if !ok { + m = _buffer_grow(b, len(s)); + } + return copy(b.buf[m:], s), nil; +} + +buffer_write_byte :: proc(b: ^Buffer, c: byte) -> io.Error { + b.last_read = .Invalid; + m, ok := _buffer_try_grow(b, 1); + if !ok { + m = _buffer_grow(b, 1); + } + b.buf[m] = c; + return nil; +} + +buffer_write_rune :: proc(b: ^Buffer, r: rune) -> (n: int, err: io.Error) { + if r < utf8.RUNE_SELF { + buffer_write_byte(b, byte(r)); + return 1, nil; + } + b.last_read = .Invalid; + m, ok := _buffer_try_grow(b, utf8.UTF_MAX); + if !ok { + m = _buffer_grow(b, utf8.UTF_MAX); + } + res: [4]byte; + res, n = utf8.encode_rune(r); + copy(b.buf[m:][:utf8.UTF_MAX], res[:n]); + resize(&b.buf, m+n); + return; +} + +buffer_next :: proc(b: ^Buffer, n: int) -> []byte { + n := n; + b.last_read = .Invalid; + m := buffer_length(b); + if n > m { + n = m; + } + data := b.buf[b.off : b.off + n]; + b.off += n; + if n > 0 { + b.last_read = .Read; + } + return data; +} + +buffer_read :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) { + b.last_read = .Invalid; + if buffer_is_empty(b) { + buffer_reset(b); + if len(p) == 0 { + return 0, nil; + } + return 0, .EOF; + } + n = copy(p, b.buf[b.off:]); + b.off += n; + if n > 0 { + b.last_read = .Read; + } + return; +} + +buffer_read_byte :: proc(b: ^Buffer) -> (byte, io.Error) { + if buffer_is_empty(b) { + buffer_reset(b); + return 0, .EOF; + } + c := b.buf[b.off]; + b.off += 1; + b.last_read = .Read; + return c, nil; +} + +buffer_read_rune :: proc(b: ^Buffer) -> (r: rune, size: int, err: io.Error) { + if buffer_is_empty(b) { + buffer_reset(b); + return 0, 0, .EOF; + } + c := b.buf[b.off]; + if c < utf8.RUNE_SELF { + b.off += 1; + b.last_read = .Read_Rune1; + return rune(c), 1, nil; + } + r, size = utf8.decode_rune(b.buf[b.off:]); + b.off += size; + b.last_read = Read_Op(i8(size)); + return; +} + +buffer_unread_byte :: proc(b: ^Buffer) -> io.Error { + if b.last_read == .Invalid { + return .Invalid_Unread; + } + b.last_read = .Invalid; + if b.off > 0 { + b.off -= 1; + } + return nil; +} + +buffer_unread_rune :: proc(b: ^Buffer) -> io.Error { + if b.last_read <= .Invalid { + return .Invalid_Unread; + } + if b.off >= int(b.last_read) { + b.off -= int(i8(b.last_read)); + } + b.last_read = .Invalid; + return nil; +} + + +buffer_read_bytes :: proc(b: ^Buffer, delim: byte) -> (line: []byte, err: io.Error) { + i := index_byte(b.buf[b.off:], delim); + end := b.off + i + 1; + if i < 0 { + end = len(b.buf); + err = .EOF; + } + line = b.buf[b.off:end]; + b.off = end; + b.last_read = .Read; + return; +} + +buffer_read_string :: proc(b: ^Buffer, delim: byte) -> (line: string, err: io.Error) { + slice: []byte; + slice, err = buffer_read_bytes(b, delim); + return string(slice), err; +} + + + +buffer_to_stream :: proc(b: ^Buffer) -> (s: io.Stream) { + s.stream_data = b; + s.stream_vtable = _buffer_vtable; + return; +} + +@(private) +_buffer_vtable := &io.Stream_VTable{ + impl_size = proc(s: io.Stream) -> i64 { + b := (^Buffer)(s.stream_data); + return i64(buffer_capacity(b)); + }, + impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { + b := (^Buffer)(s.stream_data); + return buffer_read(b, p); + }, + impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) { + b := (^Buffer)(s.stream_data); + return buffer_read_byte(b); + }, + impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) { + b := (^Buffer)(s.stream_data); + return buffer_read_rune(b); + }, + impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { + b := (^Buffer)(s.stream_data); + return buffer_write(b, p); + }, + impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error { + b := (^Buffer)(s.stream_data); + return buffer_write_byte(b, c); + }, + impl_unread_byte = proc(s: io.Stream) -> io.Error { + b := (^Buffer)(s.stream_data); + return buffer_unread_byte(b); + }, + impl_unread_rune = proc(s: io.Stream) -> io.Error { + b := (^Buffer)(s.stream_data); + return buffer_unread_rune(b); + }, + impl_destroy = proc(s: io.Stream) -> io.Error { + b := (^Buffer)(s.stream_data); + buffer_destroy(b); + return nil; + }, + + // TODO(bill): write_to and read_from + // impl_write_to = nil, + // impl_read_from = nil, +}; + -- cgit v1.2.3 From a82c902f991b11b0f846e4379dfbf19ae962afde Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Dec 2020 15:36:02 +0000 Subject: Minor correction to bytes.Buffer's vtable --- core/bytes/buffer.odin | 4 ++++ core/io/io.odin | 44 ++++++++++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 18 deletions(-) (limited to 'core/bytes/buffer.odin') diff --git a/core/bytes/buffer.odin b/core/bytes/buffer.odin index 427fc7253..61fde9605 100644 --- a/core/bytes/buffer.odin +++ b/core/bytes/buffer.odin @@ -310,6 +310,10 @@ _buffer_vtable := &io.Stream_VTable{ b := (^Buffer)(s.stream_data); return buffer_write_byte(b, c); }, + impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) { + b := (^Buffer)(s.stream_data); + return buffer_write_rune(b, r); + }, impl_unread_byte = proc(s: io.Stream) -> io.Error { b := (^Buffer)(s.stream_data); return buffer_unread_byte(b); diff --git a/core/io/io.odin b/core/io/io.odin index b4d2c16ec..e33b33064 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -44,22 +44,23 @@ Error :: enum i32 { Empty = -1, } -Close_Proc :: distinct proc(using s: Stream) -> Error; -Flush_Proc :: distinct proc(using s: Stream) -> Error; -Seek_Proc :: distinct proc(using s: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error); -Size_Proc :: distinct proc(using s: Stream) -> i64; -Read_Proc :: distinct proc(using s: Stream, p: []byte) -> (n: int, err: Error); -Read_At_Proc :: distinct proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error); -Read_From_Proc :: distinct proc(using s: Stream, r: Reader) -> (n: i64, err: Error); -Read_Byte_Proc :: distinct proc(using s: Stream) -> (byte, Error); -Read_Rune_Proc :: distinct proc(using s: Stream) -> (ch: rune, size: int, err: Error); -Unread_Byte_Proc :: distinct proc(using s: Stream) -> Error; -Unread_Rune_Proc :: distinct proc(using s: Stream) -> Error; -Write_Proc :: distinct proc(using s: Stream, p: []byte) -> (n: int, err: Error); -Write_At_Proc :: distinct proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error); -Write_To_Proc :: distinct proc(using s: Stream, w: Writer) -> (n: i64, err: Error); -Write_Byte_Proc :: distinct proc(using s: Stream, c: byte) -> Error; -Destroy_Proc :: distinct proc(using s: Stream) -> Error; +Close_Proc :: proc(using s: Stream) -> Error; +Flush_Proc :: proc(using s: Stream) -> Error; +Seek_Proc :: proc(using s: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error); +Size_Proc :: proc(using s: Stream) -> i64; +Read_Proc :: proc(using s: Stream, p: []byte) -> (n: int, err: Error); +Read_At_Proc :: proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error); +Read_From_Proc :: proc(using s: Stream, r: Reader) -> (n: i64, err: Error); +Read_Byte_Proc :: proc(using s: Stream) -> (byte, Error); +Read_Rune_Proc :: proc(using s: Stream) -> (ch: rune, size: int, err: Error); +Unread_Byte_Proc :: proc(using s: Stream) -> Error; +Unread_Rune_Proc :: proc(using s: Stream) -> Error; +Write_Proc :: proc(using s: Stream, p: []byte) -> (n: int, err: Error); +Write_At_Proc :: proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error); +Write_To_Proc :: proc(using s: Stream, w: Writer) -> (n: i64, err: Error); +Write_Byte_Proc :: proc(using s: Stream, c: byte) -> Error; +Write_Rune_Proc :: proc(using s: Stream, r: rune) -> (size: int, err: Error); +Destroy_Proc :: proc(using s: Stream) -> Error; Stream :: struct { @@ -82,6 +83,7 @@ Stream_VTable :: struct { impl_write: Write_Proc, impl_write_at: Write_At_Proc, impl_write_byte: Write_Byte_Proc, + impl_write_rune: Write_Rune_Proc, impl_read_from: Read_From_Proc, impl_unread_byte: Unread_Byte_Proc, @@ -371,10 +373,16 @@ write_string :: proc(s: Writer, str: string) -> (n: int, err: Error) { return write(s, transmute([]byte)str); } -write_rune :: proc(s: Writer, r: rune) -> (n: int, err: Error) { +write_rune :: proc(s: Writer, r: rune) -> (size: int, err: Error) { + if s.stream_vtable != nil && s.impl_write_rune != nil { + return s->impl_write_rune(r); + } + if r < utf8.RUNE_SELF { err = write_byte(s, byte(r)); - n = 1 if err == nil else 0; + if err == nil { + size = 1; + } return; } buf, w := utf8.encode_rune(r); -- cgit v1.2.3