From: Brendan Hansen Date: Tue, 13 Apr 2021 17:18:28 +0000 (-0500) Subject: dynamic arrays have allocators now X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=d34f2b5dba58ece65872d067d08ef3895666f143;p=onyx.git dynamic arrays have allocators now --- diff --git a/bin/onyx b/bin/onyx index 903d5271..2659edc1 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/core/array.onyx b/core/array.onyx index 562e3602..472c662a 100644 --- a/core/array.onyx +++ b/core/array.onyx @@ -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; diff --git a/core/io/stream.onyx b/core/io/stream.onyx index f3b036b8..f58d6249 100644 --- a/core/io/stream.onyx +++ b/core/io/stream.onyx @@ -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; diff --git a/core/string/builder.onyx b/core/string/builder.onyx index 5cad4628..575a296e 100644 --- a/core/string/builder.onyx +++ b/core/string/builder.onyx @@ -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; } diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index e256743f..c010109e 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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; diff --git a/src/onyxbuiltins.c b/src/onyxbuiltins.c index f4c0ca28..37471aef 100644 --- a/src/onyxbuiltins.c +++ b/src/onyxbuiltins.c @@ -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); } diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 18251cf6..7310b6f6 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -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; } } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index ac679c83..147685cc 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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..."); } diff --git a/tests/aoc-2020/day20.onyx b/tests/aoc-2020/day20.onyx index e1e8c110..806e44a0 100644 --- a/tests/aoc-2020/day20.onyx +++ b/tests/aoc-2020/day20.onyx @@ -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; diff --git a/tests/aoc-2020/day21.onyx b/tests/aoc-2020/day21.onyx index dc27e090..8c6ad0cc 100644 --- a/tests/aoc-2020/day21.onyx +++ b/tests/aoc-2020/day21.onyx @@ -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 {