+//
+// StringStream
+//
StringStream :: struct {
use stream : Stream;
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;
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;
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,
+}
--- /dev/null
+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
// 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) {
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();
}