Variadic append

This commit is contained in:
Ginger Bill
2017-01-29 20:48:08 +00:00
parent 984e36a151
commit 43be91bca3
5 changed files with 105 additions and 44 deletions
+1 -6
View File
@@ -14,12 +14,7 @@ main :: proc() {
defer free(array); defer free(array);
reserve(^array, 10); reserve(^array, 10);
append(^array, 2); append(^array, 2, 3, 5, 7, 11, 13);
append(^array, 3);
append(^array, 5);
append(^array, 7);
append(^array, 11);
append(^array, 13);
for val, idx in array { for val, idx in array {
fmt.println(val, idx); fmt.println(val, idx);
} }
+8 -6
View File
@@ -352,20 +352,22 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capa
} }
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, item_ptr: rawptr) { __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int) -> int {
array := cast(^Raw_Dynamic_Array)array_; array := cast(^Raw_Dynamic_Array)array_;
ok := true; ok := true;
if array.data == nil || array.capacity <= array.count { if array.data == nil || array.capacity <= array.count+item_count {
capacity := 2 * array.capacity + 8; capacity := 2 * array.capacity + max(8, item_count);
ok := __dynamic_array_reserve(array, elem_size, elem_align, capacity); ok := __dynamic_array_reserve(array, elem_size, elem_align, capacity);
} }
if !ok { if !ok {
// TODO(bill): Better error handling for failed reservation // TODO(bill): Better error handling for failed reservation
return; return array.count;
} }
data := cast(^byte)array.data; data := cast(^byte)array.data;
assert(data != nil); assert(data != nil);
mem.copy(data + (elem_size*array.count), item_ptr, elem_size); mem.copy(data + (elem_size*array.count), items, elem_size * item_count);
array.count += 1; array.count += item_count;
return array.count;
} }
+20 -19
View File
@@ -19,6 +19,7 @@ void check_stmt (Checker *c, AstNode *node, u32 flags);
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags); void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
void check_init_constant (Checker *c, Entity *e, Operand *operand); void check_init_constant (Checker *c, Entity *e, Operand *operand);
bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
Type * check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call);
gb_inline Type *check_type(Checker *c, AstNode *expression) { gb_inline Type *check_type(Checker *c, AstNode *expression) {
@@ -2598,6 +2599,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
} }
} }
Operand prev_operand = *operand;
switch (id) { switch (id) {
case BuiltinProc_new: case BuiltinProc_new:
case BuiltinProc_new_slice: case BuiltinProc_new_slice:
@@ -2715,7 +2718,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
} break; } break;
case BuiltinProc_append: { case BuiltinProc_append: {
// append :: proc(^[dynamic]Type, item: Type) { // append :: proc(^[dynamic]Type, item: ...Type) {
Type *type = operand->type; Type *type = operand->type;
if (!is_type_pointer(type)) { if (!is_type_pointer(type)) {
gbString str = type_to_string(type); gbString str = type_to_string(type);
@@ -2730,27 +2733,25 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
gb_string_free(str); gb_string_free(str);
return false; return false;
} }
// TODO(bill): Semi-memory leaks
Type *elem = type->DynamicArray.elem; Type *elem = type->DynamicArray.elem;
Type *slice_elem = make_type_slice(c->allocator, elem);
Type *proc_type_params = make_type_tuple(c->allocator);
proc_type_params->Tuple.variables = gb_alloc_array(c->allocator, Entity *, 2);
proc_type_params->Tuple.variable_count = 2;
proc_type_params->Tuple.variables[0] = make_entity_param(c->allocator, NULL, blank_token, operand->type, false, false);
proc_type_params->Tuple.variables[1] = make_entity_param(c->allocator, NULL, blank_token, slice_elem, false, false);
Type *proc_type = make_type_proc(c->allocator, NULL, proc_type_params, 2, NULL, false, true, ProcCC_Odin);
AstNode *item = ce->args.e[1]; check_call_arguments(c, &prev_operand, proc_type, call);
Operand op = {0};
check_expr(c, &op, item); if (prev_operand.mode == Addressing_Invalid) {
if (op.mode == Addressing_Invalid) {
return false; return false;
} }
Type *arg_type = op.type; operand->mode = Addressing_Value;
if (!check_is_assignable_to(c, &op, elem)) { operand->type = t_int;
gbString elem_str = type_to_string(elem);
gbString str = type_to_string(arg_type);
error_node(operand->expr, "Expected `%s` for `append` item, got `%s`", elem_str, str);
gb_string_free(str);
gb_string_free(elem_str);
return false;
}
operand->type = NULL;
operand->mode = Addressing_NoValue;
} break; } break;
@@ -3284,7 +3285,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
return false; return false;
} }
if (!are_types_identical(operand->type, b.type)) { if (!are_types_identical(a.type, b.type)) {
gbString type_a = type_to_string(a.type); gbString type_a = type_to_string(a.type);
gbString type_b = type_to_string(b.type); gbString type_b = type_to_string(b.type);
error_node(call, error_node(call,
@@ -3352,7 +3353,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
return false; return false;
} }
if (!are_types_identical(operand->type, b.type)) { if (!are_types_identical(a.type, b.type)) {
gbString type_a = type_to_string(a.type); gbString type_a = type_to_string(a.type);
gbString type_b = type_to_string(b.type); gbString type_b = type_to_string(b.type);
error_node(call, error_node(call,
+1 -1
View File
@@ -173,7 +173,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT("free"), 1, false, Expr_Stmt}, {STR_LIT("free"), 1, false, Expr_Stmt},
{STR_LIT("reserve"), 2, false, Expr_Stmt}, {STR_LIT("reserve"), 2, false, Expr_Stmt},
{STR_LIT("append"), 2, false, Expr_Stmt}, {STR_LIT("append"), 1, true, Expr_Expr},
{STR_LIT("size_of"), 1, false, Expr_Expr}, {STR_LIT("size_of"), 1, false, Expr_Expr},
{STR_LIT("size_of_val"), 1, false, Expr_Expr}, {STR_LIT("size_of_val"), 1, false, Expr_Expr},
+75 -12
View File
@@ -3025,23 +3025,86 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
GB_ASSERT(is_type_pointer(type)); GB_ASSERT(is_type_pointer(type));
type = base_type(type_deref(type)); type = base_type(type_deref(type));
GB_ASSERT(is_type_dynamic_array(type)); GB_ASSERT(is_type_dynamic_array(type));
Type *elem = type->DynamicArray.elem; Type *elem_type = type->DynamicArray.elem;
irValue *elem_size = ir_make_const_int(a, type_size_of(proc->module->sizes, a, elem)); irValue *elem_size = ir_make_const_int(a, type_size_of(proc->module->sizes, a, elem_type));
irValue *elem_align = ir_make_const_int(a, type_align_of(proc->module->sizes, a, elem)); irValue *elem_align = ir_make_const_int(a, type_align_of(proc->module->sizes, a, elem_type));
array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr); array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr);
irValue *item_ptr = ir_add_local_generated(proc, elem); isize arg_index = 0;
irValue *item = ir_build_expr(proc, ce->args.e[1]); isize arg_count = 0;
ir_emit_store(proc, item_ptr, item); for_array(i, ce->args) {
if (i == 0) {
continue;
}
AstNode *a = ce->args.e[i];
Type *at = base_type(type_of_expr(proc->module->info, a));
if (at->kind == Type_Tuple) {
arg_count += at->Tuple.variable_count;
} else {
arg_count++;
}
}
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count);
bool vari_expand = ce->ellipsis.pos.line != 0;
irValue **args = gb_alloc_array(a, irValue *, 4); for_array(i, ce->args) {
args[0] = array_ptr; irValue *a = ir_build_expr(proc, ce->args.e[i]);
args[1] = elem_size; Type *at = ir_type(a);
args[2] = elem_align; if (at->kind == Type_Tuple) {
args[3] = ir_emit_conv(proc, item_ptr, t_rawptr); for (isize i = 0; i < at->Tuple.variable_count; i++) {
return ir_emit_global_call(proc, "__dynamic_array_append", args, 4); Entity *e = at->Tuple.variables[i];
irValue *v = ir_emit_struct_ev(proc, a, i);
args[arg_index++] = v;
}
} else {
args[arg_index++] = a;
}
}
if (!vari_expand) {
for (isize i = 1; i < arg_count; i++) {
args[i] = ir_emit_conv(proc, args[i], elem_type);
}
}
if (!vari_expand) {
ir_emit_comment(proc, str_lit("variadic call argument generation"));
Type *slice_type = make_type_slice(a, elem_type);
irValue *slice = ir_add_local_generated(proc, slice_type);
isize slice_len = arg_count-1;
if (slice_len > 0) {
irValue *base_array = ir_add_local_generated(proc, make_type_array(a, elem_type, slice_len));
for (isize i = 1, j = 0; i < arg_count; i++, j++) {
irValue *addr = ir_emit_array_epi(proc, base_array, j);
ir_emit_store(proc, addr, args[i]);
}
irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
irValue *slice_elem = ir_emit_struct_ep(proc, slice, 0);
ir_emit_store(proc, slice_elem, base_elem);
irValue *len = ir_make_const_int(a, slice_len);
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len);
}
arg_count = 2;
args[arg_count-1] = ir_emit_load(proc, slice);
}
irValue *item_slice = args[1];
irValue *items = ir_slice_elem(proc, item_slice);
irValue *item_count = ir_slice_count(proc, item_slice);
irValue **daa_args = gb_alloc_array(a, irValue *, 5);
daa_args[0] = array_ptr;
daa_args[1] = elem_size;
daa_args[2] = elem_align;
daa_args[3] = ir_emit_conv(proc, items, t_rawptr);
daa_args[4] = ir_emit_conv(proc, item_count, t_int);
return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5);
} break; } break;