From: Brendan Hansen Date: Mon, 11 Jan 2021 21:50:37 +0000 (-0600) Subject: implemented #27 X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=944e1f198e4f3e8b02a21f7c147c5fd807b49e42;p=onyx.git implemented #27 --- diff --git a/core/io/stream.onyx b/core/io/stream.onyx index bd76c745..d76d09e5 100644 --- a/core/io/stream.onyx +++ b/core/io/stream.onyx @@ -124,6 +124,9 @@ stream_peek_byte :: proc (use s: ^Stream, out: ^u8) -> Error { +// +// StringStream +// StringStream :: struct { use stream : Stream; @@ -185,11 +188,10 @@ string_stream_vtable := Stream_Vtable.{ ss : ^StringStream = ~~s; use ss; - if curr_pos >= data.count do return Error.EOF; + if at >= data.count do return Error.EOF; bytes_to_read := math.min(buffer.count, data.count - at); memory.copy(buffer.data, ^data.data[at], bytes_to_read); - curr_pos += bytes_to_read; if number_read != null do *number_read = bytes_to_read; return Error.None; @@ -235,11 +237,10 @@ string_stream_vtable := Stream_Vtable.{ ss : ^StringStream = ~~s; use ss; - if curr_pos >= data.count do return Error.EOF; + if at >= data.count do return Error.EOF; bytes_to_write := math.min(buffer.count, data.count - at); memory.copy(^data.data[at], buffer.data, bytes_to_write); - curr_pos += bytes_to_write; if number_written != null do *number_written = bytes_to_write; return Error.None; @@ -266,4 +267,189 @@ string_stream_vtable := Stream_Vtable.{ close = null_proc, flush = null_proc, -} \ No newline at end of file +} + + +// +// DynamicStringStream +// +DynamicStringStream :: struct { + use stream : Stream; + + curr_pos : i32; + data : [..] u8; + alloc : Allocator; +} + +dynamic_string_stream_make :: proc (init_size := 128, a := context.allocator) -> DynamicStringStream { + data : [..] u8; + array.init(^data, init_size); + + return DynamicStringStream.{ + stream = Stream.{ + vtable = ^dynamic_string_stream_vtable, + }, + + curr_pos = 0, + data = data, + alloc = a, + }; +} + +dynamic_string_stream_to_str :: proc (use dds: ^DynamicStringStream) -> str { + return data.data[0 .. curr_pos]; +} + +#private +dynamic_string_stream_vtable := Stream_Vtable.{ + seek = proc (s: ^Stream, to: i32, whence: SeekFrom) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + dest : i32; + switch whence { + case SeekFrom.Start do dest = to; + case SeekFrom.Current do dest = curr_pos + to; + case SeekFrom.End do dest = data.count - to; // CHECK: Off by one? + } + + if dest >= data.count { + #context_scope { + context.allocator = alloc; + if !array.ensure_capacity(^data, dest) do return Error.OutOfBounds; + } + } + + curr_pos = dest; + return Error.None; + }, + + tell = proc (s: ^Stream, out: ^i32) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + if out != null do *out = curr_pos; + return Error.None; + }, + + read = proc (s: ^Stream, buffer: [] u8, number_read: ^u32) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + if curr_pos >= data.count do return Error.EOF; + + bytes_to_read := math.min(buffer.count, data.count - curr_pos); + memory.copy(buffer.data, ^data.data[curr_pos], bytes_to_read); + curr_pos += bytes_to_read; + + if number_read != null do *number_read = bytes_to_read; + return Error.None; + }, + + read_at = proc (s: ^Stream, at: u32, buffer: [] u8, number_read: ^u32) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + if at >= data.count do return Error.EOF; + + bytes_to_read := math.min(buffer.count, data.count - at); + memory.copy(buffer.data, ^data.data[at], bytes_to_read); + + if number_read != null do *number_read = bytes_to_read; + return Error.None; + }, + + read_byte = proc (s: ^Stream, out: ^u8) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + if curr_pos >= data.count do return Error.EOF; + + if out != null do *out = data[curr_pos]; + + curr_pos += 1; + return Error.None; + }, + + unread_byte = proc (s: ^Stream) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + if curr_pos <= 0 do return Error.OutOfBounds; + + curr_pos -= 1; + return Error.None; + }, + + write = proc (s: ^Stream, buffer: [] u8, number_written: ^u32) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + if curr_pos + buffer.count >= data.capacity { + #context_scope { + context.allocator = alloc; + if !array.ensure_capacity(^data, curr_pos + buffer.count) do return Error.EOF; + } + } + + memory.copy(^data.data[curr_pos], buffer.data, buffer.count); + curr_pos += buffer.count; + data.count += buffer.count; + + if number_written != null do *number_written = buffer.count; + return Error.None; + }, + + write_at = proc (s: ^Stream, at: u32, buffer: [] u8, number_written: ^u32) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + if at + buffer.count >= data.capacity { + #context_scope { + context.allocator = alloc; + if !array.ensure_capacity(^data, at + buffer.count) do return Error.EOF; + } + } + + memory.copy(^data.data[at], buffer.data, buffer.count); + data.count = math.max(data.count, at + buffer.count); + + if number_written != null do *number_written = buffer.count; + return Error.None; + }, + + write_byte = proc (s: ^Stream, byte: u8) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + #context_scope { + context.allocator = alloc; + if !array.ensure_capacity(^data, data.count + 1) do return Error.EOF; + } + + data[curr_pos] = byte; + curr_pos += 1; + data.count += 1; + + return Error.None; + }, + + size = proc (s: ^Stream) -> i32 { + dss : ^DynamicStringStream = ~~s; + use dss; + + return data.count; + }, + + flush = proc (s: ^Stream) -> Error { + dss : ^DynamicStringStream = ~~s; + use dss; + + curr_pos = 0; + array.clear(^data); + + return Error.None; + }, + + close = null_proc, +} diff --git a/core/io/writer.onyx b/core/io/writer.onyx new file mode 100644 index 00000000..90125517 --- /dev/null +++ b/core/io/writer.onyx @@ -0,0 +1,89 @@ +package core.io + +use package core.conv as conv + +Writer :: struct { + stream : ^Stream; +} + +writer_make :: proc (s: ^Stream) -> Writer { + assert(s.vtable != null, "Stream vtable was not setup correctly."); + + return Writer.{ s }; +} + +write_str :: proc (use writer: ^Writer, s: str) { + stream_write(stream, s); +} + +write_cstr :: proc (use writer: ^Writer, cs: cstr) { + use package core + + s := string.make(cs); + write_str(writer, s); +} + +write_i32 :: proc (use writer: ^Writer, n: i32, base: u32 = 10) { + use package core + + buf : [256] u8; + s := conv.i64_to_str(cast(i64) n, cast(u64) base, buf[0 .. 256]); + write_str(writer, s); +} + +write_i64 :: proc (use writer: ^Writer, n: i64, base: u64 = 10) { + use package core + + buf : [256] u8; + s := conv.i64_to_str(n, base, buf[0 .. 256]); + write_str(writer, s); +} + +write_f32 :: proc (use writer: ^Writer, f: f32) { + use package core + + buf : [256] u8; + s := conv.f64_to_str(cast(f64) f, buf[0 .. 256]); + write_str(writer, s); +} + +write_f64 :: proc (use writer: ^Writer, f: f64) { + use package core + + buf : [256] u8; + s := conv.f64_to_str(f, buf[0 .. 256]); + write_str(writer, s); +} + +write_bool :: proc (use writer: ^Writer, b: bool) { + if b do write_str(writer, "true"); + else do write_str(writer, "false"); +} + +write_ptr :: proc (use writer: ^Writer, p: ^void) { + write_i64(writer, cast(i64) p, 16); +} + +write_range :: proc (use writer: ^Writer, r: range, sep := " ") { + for i: r { + write_i32(writer, i); + if i + r.step < r.high do write_str(writer, sep); + } +} + +write_format :: proc (use writer: ^Writer, format: str, va: ...) { + // POTENTIAL BUG: this buffer will need to be bigger (or dynamic). + buffer: [2048] u8; + write_str(writer, conv.str_format_va(format, buffer[0 .. 2048], va)); +} + +write :: proc { + write_str, write_cstr, + write_i32, write_f32, + write_i64, write_f64, + write_bool, + write_ptr, + write_range, + + write_format, +} \ No newline at end of file diff --git a/core/std/js.onyx b/core/std/js.onyx index 943027ed..71ef69e5 100644 --- a/core/std/js.onyx +++ b/core/std/js.onyx @@ -18,6 +18,7 @@ package core #load "core/io/io" #load "core/io/stream" #load "core/io/reader" +#load "core/io/writer" #load "core/sys/js" diff --git a/core/std/wasi.onyx b/core/std/wasi.onyx index 6ff0eed6..7e5167c1 100644 --- a/core/std/wasi.onyx +++ b/core/std/wasi.onyx @@ -20,6 +20,7 @@ package core #load "core/io/io" #load "core/io/stream" #load "core/io/reader" +#load "core/io/writer" #load "core/sys/wasi" diff --git a/core/stdio.onyx b/core/stdio.onyx index 8ebd94ca..c3e67fda 100644 --- a/core/stdio.onyx +++ b/core/stdio.onyx @@ -11,39 +11,22 @@ package core // of the system package use package system as system -#private_file print_buffer : string.builder.Builder; +#private_file print_stream : io.DynamicStringStream; +#private_file print_writer : io.Writer; stdio_init :: proc () { - print_buffer = string.builder.make(2048); -} - -print_str :: proc (s: str) { - string.builder.append(^print_buffer, s); - if s.data[s.count - 1] == #char "\n" do print_buffer_flush(); -} - -print_cstr :: proc (s: cstr) do string.builder.append(^print_buffer, s); -print_i64 :: proc (n: i64, base: u64 = 10) do string.builder.append(^print_buffer, n, base); -print_i32 :: proc (n: i32, base: u32 = 10) do string.builder.append(^print_buffer, cast(i64) n, cast(u64) base); -print_f64 :: proc (n: f64) do string.builder.append(^print_buffer, n); -print_f32 :: proc (n: f32) do string.builder.append(^print_buffer, cast(f64) n); -print_bool :: proc (b: bool) do string.builder.append(^print_buffer, b); -print_ptr :: proc (p: ^void) do string.builder.append(^print_buffer, cast(i64) p, cast(u64) 16); - -print_range :: proc (r: range, sep := " ") { - for i: r { - print(i); - if i + r.step < r.high do print(sep); - } - print("\n"); + print_stream = io.dynamic_string_stream_make(2048, context.allocator); + print_writer = io.writer_make(^print_stream); } print :: proc { - print_str, print_cstr, - print_i64, print_i32, - print_f64, print_f32, - print_bool, print_ptr, - print_range, + proc (x: str) { + io.write(^print_writer, x); + if x[x.count - 1] == #char "\n" do print_stream_flush(); + }, + + proc (x: $T) { io.write(^print_writer, x); }, + proc (x: $T, y: $R) { io.write(^print_writer, x, y); }, } println :: proc (x: $T) { @@ -66,13 +49,13 @@ print_array :: proc (arr: $T, sep := " ") { print("\n"); } -print_buffer_flush :: proc () { - if print_buffer.data.count == 0 do return; +print_stream_flush :: proc () { + if print_stream.data.count == 0 do return; - ^print_buffer - |> string.builder.to_str() + ^print_stream + |> io.dynamic_string_stream_to_str() |> system.output_str(); - ^print_buffer |> string.builder.clear(); + ^print_stream |> io.stream_flush(); } diff --git a/core/string/builder.onyx b/core/string/builder.onyx index 2280686f..495e541e 100644 --- a/core/string/builder.onyx +++ b/core/string/builder.onyx @@ -1,5 +1,8 @@ package core.string.builder +// DEPRECATED: This package is deprecated in favor of using +// an io.DynamicStringStream with an io.Writer. + use package core.array as array use package core.string as string use package core.conv as conv diff --git a/core/sys/js.onyx b/core/sys/js.onyx index 25b2fb9b..35957198 100644 --- a/core/sys/js.onyx +++ b/core/sys/js.onyx @@ -35,5 +35,5 @@ proc () #export "_start" { main.main(args); - print_buffer_flush(); + print_stream_flush(); } diff --git a/core/sys/wasi.onyx b/core/sys/wasi.onyx index a3aaf905..533ad186 100644 --- a/core/sys/wasi.onyx +++ b/core/sys/wasi.onyx @@ -51,5 +51,5 @@ proc () #export "_start" { main.main(argv[0 .. argc]); - print_buffer_flush(); + print_stream_flush(); } diff --git a/tests/array_struct_robustness.onyx b/tests/array_struct_robustness.onyx index 8517edf1..17dfeb46 100644 --- a/tests/array_struct_robustness.onyx +++ b/tests/array_struct_robustness.onyx @@ -5,8 +5,8 @@ use package core Vec2 :: struct { x: i32; y: i32; } // Overload print() to print Vec2's. -proc (use v: Vec2) #add_overload print { - printf("Vec2(%i, %i)", x, y); +proc (use writer: ^io.Writer, use v: Vec2) #add_overload io.write { + io.write_format(writer, "Vec2(%i, %i)", x, y); } EntityStore :: struct {