diff --git a/code/demo.odin b/code/demo.odin index e3e85769c..bc193ef1f 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -9,16 +9,45 @@ #import "utf8.odin"; #import ht "http_test.odin"; - main :: proc() { - Value :: type f32; - m: map[int]Value; - reserve(^m, 16); - defer free(m); - // m[123] = 345.0; - if x, ok := m[123]; ok { - fmt.println(x); + { + m: map[f32]int; + reserve(^m, 16); + defer free(m); + + m[1.0] = 1278; + m[2.0] = 7643; + m[3.0] = 564; + c := m[3.0]; + _, ok := m[3.0]; + // assert(ok && c == 564); + + fmt.print("map["); + i := 0; + for val, key in m { + if i > 0 { + fmt.print(", "); + } + fmt.printf("%f=%v", key, val); + i += 1; + } + fmt.println("]"); } + { + m := map[string]u32{ + "a" = 56, + "b" = 13453, + "c" = 7654, + }; + defer free(m); + + c := m["c"]; + _, ok := m["c"]; + assert(ok && c == 7654); + + fmt.println(m); + } + // fm: map[128, int]f32; diff --git a/core/_preload.odin b/core/_preload.odin index 18a7a4438..1eb8a2d06 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -20,11 +20,12 @@ Type_Info_Member :: struct #ordered { offset: int, // offsets are not used in tuples } Type_Info_Record :: struct #ordered { - fields: []Type_Info_Member, - size: int, // in bytes - align: int, // in bytes - packed: bool, - ordered: bool, + fields: []Type_Info_Member, + size: int, // in bytes + align: int, // in bytes + packed: bool, + ordered: bool, + custom_align: bool, } Type_Info_Enum_Value :: raw_union { f: f64, @@ -90,10 +91,16 @@ Type_Info :: union { Union: Type_Info_Record, Raw_Union: Type_Info_Record, Enum: struct #ordered { - base: ^Type_Info, - names: []string, + base: ^Type_Info, + names: []string, values: []Type_Info_Enum_Value, }, + Map: struct #ordered { + key: ^Type_Info, + value: ^Type_Info, + generated_struct: ^Type_Info, + count: int, // == 0 if dynamic + }, } // // NOTE(bill): only the ones that are needed (not all types) @@ -113,6 +120,21 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { } +type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info { + if info == nil { + return nil; + } + base := info; + match type i in base { + case Type_Info.Named: + base = i.base; + case Type_Info.Enum: + base = i.base; + } + return base; +} + + assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume"; @@ -438,29 +460,32 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in __default_hash :: proc(data: []byte) -> u64 { - return hash.murmur64(data); + return hash.fnv64a(data); +} +__default_hash_string :: proc(s: string) -> u64 { + return __default_hash(cast([]byte)s); } -Map_Key :: struct #ordered { +__Map_Key :: struct #ordered { hash: u64, str: string, } -Map_Find_Result :: struct #ordered { +__Map_Find_Result :: struct #ordered { hash_index: int, entry_prev: int, entry_index: int, } -Map_Entry_Header :: struct #ordered { - key: Map_Key, +__Map_Entry_Header :: struct #ordered { + key: __Map_Key, next: int, /* value: Value_Type, */ } -Map_Header :: struct #ordered { +__Map_Header :: struct #ordered { m: ^Raw_Dynamic_Map, is_key_string: bool, entry_size: int, @@ -468,13 +493,13 @@ Map_Header :: struct #ordered { value_offset: int, } -__dynamic_map_reserve :: proc(using header: Map_Header, capacity: int) -> bool { +__dynamic_map_reserve :: proc(using header: __Map_Header, capacity: int) -> bool { h := __dynamic_array_reserve(^m.hashes, size_of(int), align_of(int), capacity); e := __dynamic_array_reserve(^m.entries, entry_size, entry_align, capacity); return h && e; } -__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int) { +__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { new_header := header; nm: Raw_Dynamic_Map; new_header.m = ^nm; @@ -511,25 +536,27 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int) { __dynamic_map_grow(new_header); } } - free(header.m); + free_ptr_with_allocator(header.m.hashes.allocator, header.m.hashes.data); + free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data); header.m^ = nm; - } -__dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr { +__dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr { index := __dynamic_map_find(h, key).entry_index; if index >= 0 { data := cast(^byte)__dynamic_map_get_entry(h, index); - return data + h.value_offset; + val := data + h.value_offset; + return val; } return nil; } -__dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) { +__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) { + index: int; + if m.hashes.count == 0 { __dynamic_map_grow(h); } - index: int; fr := __dynamic_map_find(h, key); if fr.entry_index >= 0 { index = fr.entry_index; @@ -544,7 +571,8 @@ __dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) { } { data := cast(^byte)__dynamic_map_get_entry(h, index); - mem.copy(data+value_offset, value, entry_size-value_offset); + val := data+value_offset; + mem.copy(val, value, entry_size-value_offset); } if __dynamic_map_full(h) { @@ -553,17 +581,17 @@ __dynamic_map_set :: proc(using h: Map_Header, key: Map_Key, value: rawptr) { } -__dynamic_map_grow :: proc(using h: Map_Header) { +__dynamic_map_grow :: proc(using h: __Map_Header) { new_count := 2*m.entries.count + 8; __dynamic_map_rehash(h, new_count); } -__dynamic_map_full :: proc(using h: Map_Header) -> bool { +__dynamic_map_full :: proc(using h: __Map_Header) -> bool { return cast(int)(0.75 * cast(f64)m.hashes.count) <= m.entries.count; } -__dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool { +__dynamic_map_hash_equal :: proc(h: __Map_Header, a, b: __Map_Key) -> bool { if a.hash == b.hash { if h.is_key_string { return a.str == b.str; @@ -573,8 +601,8 @@ __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool { return false; } -__dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result { - fr := Map_Find_Result{-1, -1, -1}; +__dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_Result { + fr := __Map_Find_Result{-1, -1, -1}; if m.hashes.count > 0 { fr.hash_index = cast(int)(key.hash % cast(u64)m.hashes.count); fr.entry_index = m.hashes[fr.hash_index]; @@ -590,7 +618,7 @@ __dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result return fr; } -__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key) -> int { +__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int { prev := m.entries.count; c := __dynamic_array_append_nothing(^m.entries, entry_size, entry_align); if c != prev { @@ -598,23 +626,23 @@ __dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key) -> int { end.key = key; end.next = -1; } - return c; + return prev; } -__dynamic_map_remove :: proc(using h: Map_Header, key: Map_Key) { +__dynamic_map_remove :: proc(using h: __Map_Header, key: __Map_Key) { fr := __dynamic_map_find(h, key); if fr.entry_index >= 0 { __dynamic_map_erase(h, fr); } } -__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header { +__dynamic_map_get_entry :: proc(using h: __Map_Header, index: int) -> ^__Map_Entry_Header { data := cast(^byte)m.entries.data + index*entry_size; - return cast(^Map_Entry_Header)data; + return cast(^__Map_Entry_Header)data; } -__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) { +__dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) { if fr.entry_prev < 0 { m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next; } else { diff --git a/core/fmt.odin b/core/fmt.odin index 1de2c2293..91519167b 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -142,10 +142,13 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { if info.params == nil { buffer_write_string(buf, "()"); } else { - count := (cast(^Tuple)info.params).fields.count; - if count == 1 { buffer_write_string(buf, "("); } - buffer_write_type(buf, info.params); - if count == 1 { buffer_write_string(buf, ")"); } + fields := (cast(^Tuple)info.params).fields; + buffer_write_string(buf, "("); + for f, i in fields { + if i > 0 { buffer_write_string(buf, ", "); } + buffer_write_type(buf, f.type_info); + } + buffer_write_string(buf, ")"); } if info.results != nil { buffer_write_string(buf, " -> "); @@ -188,18 +191,30 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { buffer_write_string(buf, "]"); buffer_write_type(buf, info.elem); + case Map: + buffer_write_string(buf, "map["); + buffer_write_type(buf, info.key); + buffer_write_byte(buf, ']'); + buffer_write_type(buf, info.value); + case Struct: buffer_write_string(buf, "struct "); if info.packed { buffer_write_string(buf, "#packed "); } if info.ordered { buffer_write_string(buf, "#ordered "); } - buffer_write_string(buf, "{"); + if info.custom_align { + buffer_write_string(buf, "#align "); + fi := Fmt_Info{buf = buf}; + fmt_int(^fi, cast(u64)info.align, false, 'd'); + buffer_write_byte(buf, ' '); + } + buffer_write_byte(buf, '{'); for field, i in info.fields { buffer_write_string(buf, field.name); buffer_write_string(buf, ": "); buffer_write_type(buf, field.type_info); buffer_write_byte(buf, ','); } - buffer_write_string(buf, "}"); + buffer_write_byte(buf, '}'); case Union: buffer_write_string(buf, "union {"); @@ -775,6 +790,39 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v'); } + case Map: + if verb != 'v' { + fmt_bad_verb(fi, verb); + return; + } + + buffer_write_string(fi.buf, "map["); + defer buffer_write_byte(fi.buf, ']'); + entries := ^(cast(^Raw_Dynamic_Map)v.data).entries; + gs, _ := union_cast(^Struct)info.generated_struct; + ed, _ := union_cast(^Dynamic_Array)gs.fields[1].type_info; + entry_type, _ := union_cast(^Struct)ed.elem; + entry_size := ed.elem_size; + for i in 0.. 0 { + buffer_write_string(fi.buf, ", "); + } + data := cast(^byte)entries.data + i*entry_size; + + header := cast(^__Map_Entry_Header)data; + if types.is_string(info.key) { + buffer_write_string(fi.buf, header.key.str); + } else { + fi := Fmt_Info{buf = fi.buf}; + fmt_arg(^fi, any{info.key, cast(rawptr)^header.key.hash}, 'v'); + } + + buffer_write_string(fi.buf, "="); + + value := data + entry_type.fields[2].offset; + fmt_arg(fi, any{info.value, cast(rawptr)value}, 'v'); + } + case Slice: if verb != 'v' { fmt_bad_verb(fi, verb); diff --git a/src/check_decl.c b/src/check_decl.c index 1cbfcacc6..b690799af 100644 --- a/src/check_decl.c +++ b/src/check_decl.c @@ -63,7 +63,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra // an extra allocation ArrayOperand operands = {0}; array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count); - check_unpack_arguments(c, &operands, inits); + check_unpack_arguments(c, lhs_count, &operands, inits, true); isize rhs_count = operands.count; for_array(i, operands) { diff --git a/src/check_expr.c b/src/check_expr.c index 55563cb2d..04f246532 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1097,8 +1097,8 @@ Type *make_map_tuple_type(gbAllocator a, Type *value) { Type *t = make_type_tuple(a); t->Tuple.variables = gb_alloc_array(a, Entity *, 2); t->Tuple.variable_count = 2; - t->Tuple.variables[0] = make_entity_param(a, NULL, blank_token, value, false, false); - t->Tuple.variables[1] = make_entity_param(a, NULL, blank_token, t_bool, false, false); + t->Tuple.variables[0] = make_entity_field(a, NULL, blank_token, value, false, 0); + t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, t_bool, false, 1); return t; } @@ -1132,11 +1132,17 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { gbAllocator a = c->allocator; { + // NOTE(bill): The preload types may have not been set yet + if (t_map_key == NULL) { + init_preload(c); + } + GB_ASSERT(t_map_key != NULL); + Type *entry_type = make_type_struct(a); /* struct { - hash: u64, + hash: Map_Key, next: int, key: Key_Type, value: Value_Type, @@ -1148,9 +1154,9 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { isize field_count = 3; Entity **fields = gb_alloc_array(a, Entity *, field_count); - fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")), t_u64, false, false); - fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("next")), t_int, false, false); - fields[2] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("value")), value, false, false); + fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("key")), t_map_key, false, 0); + fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("next")), t_int, false, 1); + fields[2] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("value")), value, false, 2); check_close_scope(c); @@ -1159,7 +1165,6 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { entry_type->Record.field_count = field_count; type_set_offsets(c->sizes, a, entry_type); - type->Map.entry_type = entry_type; } @@ -1181,8 +1186,8 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { isize field_count = 2; Entity **fields = gb_alloc_array(a, Entity *, field_count); - fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("hashes")), hashes_type, false, false); - fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("entries")), entries_type, false, false); + fields[0] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("hashes")), hashes_type, false, 0); + fields[1] = make_entity_field(a, c->context.scope, make_token_ident(str_lit("entries")), entries_type, false, 1); check_close_scope(c); @@ -1191,7 +1196,6 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { generated_struct_type->Record.field_count = field_count; type_set_offsets(c->sizes, a, generated_struct_type); - type->Map.generated_struct_type = generated_struct_type; } @@ -2676,7 +2680,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h gbString op_str = expr_to_string(op_expr); gbString type_str = type_to_string(operand->type); gbString sel_str = expr_to_string(selector); - error_node(op_expr, "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str); + error_node(op_expr, "`%s` of type `%s` has no field `%s`", op_str, type_str, sel_str); gb_string_free(sel_str); gb_string_free(type_str); gb_string_free(op_str); @@ -2885,14 +2889,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id Type *type = operand->type; if (!is_type_pointer(type)) { gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str); + error_node(operand->expr, "Expected a pointer, got `%s`", str); gb_string_free(str); return false; } type = type_deref(type); - if (!is_type_dynamic_array(type)) { + if (!is_type_dynamic_array(type) && !is_type_map(type)) { gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str); + error_node(operand->expr, "Expected a pointer to a map or dynamic array, got `%s`", str); gb_string_free(str); return false; } @@ -3824,18 +3828,28 @@ int valid_proc_and_score_cmp(void const *a, void const *b) { typedef Array(Operand) ArrayOperand; -void check_unpack_arguments(Checker *c, ArrayOperand *operands, AstNodeArray args) { +void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray args, bool allow_map_ok) { for_array(i, args) { Operand o = {0}; check_multi_expr(c, &o, args.e[i]); - if (o.mode == Addressing_MapIndex) { - Type *tuple_type = make_map_tuple_type(c->allocator, o.type); - add_type_and_value(&c->info, o.expr, o.mode, tuple_type, (ExactValue){0}); - o.type = tuple_type; - } - if (o.type == NULL || o.type->kind != Type_Tuple) { + if (o.mode == Addressing_MapIndex && + allow_map_ok && + lhs_count == 2 && + args.count == 1) { + Type *tuple = make_map_tuple_type(c->allocator, o.type); + add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value); + + Operand val = o; + Operand ok = o; + val.mode = Addressing_Value; + ok.mode = Addressing_Value; + ok.type = t_bool; + array_add(operands, val); + array_add(operands, ok); + continue; + } array_add(operands, o); } else { TypeTuple *tuple = &o.type->Tuple; @@ -3854,7 +3868,7 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod ArrayOperand operands; array_init_reserve(&operands, heap_allocator(), 2*ce->args.count); - check_unpack_arguments(c, &operands, ce->args); + check_unpack_arguments(c, -1, &operands, ce->args, false); if (operand->mode == Addressing_Overload) { GB_ASSERT(operand->overload_entities != NULL && @@ -4740,6 +4754,31 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } } break; + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + is_constant = false; + { // Checker values + for_array(i, cl->elems) { + AstNode *elem = cl->elems.e[i]; + if (elem->kind != AstNode_FieldValue) { + error_node(elem, "Only `field = value` elements are allowed in a map literal"); + continue; + } + ast_node(fv, FieldValue, elem); + check_expr_with_type_hint(c, o, fv->field, t->Map.key); + check_assignment(c, o, t->Map.key, str_lit("map literal")); + if (o->mode == Addressing_Invalid) { + continue; + } + + check_expr_with_type_hint(c, o, fv->value, t->Map.value); + check_assignment(c, o, t->Map.value, str_lit("map literal")); + } + } + } break; + default: { gbString str = type_to_string(type); error_node(node, "Invalid compound literal type `%s`", str); diff --git a/src/check_stmt.c b/src/check_stmt.c index 9b26adc5d..9155947fc 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -256,11 +256,11 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { e->flags |= EntityFlag_Used; } + Type *assignment_type = op_b.type; switch (op_b.mode) { case Addressing_Invalid: return NULL; case Addressing_Variable: - break; case Addressing_MapIndex: break; default: { @@ -287,7 +287,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { } break; } - check_assignment(c, op_a, op_b.type, str_lit("assignment")); + check_assignment(c, op_a, assignment_type, str_lit("assignment")); if (op_a->mode == Addressing_Invalid) { return NULL; } @@ -719,6 +719,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { val = t->Vector.elem; idx = t_int; break; + + case Type_Map: + val = t->Map.value; + idx = t->Map.key; + break; } } diff --git a/src/checker.c b/src/checker.c index 6b2bac628..09c97ceed 100644 --- a/src/checker.c +++ b/src/checker.c @@ -958,6 +958,12 @@ void add_type_info_type(Checker *c, Type *t) { } } break; + case Type_Map: { + add_type_info_type(c, bt->Map.key); + add_type_info_type(c, bt->Map.value); + add_type_info_type(c, bt->Map.generated_struct_type); + } break; + case Type_Tuple: for (isize i = 0; i < bt->Tuple.variable_count; i++) { Entity *var = bt->Tuple.variables[i]; @@ -1093,7 +1099,7 @@ void init_preload(Checker *c) { - if (record->field_count != 19) { + if (record->field_count != 20) { compiler_error("Invalid `Type_Info` layout"); } t_type_info_named = record->fields[ 1]->type; @@ -1114,6 +1120,7 @@ void init_preload(Checker *c) { t_type_info_union = record->fields[16]->type; t_type_info_raw_union = record->fields[17]->type; t_type_info_enum = record->fields[18]->type; + t_type_info_map = record->fields[19]->type; t_type_info_named_ptr = make_type_pointer(heap_allocator(), t_type_info_named); t_type_info_integer_ptr = make_type_pointer(heap_allocator(), t_type_info_integer); @@ -1133,6 +1140,7 @@ void init_preload(Checker *c) { t_type_info_union_ptr = make_type_pointer(heap_allocator(), t_type_info_union); t_type_info_raw_union_ptr = make_type_pointer(heap_allocator(), t_type_info_raw_union); t_type_info_enum_ptr = make_type_pointer(heap_allocator(), t_type_info_enum); + t_type_info_map_ptr = make_type_pointer(heap_allocator(), t_type_info_map); } if (t_allocator == NULL) { @@ -1155,12 +1163,12 @@ void init_preload(Checker *c) { } if (t_map_key == NULL) { - Entity *e = find_core_entity(c, str_lit("Map_Key")); + Entity *e = find_core_entity(c, str_lit("__Map_Key")); t_map_key = e->type; } if (t_map_header == NULL) { - Entity *e = find_core_entity(c, str_lit("Map_Header")); + Entity *e = find_core_entity(c, str_lit("__Map_Header")); t_map_header = e->type; } diff --git a/src/gb/gb.h b/src/gb/gb.h index 8ff378ae0..9f9e850fc 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -58,6 +58,7 @@ TODOS - More date & time functions VERSION HISTORY + 0.27 - OSX fixes and Linux gbAffinity 0.26d - Minor changes to how gbFile works 0.26c - gb_str_to_f* fix 0.26b - Minor fixes @@ -4990,16 +4991,13 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { } #elif defined(GB_SYSTEM_LINUX) -#warning gbAffinity is mostly mostly untested on Linux. All I know is that it compiles and runs. -#warning TODO(bill): gb_affinity_set on Linux is a stub - -// I have to read /proc/cpuinfo to get the number of threads per core. +// IMPORTANT TODO(bill): This gbAffinity stuff for linux needs be improved a lot! +// NOTE(zangent): I have to read /proc/cpuinfo to get the number of threads per core. #include void gb_affinity_init(gbAffinity *a) { - usize count, count_size = gb_size_of(count); - - b32 accurate = true; + b32 accurate = true; + isize threads = 0; a->thread_count = 1; a->core_count = sysconf(_SC_NPROCESSORS_ONLN); @@ -5012,37 +5010,43 @@ void gb_affinity_init(gbAffinity *a) { } // Parsing /proc/cpuinfo to get the number of threads per core. - // NOTE: This calls the CPU's threads "cores", although the wording - // is kind of weird. This should be right, though. - FILE* cpu_info = fopen("/proc/cpuinfo", "r"); - - int threads = 0; - - if(cpu_info) { - while(1) { + // NOTE(zangent): This calls the CPU's threads "cores", although the wording + // is kind of weird. This should be right, though. + if (fopen("/proc/cpuinfo", "r") != NULL) { + for (;;) { // The 'temporary char'. Everything goes into this char, // so that we can check against EOF at the end of this loop. char c; - #define check(letter) ((c = getc(cpu_info)) == letter) - if(check('c') && check('p') && check('u') && check(' ') && - check('c') && check('o') && check('r') && check('e') && check('s')) { +#define AF__CHECK(letter) ((c = getc(cpu_info)) == letter) + if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') && + AF__CHECK('c') && AF__CHECK('o') && AF__CHECK('r') && AF__CHECK('e') && AF__CHECK('s')) { // We're on a CPU info line. - while(!check(EOF)) { - if(c == '\n') break; - else if(c < '0' || c > '9') continue; + while (!AF__CHECK(EOF)) { + if (c == '\n') { + break; + } else if (c < '0' || '9' > c) { + continue; + } threads = threads * 10 + (c - '0'); } break; } else { - while(!check('\n')) {if(c==EOF) break;} + while (!AF__CHECK('\n')) { + if (c==EOF) { + break; + } + } } - if(c == EOF) break; + if (c == EOF) { + break; + } +#undef AF__CHECK } } - if(threads == 0) { - threads = 1; + if (threads == 0) { + threads = 1; accurate = false; } @@ -5062,7 +5066,8 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) { } isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { - GB_ASSERT(core >= 0 && core < a->core_count); + + GB_ASSERT(0 <= core && core < a->core_count); return a->threads_per_core; } #else diff --git a/src/ir.c b/src/ir.c index 8c3767d91..117173ab3 100644 --- a/src/ir.c +++ b/src/ir.c @@ -372,6 +372,7 @@ typedef struct irAddr { struct { irValue *map_key; Type * map_type; + Type * map_result; }; }; // union { @@ -384,10 +385,11 @@ irAddr ir_make_addr(irValue *addr) { return v; } -irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type) { +irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *map_result) { irAddr v = {irAddr_Map, addr}; - v.map_key = map_key; - v.map_type = map_type; + v.map_key = map_key; + v.map_type = map_type; + v.map_result = map_result; return v; } @@ -589,23 +591,6 @@ Type *ir_type(irValue *value) { return NULL; } -Type *ir_addr_type(irAddr addr) { - if (addr.addr == NULL) { - return NULL; - } - - if (addr.kind == irAddr_Map) { - Type *t = base_type(addr.map_type); - GB_ASSERT(is_type_map(t)); - return t->Map.value; - } - - Type *t = ir_type(addr.addr); - GB_ASSERT(is_type_pointer(t)); - return type_deref(t); -} - - bool ir_is_blank_ident(AstNode *node) { if (node->kind == AstNode_Ident) { @@ -990,6 +975,9 @@ irValue *ir_make_const_i32(gbAllocator a, i64 i) { irValue *ir_make_const_i64(gbAllocator a, i64 i) { return ir_make_value_constant(a, t_i64, make_exact_value_integer(i)); } +irValue *ir_make_const_u64(gbAllocator a, u64 i) { + return ir_make_value_constant(a, t_u64, make_exact_value_integer(i)); +} irValue *ir_make_const_f32(gbAllocator a, f32 f) { return ir_make_value_constant(a, t_f32, make_exact_value_float(f)); } @@ -1398,12 +1386,16 @@ void ir_emit_startup_runtime(irProcedure *proc) { ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime)); } +irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) { + return ir_emit(proc, ir_make_instr_conv(proc, irConv_bitcast, data, ir_type(data), type)); +} + irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index); irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right); irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) { - GB_ASSERT(is_type_pointer(ir_type(map_val))); + GB_ASSERT_MSG(is_type_pointer(ir_type(map_val)), "%s", type_to_string(ir_type(map_val))); gbAllocator a = proc->module->allocator; irValue *h = ir_add_local_generated(proc, t_map_header); @@ -1431,17 +1423,43 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) return ir_emit_load(proc, h); } -irValue *ir_gen_map_key(irProcedure *proc, irValue *key) { +irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { irValue *v = ir_add_local_generated(proc, t_map_key); - irValue *hash = ir_emit_struct_ep(proc, v, 0); Type *t = base_type(ir_type(key)); + key = ir_emit_conv(proc, key, key_type); if (is_type_integer(t)) { - ir_emit_store(proc, hash, ir_emit_conv(proc, key, t_u64)); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, t_u64)); } else if (is_type_pointer(t)) { irValue *p = ir_emit_conv(proc, key, t_uint); - ir_emit_store(proc, hash, ir_emit_conv(proc, p, t_u64)); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, p, t_u64)); + } else if (is_type_float(t)) { + irValue *bits = NULL; + i64 size = type_size_of(proc->module->sizes, proc->module->allocator, t); + switch (8*size) { + case 32: bits = ir_emit_bitcast(proc, key, t_u32); break; + case 64: bits = ir_emit_bitcast(proc, key, t_u64); break; + default: GB_PANIC("Unhandled float size: %lld bits", size); break; + } + + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, bits, t_u64)); + } else if (is_type_string(t)) { + irValue *str = ir_emit_conv(proc, key, t_string); + irValue *hashed_str = NULL; + + if (str->kind == irValue_Constant) { + ExactValue ev = str->Constant.value; + GB_ASSERT(ev.kind == ExactValue_String); + u64 hs = gb_fnv64a(ev.value_string.text, ev.value_string.len); + hashed_str = ir_make_const_u64(proc->module->allocator, hs); + } else { + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1); + args[0] = str; + hashed_str = ir_emit_global_call(proc, "__default_hash_string", args, 1); + } + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), str); } else { - GB_PANIC("TODO(bill): Map Key type"); + GB_PANIC("Unhandled map key type"); } return ir_emit_load(proc, v); @@ -1461,35 +1479,51 @@ irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val) } +Type *ir_addr_type(irAddr addr) { + if (addr.addr == NULL) { + return NULL; + } + + if (addr.kind == irAddr_Map) { + Type *t = base_type(addr.map_type); + GB_ASSERT(is_type_map(t)); + return t->Map.value; + } + + Type *t = ir_type(addr.addr); + GB_ASSERT(is_type_pointer(t)); + return type_deref(t); +} + +irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type, + irValue *map_key, irValue *map_value) { + map_type = base_type(map_type); + + irValue *h = ir_gen_map_header(proc, addr, map_type); + irValue *key = ir_gen_map_key(proc, map_key, map_type->Map.key); + irValue *v = ir_emit_conv(proc, map_value, map_type->Map.value); + irValue *ptr = ir_address_from_load_or_generate_local(proc, v); + ptr = ir_emit_conv(proc, ptr, t_rawptr); + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3); + args[0] = h; + args[1] = key; + args[2] = ptr; + + return ir_emit_global_call(proc, "__dynamic_map_set", args, 3); +} + + irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { if (addr.addr == NULL) { return NULL; } if (addr.kind == irAddr_Map) { - Type *map_type = base_type(addr.map_type); - irValue *h = ir_gen_map_header(proc, addr.addr, map_type); - irValue *key = ir_gen_map_key(proc, addr.map_key); - irValue *ptr =ir_address_from_load_or_generate_local(proc, value); - ptr = ir_emit_conv(proc, ptr, t_rawptr); - - irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3); - args[0] = h; - args[1] = key; - args[2] = ptr; - - return ir_emit_global_call(proc, "__dynamic_map_set", args, 3); + return ir_insert_dynamic_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value); } - // if (addr.kind == irAddr_Vector) { - // irValue *v = ir_emit_load(proc, addr.addr); - // Type *elem_type = base_type(ir_type(v))->Vector.elem; - // irValue *elem = ir_emit_conv(proc, value, elem_type); - // irValue *out = ir_emit(proc, ir_make_instr_insert_element(proc, v, elem, addr.Vector.index)); - // return ir_emit_store(proc, addr.addr, out); - // } else { - irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); - return ir_emit_store(proc, addr.addr, v); - // } + irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); + return ir_emit_store(proc, addr.addr, v); } irValue *ir_addr_load(irProcedure *proc, irAddr addr) { @@ -1503,7 +1537,7 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) { Type *map_type = base_type(addr.map_type); irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type); irValue *h = ir_gen_map_header(proc, addr.addr, map_type); - irValue *key = ir_gen_map_key(proc, addr.map_key); + irValue *key = ir_gen_map_key(proc, addr.map_key, map_type->Map.key); irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 2); args[0] = h; @@ -1527,7 +1561,12 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) { ir_start_block(proc, done); - return ir_emit_load(proc, v); + if (is_type_tuple(addr.map_result)) { + return ir_emit_load(proc, v); + } else { + irValue *single = ir_emit_struct_ep(proc, v, 0); + return ir_emit_load(proc, single); + } } // if (addr.kind == irAddr_Vector) { @@ -1886,6 +1925,13 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, Type *type, irValue *e, Selec e = ir_emit_array_epi(proc, e, index); } else if (type->kind == Type_Array) { e = ir_emit_array_epi(proc, e, index); + } else if (type->kind == Type_Map) { + e = ir_emit_struct_ep(proc, e, 1); + switch (index) { + case 0: e = ir_emit_struct_ep(proc, e, 1); break; // count + case 1: e = ir_emit_struct_ep(proc, e, 2); break; // capacity + case 2: e = ir_emit_struct_ep(proc, e, 3); break; // allocator + } } else { GB_PANIC("un-gep-able type"); } @@ -1912,6 +1958,13 @@ irValue *ir_emit_deep_field_ev(irProcedure *proc, Type *type, irValue *e, Select GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?"); type = type->Record.fields[index]->type; e = ir_emit_conv(proc, e, type); + } else if (type->kind == Type_Map) { + e = ir_emit_struct_ev(proc, e, 1); + switch (index) { + case 0: e = ir_emit_struct_ev(proc, e, 1); break; // count + case 1: e = ir_emit_struct_ev(proc, e, 2); break; // capacity + case 2: e = ir_emit_struct_ev(proc, e, 3); break; // allocator + } } else { e = ir_emit_struct_ev(proc, e, index); } @@ -2068,9 +2121,6 @@ String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { return str_lit(""); } -irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) { - return ir_emit(proc, ir_make_instr_conv(proc, irConv_bitcast, data, ir_type(data), type)); -} irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { @@ -2977,7 +3027,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv case_ast_node(cl, CompoundLit, expr); - return ir_emit_load(proc, ir_build_addr(proc, expr).addr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; @@ -3159,9 +3209,19 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv case BuiltinProc_clear: { ir_emit_comment(proc, str_lit("reserve")); - irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]); - irValue *count_ptr = ir_emit_struct_ep(proc, array_ptr, 1); - ir_emit_store(proc, count_ptr, v_zero); + irValue *ptr = ir_build_expr(proc, ce->args.e[0]); + Type *t = base_type(type_deref(ir_type(ptr))); + if (is_type_dynamic_array(t)) { + irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1); + ir_emit_store(proc, count_ptr, v_zero); + } else if (is_type_dynamic_map(t)) { + irValue *ha = ir_emit_struct_ep(proc, ptr, 0); + irValue *ea = ir_emit_struct_ep(proc, ptr, 1); + ir_emit_store(proc, ir_emit_struct_ep(proc, ha, 1), v_zero); + ir_emit_store(proc, ir_emit_struct_ep(proc, ea, 1), v_zero); + } else { + GB_PANIC("TODO(bill): ir clear for `%s`", type_to_string(t)); + } return NULL; } break; @@ -3537,11 +3597,11 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv case_end; case_ast_node(de, DemaybeExpr, expr); - return ir_emit_load(proc, ir_build_addr(proc, expr).addr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; case_ast_node(se, SliceExpr, expr); - return ir_emit_load(proc, ir_build_addr(proc, expr).addr); + return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; case_ast_node(ie, IndexExpr, expr); @@ -3764,21 +3824,17 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { Type *t = base_type(type_of_expr(proc->module->info, ie->expr)); gbAllocator a = proc->module->allocator; - bool deref = is_type_pointer(t); t = base_type(type_deref(t)); if (is_type_map(t)) { irAddr map_addr = ir_build_addr(proc, ie->expr); irValue *map_val = map_addr.addr; - if (deref) { - map_val = ir_addr_load(proc, map_addr); - } - irValue *key = ir_build_expr(proc, ie->index); key = ir_emit_conv(proc, key, t->Map.key); - return ir_make_addr_map(map_val, key, t); + Type *result_type = type_of_expr(proc->module->info, expr); + return ir_make_addr_map(map_val, key, t, result_type); } irValue *using_addr = NULL; @@ -4127,6 +4183,28 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { } } } break; + + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + gbAllocator a = proc->module->allocator; + { + irValue **args = gb_alloc_array(a, irValue *, 4); + args[0] = ir_gen_map_header(proc, v, type); + args[1] = ir_make_const_int(a, 2*cl->elems.count); + ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); + } + for_array(field_index, cl->elems) { + AstNode *elem = cl->elems.e[field_index]; + ast_node(fv, FieldValue, elem); + + irValue *key = ir_build_expr(proc, fv->field); + irValue *value = ir_build_expr(proc, fv->value); + ir_insert_dynamic_map_key_and_value(proc, v, type, key, value); + } + } break; + case Type_Array: { if (cl->elems.count > 0) { ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr))); @@ -4346,6 +4424,7 @@ void ir_emit_increment(irProcedure *proc, irValue *addr) { } + void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, irValue *count_ptr, irValue **val_, irValue **idx_, irBlock **loop_, irBlock **done_) { irValue *count = NULL; @@ -4365,6 +4444,11 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir irBlock *done = NULL; irBlock *body = NULL; + irValue *key = NULL; + if (expr_type->kind == Type_Map) { + key = ir_add_local_generated(proc, expr_type->Map.key); + } + irValue *index = ir_add_local_generated(proc, t_int); ir_emit_store(proc, index, ir_make_const_int(proc->module->allocator, -1)); @@ -4401,6 +4485,26 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir irValue *elem = ir_emit_struct_ep(proc, expr, 0); elem = ir_emit_load(proc, elem); val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx)); + } break; + case Type_Map: { + irValue *entries = ir_emit_struct_ep(proc, expr, 1); + irValue *elem = ir_emit_struct_ep(proc, entries, 0); + elem = ir_emit_load(proc, elem); + + irValue *entry = ir_emit_ptr_offset(proc, elem, idx); + val = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 2)); + + irValue *hash = ir_emit_struct_ep(proc, entry, 0); + if (is_type_string(expr_type->Map.key)) { + irValue *str = ir_emit_struct_ep(proc, hash, 1); + ir_emit_store(proc, key, ir_emit_load(proc, str)); + } else { + irValue *hash_ptr = ir_emit_struct_ep(proc, hash, 0); + hash_ptr = ir_emit_conv(proc, hash_ptr, ir_type(key)); + ir_emit_store(proc, key, ir_emit_load(proc, hash_ptr)); + } + + } break; default: GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); @@ -4408,6 +4512,10 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir } } + if (key != NULL) { + idx = ir_emit_load(proc, key); + } + if (val_) *val_ = val; if (idx_) *idx_ = idx; if (loop_) *loop_ = loop; @@ -4598,8 +4706,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { if (lvals.e[i].addr == NULL) { continue; } - irValue *v = ir_emit_conv(proc, inits.e[i], ir_addr_type(lvals.e[i])); - ir_addr_store(proc, lvals.e[i], v); + ir_addr_store(proc, lvals.e[i], inits.e[i]); } } @@ -4957,6 +5064,16 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { Type *expr_type = type_of_expr(proc->module->info, rs->expr); Type *et = base_type(type_deref(expr_type)); switch (et->kind) { + case Type_Map: { + irAddr addr = ir_build_addr(proc, rs->expr); + irValue *map = addr.addr; + if (is_type_pointer(type_deref(ir_addr_type(addr)))) { + map = ir_addr_load(proc, addr); + } + irValue *entries_ptr = ir_emit_struct_ep(proc, map, 1); + irValue *count_ptr = ir_emit_struct_ep(proc, entries_ptr, 1); + ir_build_range_indexed(proc, map, val_type, count_ptr, &val, &index, &loop, &done); + } break; case Type_Array: { irValue *count_ptr = NULL; irValue *array = ir_build_addr(proc, rs->expr).addr; @@ -6164,14 +6281,16 @@ void ir_gen_tree(irGen *s) { tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr); { - irValue *packed = ir_make_const_bool(a, t->Record.struct_is_packed); - irValue *ordered = ir_make_const_bool(a, t->Record.struct_is_ordered); - irValue *size = ir_make_const_int(a, type_size_of(m->sizes, a, t)); - irValue *align = ir_make_const_int(a, type_align_of(m->sizes, a, t)); + irValue *size = ir_make_const_int(a, type_size_of(m->sizes, a, t)); + irValue *align = ir_make_const_int(a, type_align_of(m->sizes, a, t)); + irValue *packed = ir_make_const_bool(a, t->Record.struct_is_packed); + irValue *ordered = ir_make_const_bool(a, t->Record.struct_is_ordered); + irValue *custom_align = ir_make_const_bool(a, t->Record.custom_align); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), size); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), align); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), packed); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), ordered); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), custom_align); } irValue *memory = ir_type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index); @@ -6394,6 +6513,20 @@ void ir_gen_tree(irGen *s) { // TODO(bill): Type_Info for procedures } break; + + case Type_Map: { + tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr); + + irValue *key = ir_emit_struct_ep(proc, tag, 0); + irValue *value = ir_emit_struct_ep(proc, tag, 1); + irValue *generated_struct = ir_emit_struct_ep(proc, tag, 2); + irValue *count = ir_emit_struct_ep(proc, tag, 3); + + ir_emit_store(proc, key, ir_get_type_info_ptr(proc, type_info_data, t->Map.key)); + ir_emit_store(proc, value, ir_get_type_info_ptr(proc, type_info_data, t->Map.value)); + ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, type_info_data, t->Map.generated_struct_type)); + ir_emit_store(proc, count, ir_make_const_int(a, t->Map.count)); + } break; } if (tag != NULL) { diff --git a/src/parser.c b/src/parser.c index 652181c90..079e39c2f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1854,6 +1854,7 @@ bool is_literal_type(AstNode *node) { case AstNode_ArrayType: case AstNode_VectorType: case AstNode_StructType: + case AstNode_MapType: return true; } return false; diff --git a/src/types.c b/src/types.c index 0402b2470..dbded4a73 100644 --- a/src/types.c +++ b/src/types.c @@ -300,6 +300,7 @@ gb_global Type *t_type_info_struct = NULL; gb_global Type *t_type_info_union = NULL; gb_global Type *t_type_info_raw_union = NULL; gb_global Type *t_type_info_enum = NULL; +gb_global Type *t_type_info_map = NULL; gb_global Type *t_type_info_named_ptr = NULL; @@ -320,6 +321,7 @@ gb_global Type *t_type_info_struct_ptr = NULL; gb_global Type *t_type_info_union_ptr = NULL; gb_global Type *t_type_info_raw_union_ptr = NULL; gb_global Type *t_type_info_enum_ptr = NULL; +gb_global Type *t_type_info_map_ptr = NULL; @@ -921,6 +923,14 @@ bool are_types_identical(Type *x, Type *y) { are_types_identical(x->Proc.results, y->Proc.results); } break; + + case Type_Map: + if (y->kind == Type_Map) { + return x->Map.count == y->Map.count && + are_types_identical(x->Map.key, y->Map.key) && + are_types_identical(x->Map.value, y->Map.value); + } + break; } @@ -1073,6 +1083,10 @@ gb_global Entity *entity__dynamic_array_count = NULL; gb_global Entity *entity__dynamic_array_capacity = NULL; gb_global Entity *entity__dynamic_array_allocator = NULL; +gb_global Entity *entity__dynamic_map_count = NULL; +gb_global Entity *entity__dynamic_map_capacity = NULL; +gb_global Entity *entity__dynamic_map_allocator = NULL; + Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel); Selection lookup_field(gbAllocator a, Type *type_, String field_name, bool is_type) { @@ -1240,7 +1254,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = entity__slice_count; return sel; } - } else if (type->kind == Type_DynamicArray) { + } else if (type->kind == Type_DynamicArray) { String data_str = str_lit("data"); String count_str = str_lit("count"); String capacity_str = str_lit("capacity"); @@ -1273,6 +1287,36 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = entity__dynamic_array_allocator; return sel; } + } else if (type->kind == Type_Map) { + String count_str = str_lit("count"); + String capacity_str = str_lit("capacity"); + String allocator_str = str_lit("allocator"); + + if (str_eq(field_name, count_str)) { + selection_add_index(&sel, 0); + if (entity__dynamic_map_count == NULL) { + entity__dynamic_map_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 0); + entity__dynamic_map_count->Variable.is_immutable = true; + } + sel.entity = entity__dynamic_map_count; + return sel; + } else if (str_eq(field_name, capacity_str)) { + selection_add_index(&sel, 1); + if (entity__dynamic_map_capacity == NULL) { + entity__dynamic_map_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 1); + entity__dynamic_map_capacity->Variable.is_immutable = true; + } + sel.entity = entity__dynamic_map_capacity; + return sel; + } else if (str_eq(field_name, allocator_str)) { + selection_add_index(&sel, 2); + if (entity__dynamic_map_allocator == NULL) { + entity__dynamic_map_allocator = make_entity_field(a, NULL, make_token_ident(allocator_str), t_allocator, false, 2); + entity__dynamic_map_allocator->Variable.is_immutable = true; + } + sel.entity = entity__dynamic_map_allocator; + return sel; + } } if (type->kind != Type_Record) { @@ -1527,8 +1571,7 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type case Type_Map: { if (t->Map.count == 0) { // Dynamic - // NOTE(bill): same as a dynamic array - return s.word_size; + return type_align_of_internal(s, allocator, t->Map.generated_struct_type, path); } GB_PANIC("TODO(bill): Fixed map alignment"); } break; @@ -1744,8 +1787,7 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP case Type_Map: { if (t->Map.count == 0) { // Dynamic - // NOTE(bill): same as a two dynamic arrays - return 2 * type_size_of_internal(s, allocator, t_raw_dynamic_array, path); + return type_size_of_internal(s, allocator, t->Map.generated_struct_type, path); } GB_PANIC("TODO(bill): Fixed map size"); }