dynamic arrays have allocators now
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 13 Apr 2021 17:18:28 +0000 (12:18 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 13 Apr 2021 17:18:28 +0000 (12:18 -0500)
bin/onyx
core/array.onyx
core/io/stream.onyx
core/string/builder.onyx
include/onyxastnodes.h
src/onyxbuiltins.c
src/onyxtypes.c
src/onyxwasm.c
tests/aoc-2020/day20.onyx
tests/aoc-2020/day21.onyx

index 903d52710345b4d9ba9f9f0d656b1e35a854b3ce..2659edc1821c2a41c6594e663a15c256466cd5d0 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 562e3602a9c59b9001752f8c5ca43edb636cbefd..472c662a9b6e9a99853d0bc54b52d65db416456f 100644 (file)
@@ -3,38 +3,39 @@ package core.array
 // ---------------------------------
 //           Dynamic Arrays
 // ---------------------------------
-make :: ($T: type_expr, initial_cap := 4) -> [..] T {
+make :: ($T: type_expr, capacity := 4, allocator := context.allocator) -> [..] T {
     arr : [..] T;
-    init(^arr, initial_cap);
+    init(^arr, capacity, allocator);
     return arr;
 }
 
-init :: (arr: ^[..] $T, initial_cap := 4) {
+init :: (arr: ^[..] $T, capacity := 4, allocator := context.allocator) {
     arr.count = 0;
-    arr.capacity = initial_cap;
-    arr.data = calloc(sizeof T * arr.capacity);
+    arr.capacity = capacity;
+    arr.allocator = allocator;
+    arr.data = raw_alloc(allocator, sizeof T * arr.capacity);
 }
 
 free :: (arr: ^[..] $T) {
     arr.count = 0;
     arr.capacity = 0;
 
-    cfree(arr.data);
+    raw_free(arr.allocator, arr.data);
     arr.data = null;
 }
 
-copy :: (arr: ^[..] $T) -> [..] T {
+copy :: (arr: ^[..] $T, allocator := context.allocator) -> [..] T {
     new_arr : [..] T;
-    init(^new_arr, arr.count);
+    init(^new_arr, arr.count, allocator);
     new_arr.count = arr.count;
 
     for i: 0 .. arr.count do new_arr.data[i] = arr.data[i];
     return new_arr;
 }
 
-copy_range :: (arr: ^[..] $T, r: range) -> [..] T {
+copy_range :: (arr: ^[..] $T, r: range, allocator := context.allocator) -> [..] T {
     new_arr : [..] T;
-    init(^new_arr, r.high - r.low);
+    init(^new_arr, r.high - r.low, allocator);
     new_arr.count = r.high - r.low;
 
     for i: r do new_arr.data[i] = arr.data[i];
@@ -45,11 +46,11 @@ clear :: (arr: ^[..] $T) {
     arr.count = 0;
 }
 
-ensure_capacity :: (arr: ^[..] $T, cap: u32) -> bool {
-    if arr.capacity >= cap do return true;
+ensure_capacity :: (arr: ^[..] $T, capacity: u32) -> bool {
+    if arr.capacity >= capacity do return true;
 
-    while cap > arr.capacity do arr.capacity <<= 1;
-    new_data := cresize(arr.data, sizeof T * arr.capacity);
+    while capacity > arr.capacity do arr.capacity <<= 1;
+    new_data := raw_resize(arr.allocator, arr.data, sizeof T * arr.capacity);
     if new_data == null do return false;
     arr.data = new_data;
     return true;
index f3b036b8b3d57b29e5ab1ea8954685b6b276fbc5..f58d6249b0c71493e9fdade4d2a2b7d955bf9530 100644 (file)
@@ -250,12 +250,11 @@ DynamicStringStream :: struct {
 
     curr_pos : i32;
     data  : [..] u8;
-    alloc : Allocator;
 }
 
 dynamic_string_stream_make :: (init_size := 128, a := context.allocator) -> DynamicStringStream {
     data : [..] u8;
-    array.init(^data, init_size);
+    array.init(^data, init_size, allocator=a);
 
     return DynamicStringStream.{
         stream = Stream.{
@@ -264,7 +263,6 @@ dynamic_string_stream_make :: (init_size := 128, a := context.allocator) -> Dyna
 
         curr_pos = 0,
         data = data,
-        alloc = a,
     };
 }
 
@@ -283,10 +281,7 @@ dynamic_string_stream_vtable := Stream_Vtable.{
         }
 
         if dest >= data.count {
-            #context_scope {
-                context.allocator = alloc;
-                if !array.ensure_capacity(^data, dest) do return Error.OutOfBounds;
-            }
+            if !array.ensure_capacity(^data, dest) do return Error.OutOfBounds;
         }
 
         curr_pos = dest;
@@ -332,10 +327,7 @@ dynamic_string_stream_vtable := Stream_Vtable.{
 
     write = (use dss: ^DynamicStringStream, buffer: [] u8) -> (Error, u32) {
         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, 0;
-            }
+            if !array.ensure_capacity(^data, curr_pos + buffer.count) do return Error.EOF, 0;
         }
 
         memory.copy(^data.data[curr_pos], buffer.data, buffer.count);
@@ -347,10 +339,7 @@ dynamic_string_stream_vtable := Stream_Vtable.{
 
     write_at = (use dss: ^DynamicStringStream, at: u32, buffer: [] u8) -> (Error, u32) {
         if at + buffer.count >= data.capacity {
-            #context_scope {
-                context.allocator = alloc;
-                if !array.ensure_capacity(^data, at + buffer.count) do return Error.EOF, 0;
-            }
+            if !array.ensure_capacity(^data, at + buffer.count) do return Error.EOF, 0;
         }
 
         memory.copy(^data.data[at], buffer.data, buffer.count);
@@ -360,10 +349,7 @@ dynamic_string_stream_vtable := Stream_Vtable.{
     },
 
     write_byte = (use dss: ^DynamicStringStream, byte: u8) -> Error {
-        #context_scope {
-            context.allocator = alloc;
-            if !array.ensure_capacity(^data, data.count + 1) do return Error.EOF;
-        }
+        if !array.ensure_capacity(^data, data.count + 1) do return Error.EOF;
 
         data[curr_pos] = byte;
         curr_pos   += 1;
index 5cad46282f2615de24dfc64745607135394301ab..575a296e395f1a30eb47b1167a2921737a78433d 100644 (file)
@@ -8,18 +8,12 @@ use package core.string as string
 use package core.conv as conv
 
 Builder :: struct {
-    alloc : Allocator;
     data  : [..] u8;
 }
 
 make :: proc (initial_cap := 4, alloc := context.allocator) -> Builder {
     builder : Builder;
-    builder.alloc = alloc;
-
-    #context_scope {
-        context.allocator = alloc;
-        array.init(^builder.data, initial_cap);
-    }
+    array.init(^builder.data, initial_cap, allocator = alloc);
 
     return builder;
 }
@@ -32,8 +26,7 @@ clear :: proc (use sb: ^Builder) -> ^Builder {
 add_str :: proc (use sb: ^Builder, s: str) -> ^Builder {
     len_total := data.count + s.count;
 
-    if data.capacity < len_total do #context_scope {
-        context.allocator = alloc;
+    if data.capacity < len_total {
         if !array.ensure_capacity(^data, len_total) do return sb;
     }
 
index e256743f6e98304f04ee11682c422f25d5e38323..c010109ef537a73ad0d30eb07639f3e36985d3d4 100644 (file)
@@ -1115,6 +1115,7 @@ extern Type     *builtin_range_type_type;
 extern AstType  *builtin_vararg_type;
 extern Type     *builtin_vararg_type_type;
 extern AstTyped *builtin_context_variable;
+extern AstType  *builtin_allocator_type;
 
 typedef struct BuiltinSymbol {
     char*    package;
index f4c0ca28ad2ade16da5325e2ab28fd7e107789a5..37471aefe850830894e1086131c8a4a8eeff6f9f 100644 (file)
@@ -47,6 +47,7 @@ Type     *builtin_range_type_type;
 AstType  *builtin_vararg_type;
 Type     *builtin_vararg_type_type;
 AstTyped *builtin_context_variable;
+AstType  *builtin_allocator_type;
 
 const BuiltinSymbol builtin_symbols[] = {
     { NULL, "void",       (AstNode *) &basic_type_void },
@@ -370,6 +371,12 @@ void initialize_builtins(bh_allocator a) {
         return;
     }
 
+    builtin_allocator_type = (AstType *) symbol_raw_resolve(p->scope, "Allocator");
+    if (builtin_allocator_type == NULL) {
+        onyx_report_error((OnyxFilePos) { 0 }, "'Allocator' struct not found in builtin package.");
+        return;
+    }
+
     fori (i, 0, Binary_Op_Count) {
         bh_arr_new(global_heap_allocator, operator_overloads[i], 4); 
     }
index 18251cf673501a9bd392d7006dbd06775c6d39c3..7310b6f61214128599b1dbc513611375a9d3886a 100644 (file)
@@ -180,7 +180,7 @@ u32 type_size_of(Type* type) {
         case Type_Kind_Enum:     return type_size_of(type->Enum.backing);
         case Type_Kind_Slice:    return 16; // HACK: These should not have to be 16 bytes in size, they should only have to be 12,
         case Type_Kind_VarArgs:  return 16; // but there are alignment issues right now with that so I decided to not fight it and just make them 16 bytes in size.
-        case Type_Kind_DynArray: return 16;
+        case Type_Kind_DynArray: return 32; // data (8), count (4), capacity (4), allocator { func (4), ---(4), data (8) }
         case Type_Kind_Compound: return type->Compound.size;
         default:                 return 0;
     }
@@ -743,12 +743,21 @@ u32 type_get_alignment_log2(Type* type) {
     return 2;
 }
 
+static const StructMember slice_members[] = {
+    { 0, 0, NULL,                         "data",  NULL, 0, 0 },
+    { 8, 1, &basic_types[Basic_Kind_U32], "count", NULL, 0, 0 },
+};
+
+static const StructMember array_members[] = {
+    { 0,  0, NULL,                         "data",      NULL, 0, 0 },
+    { 8,  1, &basic_types[Basic_Kind_U32], "count",     NULL, 0, 0 },
+    { 12, 2, &basic_types[Basic_Kind_U32], "capacity",  NULL, 0, 0 },
+    { 16, 3, NULL,                         "allocator", NULL, 0, 0 },
+};
+
 b32 type_lookup_member(Type* type, char* member, StructMember* smem) {
     if (type->kind == Type_Kind_Pointer) type = type->Pointer.elem;
 
-    smem->initial_value = NULL;
-    smem->included_through_use = 0;
-
     switch (type->kind) {
         case Type_Kind_Struct: {
             TypeStruct* stype = &type->Struct;
@@ -760,46 +769,28 @@ b32 type_lookup_member(Type* type, char* member, StructMember* smem) {
 
         case Type_Kind_VarArgs:
         case Type_Kind_Slice: {
-            if (strcmp(member, "data") == 0) {
-                smem->idx = 0;
-                smem->offset = 0;
-                smem->type = type->Slice.ptr_to_data;
-                smem->name = "data";
-                return 1;
-            }
-            if (strcmp(member, "count") == 0) {
-                smem->idx = 1;
-                smem->offset = 8;
-                smem->type = &basic_types[Basic_Kind_U32];
-                smem->name = "count";
-                return 1;
-            }
+            fori (i, 0, (i64) (sizeof(slice_members) / sizeof(StructMember))) {
+                if (strcmp(slice_members[i].name, member) == 0) {
+                    *smem = slice_members[i];
+                    if (smem->idx == 0) smem->type = type->Slice.ptr_to_data;
 
+                    return 1;
+                }
+            }
             return 0;
         }
 
         case Type_Kind_DynArray: {
-            if (strcmp(member, "data") == 0) {
-                smem->idx = 0;
-                smem->offset = 0;
-                smem->type = type->DynArray.ptr_to_data;
-                smem->name = "data";
-                return 1;
-            }
-            if (strcmp(member, "count") == 0) {
-                smem->idx = 1;
-                smem->offset = 8;
-                smem->type = &basic_types[Basic_Kind_U32];
-                smem->name = "count";
-                return 1;
-            }
-            if (strcmp(member, "capacity") == 0) {
-                smem->idx = 2;
-                smem->offset = 12;
-                smem->type = &basic_types[Basic_Kind_U32];
-                smem->name = "capacity";
-                return 1;
+            fori (i, 0, (i64) (sizeof(array_members) / sizeof(StructMember))) {
+                if (strcmp(array_members[i].name, member) == 0) {
+                    *smem = array_members[i];
+                    if (smem->idx == 0) smem->type = type->DynArray.ptr_to_data;
+                    if (smem->idx == 3) smem->type = type_build_from_ast(context.ast_alloc, builtin_allocator_type);
+
+                    return 1;
+                }
             }
+            return 0;
         }
 
         default: return 0;
@@ -822,46 +813,22 @@ b32 type_lookup_member_by_idx(Type* type, i32 idx, StructMember* smem) {
         // are identical.                       - brendanfh   2020/09/07
         case Type_Kind_VarArgs:
         case Type_Kind_Slice: {
-            if (idx == 0) {
-                smem->idx = 0;
-                smem->offset = 0;
-                smem->type = type->Slice.ptr_to_data;
-                smem->name = "data";
-                return 1;
-            }
-            if (idx == 1) {
-                smem->idx = 1;
-                smem->offset = 8;
-                smem->type = &basic_types[Basic_Kind_U32];
-                smem->name = "count";
-                return 1;
-            }
+            if (idx > 2) return 0;
 
-            return 0;
+            *smem = slice_members[idx];
+            if (smem->idx == 0) smem->type = type->Slice.ptr_to_data;
+
+            return 1;
         }
 
         case Type_Kind_DynArray: {
-            if (idx == 0) {
-                smem->idx = 0;
-                smem->offset = 0;
-                smem->type = type->DynArray.ptr_to_data;
-                smem->name = "data";
-                return 1;
-            }
-            if (idx == 1) {
-                smem->idx = 1;
-                smem->offset = 8;
-                smem->type = &basic_types[Basic_Kind_U32];
-                smem->name = "count";
-                return 1;
-            }
-            if (idx == 2) {
-                smem->idx = 2;
-                smem->offset = 12;
-                smem->type = &basic_types[Basic_Kind_U32];
-                smem->name = "capacity";
-                return 1;
-            }
+            if (idx > 4) return 0;
+
+            *smem = array_members[idx];
+            if (idx == 0) smem->type = type->DynArray.ptr_to_data;
+            if (idx == 3) smem->type = type_build_from_ast(context.ast_alloc, builtin_allocator_type);
+
+            return 1;
         }
 
         default: return 0;
@@ -872,7 +839,7 @@ i32 type_linear_member_count(Type* type) {
     switch (type->kind) {
         case Type_Kind_Slice:
         case Type_Kind_VarArgs:  return 2;
-        case Type_Kind_DynArray: return 3;
+        case Type_Kind_DynArray: return 5;
         case Type_Kind_Compound: return bh_arr_length(type->Compound.linear_members);
         case Type_Kind_Struct:   return bh_arr_length(type->Struct.linear_members);
         default: return 0; 
@@ -907,6 +874,11 @@ b32 type_linear_member_lookup(Type* type, i32 idx, TypeWithOffset* two) {
                 two->type = &basic_types[Basic_Kind_U32];
                 two->offset = 12;
             }
+            if (idx == 3 || idx == 4) {
+                Type* allocator_type = type_build_from_ast(context.ast_alloc, builtin_allocator_type);
+                type_linear_member_lookup(allocator_type, idx - 3, two);
+                two->offset += 16;
+            }
 
             return 1;
         }
@@ -1029,7 +1001,7 @@ u32 type_structlike_mem_count(Type* type) {
         case Type_Kind_Struct:   return type->Struct.mem_count;
         case Type_Kind_Slice:    return 2;
         case Type_Kind_VarArgs:  return 2;
-        case Type_Kind_DynArray: return 3;
+        case Type_Kind_DynArray: return 4;
         default: return 0;
     }
 }
@@ -1039,7 +1011,7 @@ u32 type_structlike_is_simple(Type* type) {
         case Type_Kind_Struct:   return type_struct_is_simple(type);
         case Type_Kind_Slice:    return 1;
         case Type_Kind_VarArgs:  return 1;
-        case Type_Kind_DynArray: return 1;
+        case Type_Kind_DynArray: return 0;
         default: return 0;
     }
 }
index ac679c83176de9147897fa53d0c057b0f1650bba..147685cca7fb553a2b68e9bae45555b334c6befc 100644 (file)
@@ -898,10 +898,11 @@ EMIT_FUNC(for, AstFor* for_node) {
     switch (for_node->loop_type) {
         case For_Loop_Range:  emit_for_range(mod, &code, for_node, iter_local); break;
         case For_Loop_Array:  emit_for_array(mod, &code, for_node, iter_local); break;
-        // NOTE: A dynamic array is just a slice with an extra capacity field on the end.
-        // Just dropping the capacity field will mean we can just use the slice implementation.
+        // NOTE: A dynamic array is just a slice with a capacity and allocator on the end.
+        // Just dropping the extra fields will mean we can just use the slice implementation.
         //                                                  - brendanfh   2020/09/04
-        case For_Loop_DynArr: WI(WI_DROP);
+        //                                                  - brendanfh   2021/04/13
+        case For_Loop_DynArr: WI(WI_DROP); WI(WI_DROP); WI(WI_DROP);
         case For_Loop_Slice:  emit_for_slice(mod, &code, for_node, iter_local); break;
         default: onyx_report_error(for_node->token->pos, "Invalid for loop type. You should probably not be seeing this...");
     }
index e1e8c1106aff9775ffb235db8100b28595ced710..806e44a06a6f07a5819a2f9e96b0d2a11e0dfa84 100644 (file)
@@ -67,10 +67,7 @@ reverse_binary :: (n_: u32, digits := TILE_DATA_WIDTH) -> u32 {
 
 build_edges :: (tile: [] bool, a := context.allocator) -> [] u32 {
        edges : [..] u32;
-       #context_scope {
-               context.allocator = a;
-               array.init(^edges, 8);
-       }
+    array.init(^edges, 8, allocator=a);
 
        for y: u32.[0, 9] {
                edge := 0;
index dc27e090ef611183bc3aa2cec14ebda506add732..8c6ad0ccfb5cb973188ff40954c63dcaa54d520e 100644 (file)
@@ -13,14 +13,14 @@ use package core.string.reader as reader
 Ingredient :: struct {
     // This will just be a pointer into the file contents.
     name       : str      = .{ null, 0 };
-    appears_on : [..] u32 = .{ null, 0, 0 };
+    appears_on : [..] u32 = .{ null, 0, 0, .{ null, null_proc } };
 
     allergen   : str      = .{ null, 0 };
 }
 
 Allergen :: struct {
        name       : str      = .{ null, 0 };
-    appears_on : [..] u32 = .{ null, 0, 0 };
+    appears_on : [..] u32 = .{ null, 0, 0, .{ null, null_proc } };
 }
 
 Food :: struct {