getting rid of uses of string.builder, string.reader
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 29 May 2021 03:20:55 +0000 (22:20 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 29 May 2021 03:20:55 +0000 (22:20 -0500)
15 files changed:
core/alloc/arena.onyx
core/alloc/pool.onyx
core/builtin.onyx
core/container/array.onyx
core/container/list.onyx
core/conv.onyx
core/io/reader.onyx
core/string.onyx
core/string/builder.onyx
core/string/reader.onyx
examples/06_dynamic_arrays.onyx
examples/07_structs.onyx
tests/aoc-2020/day1.onyx
tests/aoc-2020/day2.onyx
tests/aoc-2020/day22.onyx

index df6b90b2af3a89e0ac4163ed9bf340014eadec2c..46665d6a934009e061a3cf39d05cbc209bd8e5ef 100644 (file)
@@ -30,7 +30,7 @@ arena_alloc_proc :: (data: rawptr, aa: AllocationAction, size: u32, align: u32,
     alloc_arena := cast(^ArenaState) data;
 
     if aa == AllocationAction.Alloc {
-        // NOTE: An allocation of this size does not fit into a single arena.
+        // An allocation of this size does not fit into a single arena.
         if size > alloc_arena.arena_size - sizeof rawptr {
             return null;
         }
@@ -59,8 +59,10 @@ arena_alloc_proc :: (data: rawptr, aa: AllocationAction, size: u32, align: u32,
     return null;
 }
 
-// NOTE: `arena_size` must be at least 4
+@Note // `arena_size` must be at least 4
 make :: (backing: Allocator, arena_size: u32) -> ArenaState {
+    assert(arena_size >= 4, "Arena size was expected to be at least 4 bytes.");
+    
     initial_arena := cast(^Arena) raw_alloc(backing, arena_size);
     initial_arena.next = null;
 
index b32c29bd95e8ef89d4e5130b5e0f99bb0aba901d..1bf8504cae5b3836ff9268f6a0575f5b79130fc2 100644 (file)
@@ -46,7 +46,9 @@ pool_alloc :: (pool: ^PoolAllocator($Elem)) -> ^Elem {
 }
 
 pool_free :: (pool: ^PoolAllocator($Elem), elem: ^Elem) {
-    // TODO: Maybe add a check that the elem pointer is actually in the buffer?? 
+    @TODO
+    // Add a check that the elem pointer is actually in the buffer?? 
+    
     *(cast(^rawptr) elem) = cast(rawptr) pool.first_free;
     pool.first_free = elem;
 }
index 2ea67a662c163ecb2bbdeb76ca526013de56a073..f252db2528421d479481058b70b0ca97345fa965 100644 (file)
@@ -8,7 +8,8 @@ package builtin
 str  :: #type []u8;
 cstr :: #type ^u8;
 
-// NOTE: Because of many implementation details, all fields of this
+@Note
+// Because of many implementation details, all fields of this
 // struct are required to be i32's.
 range :: struct {
     low  : i32;
@@ -39,7 +40,7 @@ vararg_get :: proc {
     }
 }
 
-// HACK: NullProcHack
+@NullProcHack
 null_proc :: proc () #null ---
 null      :: cast(rawptr) 0;
 
index 98ca56b805bbfadeddaa1eb9369aac8bb7e2535c..c1651dc4a9014b544ded27f76a95edfaa23aafc4 100644 (file)
@@ -184,7 +184,7 @@ sort :: (arr: ^[..] $T, cmp: (T, T) -> i32) {
         x := arr.data[i];
         j := i - 1;
 
-        // NOTE: This is written this way because '&&' does not short circuit right now.
+        @ShortCircuitLogicalOps // This is written this way because '&&' does not short circuit right now.
         while j >= 0 {
             if cmp(arr.data[j], x) > 0 {
                 arr.data[j + 1] = arr.data[j];
index d4bd0658e3daf8691fbe07544ae23255e9aae0a8..a831b2a2da72c14fa268bd900333e952b71bb3e3 100644 (file)
@@ -1,5 +1,7 @@
 package core.list
 
+use package core.intrinsics.onyx { __zero_value }
+
 ListElem :: struct (T: type_expr) {
     next: ^ListElem(T) = null;
     prev: ^ListElem(T) = null;
@@ -39,7 +41,7 @@ push_begin :: (list: ^List($T), x: T) {
     if list.last == null do list.last = new_elem;
 }
 
-pop_end :: (list: ^List($T), default: T = 0) -> T {
+pop_end :: (list: ^List($T), default: T = __zero_value(T)) -> T {
     if list.last == null do return default;
 
     end := list.last;
@@ -50,7 +52,7 @@ pop_end :: (list: ^List($T), default: T = 0) -> T {
     return end.data;
 }
 
-pop_begin :: (list: ^List($T), default: T = 0) -> T {
+pop_begin :: (list: ^List($T), default: T = __zero_value(T)) -> T {
     if list.last == null do return default;
 
     begin := list.first;
@@ -71,6 +73,23 @@ contains :: (list: ^List($T), x: T) -> bool {
     return false;
 }
 
+fold :: (list: ^List($T), init: $R, f: (T, R) -> R) -> R {
+    val := init;
+
+    link := list.first;
+    while link != null {
+        val = f(link.data, val);
+        link = link.next;
+    }
+
+    return val;
+}
+
+map :: proc {
+    (list: ^List($T), f: (^T) -> void) {
+    }
+}
+
 get_iterator :: (list: ^List($T)) -> Iterator(T) {
     iterator_next :: ($T: type_expr, data: rawptr) -> (T, bool) {
         list_iter := cast(^ListIterator(T)) data;
index 6bfab2afa101803080d75871c555d458de35983f..5c7383cc8656b29ace4e6b141d8961996eae62c3 100644 (file)
@@ -86,7 +86,7 @@ i64_to_str :: (n: i64, base: u64, buf: [] u8, min_length := 0) -> str {
     return str.{ data = c + 1, count = len };
 }
 
-// NOTE: This is a big hack but it will work for now
+@Hack @Cleanup // This is a big hack but it will work for now
 f64_to_str :: (f: f64, buf: [] u8) -> str {
     f *= 10000.0;
     v := cast(i64) f;
index 8ab638a03b8af14fb7379d2faeb27d543ffbf3b4..943d360ba59fb49656146b6d5f4d50f034f789c7 100644 (file)
@@ -1,5 +1,7 @@
 package core.io
 
+memory :: package core.memory
+
 Reader :: struct {
     stream : ^Stream;
 }
@@ -10,11 +12,24 @@ reader_make :: (s: ^Stream) -> Reader {
     return Reader.{ s };
 }
 
+reader_from_string :: (s: str) -> Reader {
+    stream_ptr := new(StringStream);     @Leak
+    *stream_ptr = string_stream_make(s);
+
+    return Reader.{ stream_ptr };
+}
+
 read_byte :: (use reader: ^Reader) -> u8 {
     err, byte := stream_read_byte(stream);
     return byte;
 }
 
+read_bytes :: (use reader: ^Reader, bytes := 1, allocator := context.allocator) -> str {
+    buffer := memory.make_slice(u8, bytes, allocator);
+    stream_read(stream, buffer);
+    return buffer;
+}
+
 read_u32 :: (use reader: ^Reader) -> u32 {
     n: u32 = 0;
 
@@ -112,7 +127,7 @@ read_word :: (use reader: ^Reader, numeric_allowed := false, allocator := contex
     return out;
 }
 
-read_until :: (use reader: ^Reader, until: u8, allocator := context.allocator, consume_end := false) -> str {
+read_until :: (use reader: ^Reader, until: u8, skip: u32 = 0, allocator := context.allocator, consume_end := false) -> str {
     _, curr_pos := stream_tell(stream);
 
     count := 0;
@@ -122,7 +137,8 @@ read_until :: (use reader: ^Reader, until: u8, allocator := context.allocator, c
         if curr != until {
             count += 1;
         } else {
-            break;
+            if skip == 0 do break;
+            else do skip -= 1;
         }
 
         err, curr = stream_read_byte(stream);
@@ -173,3 +189,7 @@ skip_whitespace :: (use reader: ^Reader) {
         }
     }
 }
+
+skip_bytes :: (use reader: ^Reader, bytes: u32) {
+    for _: bytes do stream_read_byte(stream);
+}
\ No newline at end of file
index 6bf5a7dcec10ae628415cf371597b04c99f068b8..a34f65ee3654e0da7ac0eab0af94e2124e75791f 100644 (file)
@@ -53,6 +53,25 @@ concat :: proc {
         return str.{ data, len1 + len2 };
     },
 
+    @Cleanup // Don't love that the allocator is necessary here,
+    // but it is impossible to specify a default value for the
+    // allocator while having a variadic number of strings. This
+    // is only due to the languages constraints however. This
+    // could easily be changed since there is no ambiguity.
+    (allocator: Allocator, strings: ..str) -> str {
+        total_length := 0;
+        for s: strings do total_length += s.count;
+
+        data := cast(^u8) raw_alloc(allocator, total_length);
+        offset := 0;
+        for s: strings {
+            memory.copy(data + offset, s.data, s.count);
+            offset += s.count;
+        }
+
+        return str.{ data, total_length };
+    },
+
     (into: ^[..] u8, s: str) -> str {
         array.ensure_capacity(into, into.count + s.count);
         memory.copy(into.data, s.data, into.count);
@@ -61,6 +80,7 @@ concat :: proc {
     }
 }
 
+
 split :: (s: str, delim: u8, allocator := context.allocator) -> []str {
     delim_count := 0;
     for i: 0 .. s.count do if s[i] == delim do delim_count += 1;
@@ -107,7 +127,8 @@ contains :: proc {
     },
 }
 
-// TODO: Check this for edge cases and other bugs. I'm not confident
+@TODO
+// Check this for edge cases and other bugs. I'm not confident
 // it will work perfectly yet.                   - brendanfh 2020/12/21
 compare :: (str1: str, str2: str) -> i32 {
     i := 0;
@@ -238,38 +259,6 @@ advance :: proc {
 
 // DEPRECATED
 // Everything below this point is deprecated
-read_u32 :: (s: ^str, out: ^u32) {
-    n := 0;
-
-    strip_leading_whitespace(s);
-    while s.data[0] >= #char "0" && s.data[0] <= #char "9" {
-        n *= 10;
-        n += cast(u32) (s.data[0] - #char "0");
-
-        s.data += 1;
-        s.count -= 1;
-    }
-
-    *out = n;
-}
-
-read_char :: (s: ^str, out: ^u8) {
-    *out = s.data[0];
-    s.data += 1;
-    s.count -= 1;
-}
-
-read_chars :: (s: ^str, out: ^str, char_count := 1) {
-    out.data = s.data;
-    out.count = char_count;
-    s.data += char_count;
-    s.count -= char_count;
-}
-
-discard_chars :: (s: ^str, char_count := 1) {
-    s.data += char_count;
-    s.count -= char_count;
-}
 
 // Goes up to but not including the closest newline or EOF
 read_line :: (s: ^str, out: ^str) {
@@ -313,7 +302,7 @@ read_until :: (s: ^str, upto: u8, skip := 0) -> str {
     return out;
 }
 
-read_until_either :: (s: ^str, skip: u32, uptos: ..u8) -> str {
+read_until_any :: (s: ^str, skip: u32, uptos: ..u8) -> str {
     if s.count == 0 do return "";
 
     out : str;
@@ -347,7 +336,3 @@ advance_line :: (s: ^str) {
     s.data += adv + 1;
     s.count -= adv + 1;
 }
-
-read :: proc {
-    read_u32, read_char
-}
index 3f15861abf0970755c34dc6399cf7ccdf739c171..afbfc8ec60eac4bbc9517d2c7ab2b99d1d386aff 100644 (file)
@@ -3,6 +3,8 @@ package core.string.builder
 // DEPRECATED: This package is deprecated in favor of using
 // an io.DynamicStringStream with an io.Writer.
 
+#if false {
+
 #private_file array  :: package core.array
 #private_file string :: package core.string
 #private_file conv   :: package core.conv
@@ -71,3 +73,4 @@ to_str :: proc (use sb: ^Builder) -> str {
     return str.{ data.data, data.count };
 }
 
+}
\ No newline at end of file
index c950227dae48131be4420b044539425ad306548a..4c323792d9547d1b928463fa52bc9ea1902d0425 100644 (file)
@@ -88,7 +88,6 @@ read_line :: proc (use reader: ^StringReader) -> str {
     out.data = data;
     out.count = 0;
 
-    // HACK(Brendan): I want to use a for loop, but I don't know why.
     for ch: *(cast(^str) reader) {
         if ch == #char "\n" do break;
         out.count += 1;
@@ -114,7 +113,6 @@ read_until :: proc (use reader: ^StringReader, skip: u32, uptos: ..u8) -> str {
 
     s := skip;
     
-    // HACK(Brendan): See above.
     for ch: *(cast(^str) reader) {
         for upto: uptos do if ch == upto {
             if s == 0 do break break;
index d41c7609e55240f64d78487ae3c73b022afa0824..fb4d27c8c8b3a5d1a8a8faa3d9088a2d204aa528 100644 (file)
@@ -20,7 +20,7 @@ main :: (args: [] cstr) {
     // Currently, there are no implicit procedure calls anywhere
     // in the language because I find explicitly specifying
     // everything to be less bug prone in the long run, at the
-    // trade off of being mildly tedious. Since there are implicit
+    // trade off of being mildly tedious. Since there aren't implicit
     // procedure calls, we have to initialize and free the dynamic
     // array explicitly. The 'defer' simply runs array.free at the
     // end of this procedure scope. We will talk more about how to
index b562d0595754553cb7c68e049613095fe7356c30..0d1acc55c1cbdb0124ce4e701d57f5adea4b9e4a 100644 (file)
@@ -73,7 +73,7 @@ main :: (args: [] cstr) {
 
     print_spacer();
 
-    // Structs in Onyx can behave like C unions, simply by usings the '#union' directive.
+    // Structs in Onyx can behave like C unions, simply by using the '#union' directive.
     FloatIntUnion :: struct #union {
         i : i32;
         f : f32;
index e3a570eccc8e539fe7c0db033e1bff6c5e1dcbe0..d4728cae5d81b57746e5ff740811a241bcf7d65d 100644 (file)
@@ -4,13 +4,14 @@ use package core
 
 main :: (args: [] cstr) {
     contents := #file_contents "./tests/aoc-2020/input/day1.txt";
+    reader := io.reader_from_string(contents);
 
     nums := array.make(u32, 128);
     defer array.free(^nums);
 
     while num := 1; num > 0 {
         // This sets num to be 0 if there is no number
-        string.read_u32(^contents, ^num); 
+        num = io.read_u32(^reader);
         if num != 0 do array.push(^nums, num);
     }
 
index 8e2be91bcb7099b1877720d4283defdd158f3760..1731a9121d199f7ab9e9fc60baf1371b24fe67f6 100644 (file)
@@ -6,22 +6,22 @@ use package core
 
 main :: (args: [] cstr) {
     contents := #file_contents "./tests/aoc-2020/input/day2.txt";
+    reader := io.reader_from_string(contents);
 
     valid := 0;
-    lo : u32;
-    hi : u32;
-    ch : u8;
-    pw := "";
 
     while true {
-        string.read_u32(^contents, ^lo);
+        lo := io.read_u32(^reader);
         if lo == 0 do break;
-        string.discard_chars(^contents);
-        string.read_u32(^contents, ^hi);
-        string.discard_chars(^contents);
-        string.read_char(^contents, ^ch);
-        string.discard_chars(^contents, 2);
-        string.read_line(^contents, ^pw);
+
+        io.read_byte(^reader);
+        hi := io.read_u32(^reader);
+
+        io.read_byte(^reader);
+        ch := io.read_byte(^reader);
+
+        io.skip_bytes(^reader, 2);
+        pw := io.read_line(^reader);
 
         // Part 1
         // count := 0;
index 29cab03d7ab791bad66a0f54f2880f67d7604df4..c1d99d90fad768ec2ab20393b2422ea750dcdbd8 100644 (file)
@@ -43,20 +43,20 @@ combat :: (player1: ^[..] u32, player2: ^[..] u32) -> u32 {
 //   4,5,2,8,|1,3,9,7,
 // Larger numbers are encoded in base 64.
 encode_hands :: (alloc: Allocator, p1: ^[..] u32, p2: ^[..] u32) -> str {
-    b :: package core.string.builder
+    stream := io.dynamic_string_stream_make(256, alloc);
+    writer := io.writer_make(^stream);
 
-    builder := b.make(256, alloc);
     for n: *p1 {
-        b.add_i64(^builder, ~~n, 64);
-        b.add_str(^builder, ",");
+        io.write_i64(^writer, ~~n, 64);
+        io.write_str(^writer, ",");
     }
-    b.add_str(^builder, "|");
+    io.write_str(^writer, "|");
     for n: *p2 {
-        b.add_i64(^builder, ~~n, 64);
-        b.add_str(^builder, ",");
+        io.write_i64(^writer, ~~n, 64);
+        io.write_str(^writer, ",");
     }
 
-    return b.to_str(^builder);
+    return io.dynamic_string_stream_to_str(^stream);
 }
 
 recursive_combat :: (player1: ^[..] u32, player2: ^[..] u32) -> u32 {