aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas T Jonsson <mail@andreasjonsson.se>2024-05-02 09:27:46 +0200
committerAndreas T Jonsson <mail@andreasjonsson.se>2024-05-02 09:27:46 +0200
commit7feff1c11335be9c0d804c3ca93050b7d154aad8 (patch)
tree62c89fcafad6b6c9445cb37153e62a6b23223d39 /src
parent6bbdbb4447b0a2b5b485ae4351016b05ae79758f (diff)
parentfd582015fe2bbaabc42f78caefec1bd95f4d1465 (diff)
Merged with master
Diffstat (limited to 'src')
-rw-r--r--src/bug_report.cpp27
-rw-r--r--src/build_settings.cpp6
-rw-r--r--src/check_expr.cpp10
-rw-r--r--src/check_stmt.cpp57
-rw-r--r--src/checker.cpp31
-rw-r--r--src/docs_writer.cpp11
-rw-r--r--src/error.cpp4
-rw-r--r--src/exact_value.cpp37
-rw-r--r--src/linker.cpp2
-rw-r--r--src/llvm_backend_general.cpp2
-rw-r--r--src/llvm_backend_stmt.cpp53
-rw-r--r--src/llvm_backend_type.cpp2
-rw-r--r--src/ptr_map.cpp447
-rw-r--r--src/string_map.cpp300
-rw-r--r--src/string_set.cpp4
-rw-r--r--src/tokenizer.cpp3
16 files changed, 520 insertions, 476 deletions
diff --git a/src/bug_report.cpp b/src/bug_report.cpp
index 0ec383b44..c73595e99 100644
--- a/src/bug_report.cpp
+++ b/src/bug_report.cpp
@@ -204,14 +204,27 @@ gb_internal void report_cpu_info() {
}
#elif defined(GB_CPU_ARM)
- /*
- TODO(Jeroen): On *nix, perhaps query `/proc/cpuinfo`.
- */
- #if defined(GB_ARCH_64_BIT)
- gb_printf("ARM64\n");
- #else
- gb_printf("ARM\n");
+ bool generic = true;
+
+ #if defined(GB_SYSTEM_OSX)
+ char cpu_name[128] = {};
+ size_t cpu_name_size = 128;
+ if (sysctlbyname("machdep.cpu.brand_string", &cpu_name, &cpu_name_size, nullptr, 0) == 0) {
+ generic = false;
+ gb_printf("%s\n", (char *)&cpu_name[0]);
+ }
#endif
+
+ if (generic) {
+ /*
+ TODO(Jeroen): On *nix, perhaps query `/proc/cpuinfo`.
+ */
+ #if defined(GB_ARCH_64_BIT)
+ gb_printf("ARM64\n");
+ #else
+ gb_printf("ARM\n");
+ #endif
+ }
#else
gb_printf("Unknown\n");
#endif
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 9ecc11cb5..b63f08980 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -1596,8 +1596,10 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
if (bc->metrics.os == TargetOs_js || bc->metrics.os == TargetOs_wasi) {
// TODO(bill): Should these even have a default "heap-like" allocator?
}
- bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR = true;
- bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR = !bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR;
+
+ if (!bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR && !bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR) {
+ bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR = true;
+ }
}
}
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index b893b3a00..06d0a8b12 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -8079,11 +8079,10 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op
}
uintptr key = hash_exact_value(operand.value);
- TypeAndToken *found = map_get(seen, key);
- if (found != nullptr) {
+ GB_ASSERT(key != 0);
+ isize count = multi_map_count(seen, key);
+ if (count) {
TEMPORARY_ALLOCATOR_GUARD();
-
- isize count = multi_map_count(seen, key);
TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count);
multi_map_get_all(seen, key, taps);
@@ -9406,7 +9405,8 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
continue;
}
ExactValue v = f->Constant.value;
- auto found = map_get(&seen, hash_exact_value(v));
+ uintptr hash = hash_exact_value(v);
+ auto found = map_get(&seen, hash);
if (!found) {
array_add(&unhandled, f);
}
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 971841165..cccbab4f6 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -1629,6 +1629,17 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
if (build_context.no_rtti && is_type_enum(t->BitSet.elem)) {
error(node, "Iteration over a bit_set of an enum is not allowed runtime type information (RTTI) has been disallowed");
}
+ if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) {
+ String name = rs->vals[0]->Ident.token.string;
+ Entity *found = scope_lookup(ctx->scope, name);
+ if (found && are_types_identical(found->type, t->BitSet.elem)) {
+ ERROR_BLOCK();
+ gbString s = expr_to_string(expr);
+ error(rs->vals[0], "'%.*s' shadows a previous declaration which might be ambiguous with 'for (%.*s in %s)'", LIT(name), LIT(name), s);
+ error_line("\tSuggestion: Use a different identifier if iteration is wanted, or surround in parentheses if a normal for loop is wanted\n");
+ gb_string_free(s);
+ }
+ }
break;
case Type_EnumeratedArray:
@@ -1664,17 +1675,36 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
if (is_reverse) {
error(node, "#reverse for is not supported for map types, as maps are unordered");
}
+ if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) {
+ String name = rs->vals[0]->Ident.token.string;
+ Entity *found = scope_lookup(ctx->scope, name);
+ if (found && are_types_identical(found->type, t->Map.key)) {
+ ERROR_BLOCK();
+ gbString s = expr_to_string(expr);
+ error(rs->vals[0], "'%.*s' shadows a previous declaration which might be ambiguous with 'for (%.*s in %s)'", LIT(name), LIT(name), s);
+ error_line("\tSuggestion: Use a different identifier if iteration is wanted, or surround in parentheses if a normal for loop is wanted\n");
+ gb_string_free(s);
+ }
+ }
break;
case Type_Tuple:
{
isize count = t->Tuple.variables.count;
- if (count < 1 || count > 3) {
+ if (count < 1) {
+ ERROR_BLOCK();
+ check_not_tuple(ctx, &operand);
+ error_line("\tMultiple return valued parameters in a range statement are limited to a minimum of 1 usable values with a trailing boolean for the conditional, got %td\n", count);
+ break;
+ }
+ enum : isize {MAXIMUM_COUNT = 100};
+ if (count > MAXIMUM_COUNT) {
ERROR_BLOCK();
check_not_tuple(ctx, &operand);
- error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of 2 usable values with a trailing boolean for the conditional\n");
+ error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of %td usable values with a trailing boolean for the conditional, got %td\n", MAXIMUM_COUNT, count);
break;
}
+
Type *cond_type = t->Tuple.variables[count-1]->type;
if (!is_type_boolean(cond_type)) {
gbString s = type_to_string(cond_type);
@@ -1683,24 +1713,23 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
break;
}
+ max_val_count = count;
+
for (Entity *e : t->Tuple.variables) {
array_add(&vals, e->type);
}
is_possibly_addressable = false;
- if (rs->vals.count > 1 && rs->vals[1] != nullptr && count < 3) {
- gbString s = type_to_string(t);
- error(operand.expr, "Expected a 3-valued expression on the rhs, got (%s)", s);
- gb_string_free(s);
- break;
- }
-
- if (rs->vals.count > 0 && rs->vals[0] != nullptr && count < 2) {
- gbString s = type_to_string(t);
- error(operand.expr, "Expected at least a 2-valued expression on the rhs, got (%s)", s);
- gb_string_free(s);
- break;
+ bool do_break = false;
+ for (isize i = rs->vals.count-1; i >= 0; i--) {
+ if (rs->vals[i] != nullptr && count < i+2) {
+ gbString s = type_to_string(t);
+ error(operand.expr, "Expected a %td-valued expression on the rhs, got (%s)", i+2, s);
+ gb_string_free(s);
+ do_break = true;
+ break;
+ }
}
if (is_reverse) {
diff --git a/src/checker.cpp b/src/checker.cpp
index f36677c84..12c8f5291 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -1898,8 +1898,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
add_type_info_dependency(c->info, c->decl, t);
MUTEX_GUARD_BLOCK(&c->info->type_info_mutex) {
- MapFindResult fr;
- auto found = map_try_get(&c->info->type_info_map, t, &fr);
+ auto found = map_get(&c->info->type_info_map, t);
if (found != nullptr) {
// Types have already been added
return;
@@ -1923,7 +1922,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
ti_index = c->info->type_info_types.count;
array_add(&c->info->type_info_types, t);
}
- map_set_internal_from_try_get(&c->checker->info.type_info_map, t, ti_index, fr);
+ map_set(&c->checker->info.type_info_map, t, ti_index);
if (prev) {
// NOTE(bill): If a previous one exists already, no need to continue
@@ -2194,7 +2193,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
// IMPORTANT NOTE(bill): this must be copied as `map_set` takes a const ref
// and effectively assigns the `+1` of the value
isize const count = set->count;
- if (map_set_if_not_previously_exists(set, ti_index, count)) {
+ if (map_set_if_not_previously_exists(set, ti_index+1, count)) {
// Type already exists;
return;
}
@@ -2537,6 +2536,11 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
is_init = false;
}
+ if ((e->flags & EntityFlag_Disabled) != 0) {
+ warning(e->token, "This @(init) procedure is disabled; you must call it manually");
+ is_init = false;
+ }
+
if (is_init) {
add_dependency_to_set(c, e);
array_add(&c->info.init_procedures, e);
@@ -2927,6 +2931,8 @@ gb_internal void init_core_type_info(Checker *c) {
return;
}
Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
+ GB_ASSERT(type_info_entity != nullptr);
+ GB_ASSERT(type_info_entity->type != nullptr);
t_type_info = type_info_entity->type;
t_type_info_ptr = alloc_type_pointer(t_type_info);
@@ -4310,17 +4316,22 @@ gb_internal bool correct_single_type_alias(CheckerContext *c, Entity *e) {
gb_internal bool correct_type_alias_in_scope_backwards(CheckerContext *c, Scope *s) {
bool correction = false;
- u32 n = s->elements.count;
- for (u32 i = n-1; i < n; i--) {
- correction |= correct_single_type_alias(c, s->elements.entries[i].value);
+ for (u32 n = s->elements.count, i = n-1; i < n; i--) {
+ auto const &entry = s->elements.entries[i];
+ Entity *e = entry.value;
+ if (entry.hash && e != nullptr) {
+ correction |= correct_single_type_alias(c, e);
+ }
}
return correction;
}
gb_internal bool correct_type_alias_in_scope_forwards(CheckerContext *c, Scope *s) {
bool correction = false;
- u32 n = s->elements.count;
- for (isize i = 0; i < n; i++) {
- correction |= correct_single_type_alias(c, s->elements.entries[i].value);
+ for (auto const &entry : s->elements) {
+ Entity *e = entry.value;
+ if (e != nullptr) {
+ correction |= correct_single_type_alias(c, entry.value);
+ }
}
return correction;
}
diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp
index 9ced78d33..ba71eae4d 100644
--- a/src/docs_writer.cpp
+++ b/src/docs_writer.cpp
@@ -987,9 +987,8 @@ gb_internal void odin_doc_update_entities(OdinDocWriter *w) {
auto entities = array_make<Entity *>(heap_allocator(), 0, w->entity_cache.count);
defer (array_free(&entities));
- for (u32 i = 0; i < w->entity_cache.count; i++) {
- Entity *e = w->entity_cache.entries[i].key;
- array_add(&entities, e);
+ for (auto const &entry : w->entity_cache) {
+ array_add(&entities, entry.key);
}
for (Entity *e : entities) {
GB_ASSERT(e != nullptr);
@@ -998,9 +997,9 @@ gb_internal void odin_doc_update_entities(OdinDocWriter *w) {
}
}
- for (u32 i = 0; i < w->entity_cache.count; i++) {
- Entity *e = w->entity_cache.entries[i].key;
- OdinDocEntityIndex entity_index = w->entity_cache.entries[i].value;
+ for (auto const &entry : w->entity_cache) {
+ Entity *e = entry.key;
+ OdinDocEntityIndex entity_index = entry.value;
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
OdinDocEntityIndex foreign_library = 0;
diff --git a/src/error.cpp b/src/error.cpp
index 7fb62c966..1b091f88e 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -376,11 +376,11 @@ gb_internal void error_out_coloured(char const *str, TerminalStyle style, Termin
gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
global_error_collector.count.fetch_add(1);
+ mutex_lock(&global_error_collector.mutex);
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
print_all_errors();
gb_exit(1);
}
- mutex_lock(&global_error_collector.mutex);
push_error_value(pos, ErrorValue_Error);
// NOTE(bill): Duplicate error, skip it
@@ -403,6 +403,8 @@ gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va
error_out("\n");
show_error_on_line(pos, end);
} else {
+ global_error_collector.curr_error_value = {};
+ global_error_collector.curr_error_value_set.store(false);
global_error_collector.count.fetch_sub(1);
}
try_pop_error_value();
diff --git a/src/exact_value.cpp b/src/exact_value.cpp
index b744d2db0..83af82f55 100644
--- a/src/exact_value.cpp
+++ b/src/exact_value.cpp
@@ -54,37 +54,50 @@ gb_global ExactValue const empty_exact_value = {};
gb_internal uintptr hash_exact_value(ExactValue v) {
mutex_lock(&hash_exact_value_mutex);
defer (mutex_unlock(&hash_exact_value_mutex));
+
+ uintptr res = 0;
switch (v.kind) {
case ExactValue_Invalid:
return 0;
case ExactValue_Bool:
- return gb_fnv32a(&v.value_bool, gb_size_of(v.value_bool));
+ res = gb_fnv32a(&v.value_bool, gb_size_of(v.value_bool));
+ break;
case ExactValue_String:
- return gb_fnv32a(v.value_string.text, v.value_string.len);
+ res = gb_fnv32a(v.value_string.text, v.value_string.len);
+ break;
case ExactValue_Integer:
{
u32 key = gb_fnv32a(v.value_integer.dp, gb_size_of(*v.value_integer.dp) * v.value_integer.used);
u8 last = (u8)v.value_integer.sign;
- return (key ^ last) * 0x01000193;
+ res = (key ^ last) * 0x01000193;
+ break;
}
case ExactValue_Float:
- return gb_fnv32a(&v.value_float, gb_size_of(v.value_float));
+ res = gb_fnv32a(&v.value_float, gb_size_of(v.value_float));
+ break;
case ExactValue_Pointer:
- return ptr_map_hash_key(v.value_pointer);
+ res = ptr_map_hash_key(v.value_pointer);
+ break;
case ExactValue_Complex:
- return gb_fnv32a(v.value_complex, gb_size_of(Complex128));
+ res = gb_fnv32a(v.value_complex, gb_size_of(Complex128));
+ break;
case ExactValue_Quaternion:
- return gb_fnv32a(v.value_quaternion, gb_size_of(Quaternion256));
+ res = gb_fnv32a(v.value_quaternion, gb_size_of(Quaternion256));
+ break;
case ExactValue_Compound:
- return ptr_map_hash_key(v.value_compound);
+ res = ptr_map_hash_key(v.value_compound);
+ break;
case ExactValue_Procedure:
- return ptr_map_hash_key(v.value_procedure);
+ res = ptr_map_hash_key(v.value_procedure);
+ break;
case ExactValue_Typeid:
- return ptr_map_hash_key(v.value_typeid);
+ res = ptr_map_hash_key(v.value_typeid);
+ break;
+ default:
+ res = gb_fnv32a(&v, gb_size_of(ExactValue));
}
- return gb_fnv32a(&v, gb_size_of(ExactValue));
-
+ return res & 0x7fffffff;
}
diff --git a/src/linker.cpp b/src/linker.cpp
index 498a96c5f..e694fd999 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -167,7 +167,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (has_asm_extension(lib)) {
if (!string_set_update(&asm_files, lib)) {
- String asm_file = asm_files.entries[i].value;
+ String asm_file = lib;
String obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".obj"));
String obj_format = str_lit("win64");
#if defined(GB_ARCH_32_BIT)
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 02afa628c..15cbb7c71 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -140,7 +140,7 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
}
gen->default_module.gen = gen;
- map_set(&gen->modules, cast(void *)nullptr, &gen->default_module);
+ map_set(&gen->modules, cast(void *)1, &gen->default_module);
lb_init_module(&gen->default_module, c);
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index 24dd321f6..851433415 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -802,8 +802,19 @@ gb_internal void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_
if (done_) *done_ = done;
}
-gb_internal void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type,
- lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) {
+gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
+ Ast *expr = unparen_expr(rs->expr);
+
+ Type *expr_type = type_of_expr(expr);
+ Type *et = base_type(type_deref(expr_type));
+ GB_ASSERT(et->kind == Type_Tuple);
+
+ i32 value_count = cast(i32)et->Tuple.variables.count;
+
+ lbValue *values = gb_alloc_array(permanent_allocator(), lbValue, value_count);
+
+ lb_open_scope(p, scope);
+
lbBlock *loop = lb_create_block(p, "for.tuple.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
@@ -821,11 +832,26 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type
lb_emit_if(p, cond, body, done);
lb_start_block(p, body);
+ for (i32 i = 0; i < value_count; i++) {
+ values[i] = lb_emit_tuple_ev(p, tuple_value, i);
+ }
- if (val0_) *val0_ = lb_emit_tuple_ev(p, tuple_value, 0);
- if (val1_) *val1_ = lb_emit_tuple_ev(p, tuple_value, 1);
- if (loop_) *loop_ = loop;
- if (done_) *done_ = done;
+ GB_ASSERT(rs->vals.count <= value_count);
+ for (isize i = 0; i < rs->vals.count; i++) {
+ Ast *val = rs->vals[i];
+ if (val != nullptr) {
+ lb_store_range_stmt_val(p, val, values[i]);
+ }
+ }
+
+ lb_push_target_list(p, rs->label, done, loop, nullptr);
+
+ lb_build_stmt(p, rs->body);
+
+ lb_close_scope(p, lbDeferExit_Default, nullptr);
+ lb_pop_target_list(p);
+ lb_emit_jump(p, loop);
+ lb_start_block(p, done);
}
gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
@@ -968,6 +994,17 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
}
}
+ TypeAndValue tav = type_and_value_of_expr(expr);
+ if (tav.mode != Addressing_Type) {
+ Type *expr_type = type_of_expr(expr);
+ Type *et = base_type(type_deref(expr_type));
+ if (et->kind == Type_Tuple) {
+ lb_build_range_tuple(p, rs, scope);
+ return;
+ }
+ }
+
+
lb_open_scope(p, scope);
Ast *val0 = rs->vals.count > 0 ? lb_strip_and_prefix(rs->vals[0]) : nullptr;
@@ -986,7 +1023,6 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
lbBlock *loop = nullptr;
lbBlock *done = nullptr;
bool is_map = false;
- TypeAndValue tav = type_and_value_of_expr(expr);
if (tav.mode == Addressing_Type) {
lb_build_range_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done);
@@ -1062,8 +1098,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
break;
}
case Type_Tuple:
- lb_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done);
- break;
+ GB_PANIC("Should be handled already");
case Type_BitSet: {
lbModule *m = p->module;
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index e202a59ba..2c4abbb4d 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -2,7 +2,7 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_
auto *set = &info->minimum_dependency_type_info_set;
isize index = type_info_index(info, type, err_on_not_found);
if (index >= 0) {
- auto *found = map_get(set, index);
+ auto *found = map_get(set, index+1);
if (found) {
GB_ASSERT(*found >= 0);
return *found + 1;
diff --git a/src/ptr_map.cpp b/src/ptr_map.cpp
index 23278014f..362e412ba 100644
--- a/src/ptr_map.cpp
+++ b/src/ptr_map.cpp
@@ -16,23 +16,21 @@ struct MapFindResult {
};
enum : MapIndex { MAP_SENTINEL = ~(MapIndex)0 };
+static void *const MAP_TOMBSTONE = (void *)~(uintptr)0;
template <typename K, typename V>
struct PtrMapEntry {
static_assert(sizeof(K) == sizeof(void *), "Key size must be pointer size");
- K key;
- V value;
- MapIndex next;
+ K key;
+ V value;
};
template <typename K, typename V>
struct PtrMap {
- MapIndex * hashes;
- usize hashes_count;
PtrMapEntry<K, V> *entries;
u32 count;
- u32 entries_capacity;
+ u32 capacity;
};
@@ -69,7 +67,6 @@ template <typename K, typename V> gb_internal void map_grow (PtrMap<
template <typename K, typename V> gb_internal void map_rehash (PtrMap<K, V> *h, isize new_count);
template <typename K, typename V> gb_internal void map_reserve (PtrMap<K, V> *h, isize cap);
-#if PTR_MAP_ENABLE_MULTI_MAP
// Mutlivalued map procedure
template <typename K, typename V> gb_internal PtrMapEntry<K, V> * multi_map_find_first(PtrMap<K, V> *h, K key);
template <typename K, typename V> gb_internal PtrMapEntry<K, V> * multi_map_find_next (PtrMap<K, V> *h, PtrMapEntry<K, V> *e);
@@ -79,7 +76,6 @@ template <typename K, typename V> gb_internal void multi_map_get_all (PtrMap<
template <typename K, typename V> gb_internal void multi_map_insert (PtrMap<K, V> *h, K key, V const &value);
template <typename K, typename V> gb_internal void multi_map_remove (PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e);
template <typename K, typename V> gb_internal void multi_map_remove_all(PtrMap<K, V> *h, K key);
-#endif
gb_internal gbAllocator map_allocator(void) {
return heap_allocator();
@@ -94,170 +90,141 @@ gb_internal gb_inline void map_init(PtrMap<K, V> *h, isize capacity) {
template <typename K, typename V>
gb_internal gb_inline void map_destroy(PtrMap<K, V> *h) {
gbAllocator a = map_allocator();
- gb_free(a, h->hashes);
gb_free(a, h->entries);
}
-template <typename K, typename V>
-gb_internal void map__resize_hashes(PtrMap<K, V> *h, usize count) {
- h->hashes_count = cast(u32)resize_array_raw(&h->hashes, map_allocator(), h->hashes_count, count, MAP_CACHE_LINE_SIZE);
-}
-
-template <typename K, typename V>
-gb_internal void map__reserve_entries(PtrMap<K, V> *h, usize capacity) {
- h->entries_capacity = cast(u32)resize_array_raw(&h->entries, map_allocator(), h->entries_capacity, capacity, MAP_CACHE_LINE_SIZE);
-}
-
template <typename K, typename V>
-gb_internal MapIndex map__add_entry(PtrMap<K, V> *h, K key) {
- PtrMapEntry<K, V> e = {};
- e.key = key;
- e.next = MAP_SENTINEL;
- if (h->count+1 >= h->entries_capacity) {
- map__reserve_entries(h, gb_max(h->entries_capacity*2, 4));
- }
- h->entries[h->count++] = e;
- return cast(MapIndex)(h->count-1);
-}
-
-template <typename K, typename V>
-gb_internal MapFindResult map__find(PtrMap<K, V> *h, K key) {
- MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
- if (h->hashes_count == 0) {
- return fr;
+gb_internal void map__insert(PtrMap<K, V> *h, K key, V const &value) {
+ if (h->count+1 >= h->capacity) {
+ map_grow(h);
}
u32 hash = ptr_map_hash_key(key);
- fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
- fr.entry_index = h->hashes[fr.hash_index];
- while (fr.entry_index != MAP_SENTINEL) {
- auto *entry = &h->entries[fr.entry_index];
- if (entry->key == key) {
- return fr;
+ u32 mask = h->capacity-1;
+ MapIndex index = hash & mask;
+ MapIndex original_index = index;
+ do {
+ auto *entry = h->entries+index;
+ if (!entry->key || entry->key == cast(K)MAP_TOMBSTONE) {
+ entry->key = key;
+ entry->value = value;
+ h->count += 1;
+ return;
}
- fr.entry_prev = fr.entry_index;
- fr.entry_index = entry->next;
- }
- return fr;
-}
+ index = (index+1)&mask;
+ } while (index != original_index);
-template <typename K, typename V>
-gb_internal MapFindResult map__find_from_entry(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
- MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
- if (h->hashes_count == 0) {
- return fr;
- }
- u32 hash = ptr_map_hash_key(e->key);
- fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
- fr.entry_index = h->hashes[fr.hash_index];
- while (fr.entry_index != MAP_SENTINEL) {
- if (&h->entries[fr.entry_index] == e) {
- return fr;
- }
- fr.entry_prev = fr.entry_index;
- fr.entry_index = h->entries[fr.entry_index].next;
- }
- return fr;
+ GB_PANIC("FAILED TO INSERT");
}
template <typename K, typename V>
gb_internal b32 map__full(PtrMap<K, V> *h) {
- return 0.75f * h->hashes_count <= h->count;
+ return 0.75f * h->capacity <= h->count;
}
template <typename K, typename V>
gb_internal gb_inline void map_grow(PtrMap<K, V> *h) {
- isize new_count = gb_max(h->hashes_count<<1, 16);
- map_rehash(h, new_count);
+ isize new_capacity = gb_max(h->capacity<<1, 16);
+ map_reserve(h, new_capacity);
}
template <typename K, typename V>
-gb_internal void map_reset_entries(PtrMap<K, V> *h) {
- for (usize i = 0; i < h->hashes_count; i++) {
- h->hashes[i] = MAP_SENTINEL;
- }
- for (usize i = 0; i < h->count; i++) {
- MapFindResult fr;
- PtrMapEntry<K, V> *e = &h->entries[i];
- e->next = MAP_SENTINEL;
- fr = map__find_from_entry(h, e);
- if (fr.entry_prev == MAP_SENTINEL) {
- h->hashes[fr.hash_index] = cast(MapIndex)i;
- } else {
- h->entries[fr.entry_prev].next = cast(MapIndex)i;
- }
+gb_internal void try_map_grow(PtrMap<K, V> *h) {
+ if (h->capacity == 0 || map__full(h)) {
+ map_grow(h);
}
}
+
template <typename K, typename V>
gb_internal void map_reserve(PtrMap<K, V> *h, isize cap) {
- if (h->count*2 < h->hashes_count) {
+ if (cap < h->capacity) {
return;
}
- map__reserve_entries(h, cap);
- map__resize_hashes(h, cap*2);
- map_reset_entries(h);
-}
+ cap = next_pow2_isize(cap);
+ typedef PtrMapEntry<K, V> EntryType;
+ PtrMap<K, V> new_h = {};
+ new_h.count = 0;
+ new_h.capacity = cast(u32)cap;
+ new_h.entries = gb_alloc_array(map_allocator(), EntryType, new_h.capacity);
-template <typename K, typename V>
-gb_internal void map_rehash(PtrMap<K, V> *h, isize new_count) {
- map_reserve(h, new_count);
+ if (h->count) {
+ for (u32 i = 0; i < h->capacity; i++) {
+ auto *entry = h->entries+i;
+ if (entry->key &&
+ entry->key != cast(K)MAP_TOMBSTONE) {
+ map__insert(&new_h, entry->key, entry->value);
+ }
+ }
+ }
+ map_destroy(h);
+ *h = new_h;
}
template <typename K, typename V>
gb_internal V *map_get(PtrMap<K, V> *h, K key) {
- MapIndex hash_index = MAP_SENTINEL;
- MapIndex entry_prev = MAP_SENTINEL;
- MapIndex entry_index = MAP_SENTINEL;
- if (h->hashes_count != 0) {
- u32 hash = ptr_map_hash_key(key);
- hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
- entry_index = h->hashes[hash_index];
- while (entry_index != MAP_SENTINEL) {
- auto *entry = &h->entries[entry_index];
- if (entry->key == key) {
- return &entry->value;
- }
- entry_prev = entry_index;
- entry_index = entry->next;
- }
+ if (h->count == 0) {
+ return nullptr;
+ }
+ if (key == 0) {
+ GB_PANIC("0 key");
}
+
+ u32 hash = ptr_map_hash_key(key);
+ u32 mask = (h->capacity-1);
+ u32 index = hash & mask;
+ u32 original_index = index;
+ do {
+ auto *entry = h->entries+index;
+ if (!entry->key) {
+ // NOTE(bill): no found, but there isn't any key removal for this hash map
+ return nullptr;
+ } else if (entry->key == key) {
+ return &entry->value;
+ }
+ index = (index+1) & mask;
+ } while (original_index != index);
return nullptr;
}
template <typename K, typename V>
-gb_internal V *map_try_get(PtrMap<K, V> *h, K key, MapFindResult *fr_) {
- MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
- if (h->hashes_count != 0) {
- u32 hash = ptr_map_hash_key(key);
- fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
- fr.entry_index = h->hashes[fr.hash_index];
- while (fr.entry_index != MAP_SENTINEL) {
- auto *entry = &h->entries[fr.entry_index];
- if (entry->key == key) {
- return &entry->value;
- }
- fr.entry_prev = fr.entry_index;
- fr.entry_index = entry->next;
- }
+gb_internal V *map_try_get(PtrMap<K, V> *h, K key, MapIndex *found_index_) {
+ if (found_index_) *found_index_ = ~(MapIndex)0;
+
+ if (h->count == 0) {
+ return nullptr;
}
- if (h->hashes_count == 0 || map__full(h)) {
- map_grow(h);
+ if (key == 0) {
+ GB_PANIC("0 key");
}
- if (fr_) *fr_ = fr;
+
+ u32 hash = ptr_map_hash_key(key);
+ u32 mask = (h->capacity-1);
+ u32 index = hash & mask;
+ u32 original_index = index;
+ do {
+ auto *entry = h->entries+index;
+ if (!entry->key) {
+ // NOTE(bill): no found, but there isn't any key removal for this hash map
+ return nullptr;
+ } else if (entry->key == key) {
+ if (found_index_) *found_index_ = index;
+ return &entry->value;
+ }
+ index = (index+1) & mask;
+ } while (original_index != index);
return nullptr;
}
template <typename K, typename V>
-gb_internal void map_set_internal_from_try_get(PtrMap<K, V> *h, K key, V const &value, MapFindResult const &fr) {
- MapIndex index = map__add_entry(h, key);
- if (fr.entry_prev != MAP_SENTINEL) {
- h->entries[fr.entry_prev].next = index;
+gb_internal void map_set_internal_from_try_get(PtrMap<K, V> *h, K key, V const &value, MapIndex found_index) {
+ if (found_index != MAP_SENTINEL) {
+ GB_ASSERT(h->entries[found_index].key == key);
+ h->entries[found_index].value = value;
} else {
- h->hashes[fr.hash_index] = index;
+ map_set(h, key, value);
}
- h->entries[index].value = value;
}
template <typename K, typename V>
@@ -269,116 +236,83 @@ gb_internal V &map_must_get(PtrMap<K, V> *h, K key) {
template <typename K, typename V>
gb_internal void map_set(PtrMap<K, V> *h, K key, V const &value) {
- MapIndex index;
- MapFindResult fr;
- if (h->hashes_count == 0) {
- map_grow(h);
- }
- fr = map__find(h, key);
- if (fr.entry_index != MAP_SENTINEL) {
- index = fr.entry_index;
- } else {
- index = map__add_entry(h, key);
- if (fr.entry_prev != MAP_SENTINEL) {
- h->entries[fr.entry_prev].next = index;
- } else {
- h->hashes[fr.hash_index] = index;
- }
- }
- h->entries[index].value = value;
-
- if (map__full(h)) {
- map_grow(h);
+ GB_ASSERT(key != 0);
+ try_map_grow(h);
+ auto *found = map_get(h, key);
+ if (found) {
+ *found = value;
+ return;
}
+ map__insert(h, key, value);
}
// returns true if it previously existed
template <typename K, typename V>
gb_internal bool map_set_if_not_previously_exists(PtrMap<K, V> *h, K key, V const &value) {
- MapIndex index;
- MapFindResult fr;
- if (h->hashes_count == 0) {
- map_grow(h);
- }
- fr = map__find(h, key);
- if (fr.entry_index != MAP_SENTINEL) {
+ try_map_grow(h);
+ auto *found = map_get(h, key);
+ if (found) {
return true;
- } else {
- index = map__add_entry(h, key);
- if (fr.entry_prev != MAP_SENTINEL) {
- h->entries[fr.entry_prev].next = index;
- } else {
- h->hashes[fr.hash_index] = index;
- }
- }
- h->entries[index].value = value;
-
- if (map__full(h)) {
- map_grow(h);
}
+ map__insert(h, key, value);
return false;
}
template <typename K, typename V>
-gb_internal void map__erase(PtrMap<K, V> *h, MapFindResult const &fr) {
- MapFindResult last;
- if (fr.entry_prev == MAP_SENTINEL) {
- h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
- } else {
- h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next;
- }
- if (fr.entry_index == h->count-1) {
- h->count--;
- return;
- }
- h->entries[fr.entry_index] = h->entries[h->count-1];
- h->count--;
-
- last = map__find(h, h->entries[fr.entry_index].key);
- if (last.entry_prev != MAP_SENTINEL) {
- h->entries[last.entry_prev].next = fr.entry_index;
- } else {
- h->hashes[last.hash_index] = fr.entry_index;
- }
-}
-
-template <typename K, typename V>
gb_internal void map_remove(PtrMap<K, V> *h, K key) {
- MapFindResult fr = map__find(h, key);
- if (fr.entry_index != MAP_SENTINEL) {
- map__erase(h, fr);
+ MapIndex found_index = 0;
+ if (map_try_get(h, key, &found_index)) {
+ h->entries[found_index].key = cast(K)MAP_TOMBSTONE;
+ h->count -= 1;
}
}
template <typename K, typename V>
gb_internal gb_inline void map_clear(PtrMap<K, V> *h) {
h->count = 0;
- for (usize i = 0; i < h->hashes_count; i++) {
- h->hashes[i] = MAP_SENTINEL;
- }
+ gb_zero_array(h->entries, h->capacity);
}
#if PTR_MAP_ENABLE_MULTI_MAP
template <typename K, typename V>
gb_internal PtrMapEntry<K, V> *multi_map_find_first(PtrMap<K, V> *h, K key) {
- MapIndex i = map__find(h, key).entry_index;
- if (i == MAP_SENTINEL) {
+ if (h->count == 0) {
return nullptr;
}
- return &h->entries[i];
+ u32 hash = ptr_map_hash_key(key);
+ u32 mask = (h->capacity-1);
+ u32 index = hash & mask;
+ u32 original_index = index;
+ do {
+ auto *entry = h->entries+index;
+ if (!entry->key) {
+ // NOTE(bill): no found, but there isn't any key removal for this hash map
+ return nullptr;
+ } else if (entry->key == key) {
+ return entry;
+ }
+ index = (index+1) & mask;
+ } while (original_index != index);
+ return nullptr;
}
template <typename K, typename V>
gb_internal PtrMapEntry<K, V> *multi_map_find_next(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
- MapIndex i = e->next;
- while (i != MAP_SENTINEL) {
- if (h->entries[i].key == e->key) {
- return &h->entries[i];
+ u32 mask = h->capacity-1;
+ MapIndex index = cast(MapIndex)(e - h->entries);
+ MapIndex original_index = index;
+ do {
+ index = (index+1)&mask;
+ auto *entry = h->entries+index;
+ if (!entry->key) {
+ return nullptr;
}
- i = h->entries[i].next;
- }
+ if (entry->key == e->key) {
+ return entry;
+ }
+ } while (original_index != index);
return nullptr;
}
@@ -405,34 +339,16 @@ gb_internal void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
template <typename K, typename V>
gb_internal void multi_map_insert(PtrMap<K, V> *h, K key, V const &value) {
- MapFindResult fr;
- MapIndex i;
- if (h->hashes_count == 0) {
- map_grow(h);
- }
- // Make
- fr = map__find(h, key);
- i = map__add_entry(h, key);
- if (fr.entry_prev == MAP_SENTINEL) {
- h->hashes[fr.hash_index] = i;
- } else {
- h->entries[fr.entry_prev].next = i;
- }
- h->entries[i].next = fr.entry_index;
- h->entries[i].value = value;
- // Grow if needed
- if (map__full(h)) {
- map_grow(h);
- }
+ try_map_grow(h);
+ map__insert(h, key, value);
}
-template <typename K, typename V>
-gb_internal void multi_map_remove(PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e) {
- MapFindResult fr = map__find_from_entry(h, e);
- if (fr.entry_index != MAP_SENTINEL) {
- map__erase(h, fr);
- }
-}
+// template <typename K, typename V>
+// gb_internal void multi_map_remove(PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e) {
+// if (fr.entry_index != MAP_SENTINEL) {
+// map__erase(h, fr);
+// }
+// }
template <typename K, typename V>
gb_internal void multi_map_remove_all(PtrMap<K, V> *h, K key) {
@@ -443,22 +359,77 @@ gb_internal void multi_map_remove_all(PtrMap<K, V> *h, K key) {
#endif
+
+
+template <typename K, typename V>
+struct PtrMapIterator {
+ PtrMap<K, V> *map;
+ MapIndex index;
+
+ PtrMapIterator<K, V> &operator++() noexcept {
+ for (;;) {
+ ++index;
+ if (map->capacity == index) {
+ return *this;
+ }
+ PtrMapEntry<K, V> *entry = map->entries+index;
+ if (entry->key && entry->key != cast(K)MAP_TOMBSTONE) {
+ return *this;
+ }
+ }
+ }
+
+ bool operator==(PtrMapIterator<K, V> const &other) const noexcept {
+ return this->map == other->map && this->index == other->index;
+ }
+
+ operator PtrMapEntry<K, V> *() const {
+ return map->entries+index;
+ }
+};
+
+
template <typename K, typename V>
-gb_internal PtrMapEntry<K, V> *begin(PtrMap<K, V> &m) {
- return m.entries;
+gb_internal PtrMapIterator<K, V> end(PtrMap<K, V> &m) noexcept {
+ return PtrMapIterator<K, V>{&m, m.capacity};
}
+
template <typename K, typename V>
-gb_internal PtrMapEntry<K, V> const *begin(PtrMap<K, V> const &m) {
- return m.entries;
+gb_internal PtrMapIterator<K, V> const end(PtrMap<K, V> const &m) noexcept {
+ return PtrMapIterator<K, V>{&m, m.capacity};
}
+
template <typename K, typename V>
-gb_internal PtrMapEntry<K, V> *end(PtrMap<K, V> &m) {
- return m.entries + m.count;
-}
+gb_internal PtrMapIterator<K, V> begin(PtrMap<K, V> &m) noexcept {
+ if (m.count == 0) {
+ return end(m);
+ }
+ MapIndex index = 0;
+ while (index < m.capacity) {
+ auto key = m.entries[index].key;
+ if (key && key != cast(K)MAP_TOMBSTONE) {
+ break;
+ }
+ index++;
+ }
+ return PtrMapIterator<K, V>{&m, index};
+}
template <typename K, typename V>
-gb_internal PtrMapEntry<K, V> const *end(PtrMap<K, V> const &m) {
- return m.entries + m.count;
+gb_internal PtrMapIterator<K, V> const begin(PtrMap<K, V> const &m) noexcept {
+ if (m.count == 0) {
+ return end(m);
+ }
+
+ MapIndex index = 0;
+ while (index < m.capacity) {
+ auto key = m.entries[index].key;
+ if (key && key != cast(K)MAP_TOMBSTONE) {
+ break;
+ }
+ index++;
+ }
+ return PtrMapIterator<K, V>{&m, index};
}
diff --git a/src/string_map.cpp b/src/string_map.cpp
index f8b86a950..4de88bbf9 100644
--- a/src/string_map.cpp
+++ b/src/string_map.cpp
@@ -2,8 +2,8 @@ GB_STATIC_ASSERT(sizeof(MapIndex) == sizeof(u32));
struct StringHashKey {
- u32 hash;
String string;
+ u32 hash;
operator String() const noexcept {
return this->string;
@@ -13,7 +13,8 @@ struct StringHashKey {
}
};
gb_internal gb_inline u32 string_hash(String const &s) {
- return fnv32a(s.text, s.len) & 0x7fffffff;
+ u32 res = fnv32a(s.text, s.len) & 0x7fffffff;
+ return res | (res == 0);
}
gb_internal gb_inline StringHashKey string_hash_string(String const &s) {
@@ -25,19 +26,16 @@ gb_internal gb_inline StringHashKey string_hash_string(String const &s) {
template <typename T>
struct StringMapEntry {
- String key;
- u32 hash;
- MapIndex next;
- T value;
+ String key;
+ u32 hash;
+ T value;
};
template <typename T>
struct StringMap {
- MapIndex * hashes;
- usize hashes_count;
StringMapEntry<T> *entries;
u32 count;
- u32 entries_capacity;
+ u32 capacity;
};
@@ -73,127 +71,91 @@ gb_internal gb_inline void string_map_init(StringMap<T> *h, usize capacity) {
template <typename T>
gb_internal gb_inline void string_map_destroy(StringMap<T> *h) {
- gb_free(string_map_allocator(), h->hashes);
gb_free(string_map_allocator(), h->entries);
}
template <typename T>
-gb_internal void string_map__resize_hashes(StringMap<T> *h, usize count) {
- h->hashes_count = cast(u32)resize_array_raw(&h->hashes, string_map_allocator(), h->hashes_count, count, MAP_CACHE_LINE_SIZE);
-}
-
-
-template <typename T>
-gb_internal void string_map__reserve_entries(StringMap<T> *h, usize capacity) {
- h->entries_capacity = cast(u32)resize_array_raw(&h->entries, string_map_allocator(), h->entries_capacity, capacity, MAP_CACHE_LINE_SIZE);
-}
-
-
-template <typename T>
-gb_internal MapIndex string_map__add_entry(StringMap<T> *h, u32 hash, String const &key) {
- StringMapEntry<T> e = {};
- e.key = key;
- e.hash = hash;
- e.next = MAP_SENTINEL;
- if (h->count+1 >= h->entries_capacity) {
- string_map__reserve_entries(h, gb_max(h->entries_capacity*2, 4));
+gb_internal void string_map__insert(StringMap<T> *h, u32 hash, String const &key, T const &value) {
+ if (h->count+1 >= h->capacity) {
+ string_map_grow(h);
}
- h->entries[h->count++] = e;
- return cast(MapIndex)(h->count-1);
-}
-
-template <typename T>
-gb_internal MapFindResult string_map__find(StringMap<T> *h, u32 hash, String const &key) {
- MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
- if (h->hashes_count != 0) {
- fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
- fr.entry_index = h->hashes[fr.hash_index];
- while (fr.entry_index != MAP_SENTINEL) {
- auto *entry = &h->entries[fr.entry_index];
- if (entry->hash == hash && entry->key == key) {
- return fr;
- }
- fr.entry_prev = fr.entry_index;
- fr.entry_index = entry->next;
+ GB_ASSERT(h->count+1 < h->capacity);
+
+ u32 mask = h->capacity-1;
+ MapIndex index = hash & mask;
+ MapIndex original_index = index;
+ do {
+ auto *entry = h->entries+index;
+ if (entry->hash == 0) {
+ entry->key = key;
+ entry->hash = hash;
+ entry->value = value;
+
+ h->count += 1;
+ return;
}
- }
- return fr;
-}
+ index = (index+1)&mask;
+ } while (index != original_index);
-template <typename T>
-gb_internal MapFindResult string_map__find_from_entry(StringMap<T> *h, StringMapEntry<T> *e) {
- MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
- if (h->hashes_count != 0) {
- fr.hash_index = cast(MapIndex)(e->hash & (h->hashes_count-1));
- fr.entry_index = h->hashes[fr.hash_index];
- while (fr.entry_index != MAP_SENTINEL) {
- auto *entry = &h->entries[fr.entry_index];
- if (entry == e) {
- return fr;
- }
- fr.entry_prev = fr.entry_index;
- fr.entry_index = entry->next;
- }
- }
- return fr;
+ GB_PANIC("Full map");
}
template <typename T>
gb_internal b32 string_map__full(StringMap<T> *h) {
- return 0.75f * h->hashes_count <= h->count;
+ return 0.75f * h->count <= h->capacity;
}
template <typename T>
gb_inline void string_map_grow(StringMap<T> *h) {
- isize new_count = gb_max(h->hashes_count<<1, 16);
- string_map_reserve(h, new_count);
+ isize new_capacity = gb_max(h->capacity<<1, 16);
+ string_map_reserve(h, new_capacity);
}
template <typename T>
-gb_internal void string_map_reset_entries(StringMap<T> *h) {
- for (u32 i = 0; i < h->hashes_count; i++) {
- h->hashes[i] = MAP_SENTINEL;
- }
- for (isize i = 0; i < h->count; i++) {
- MapFindResult fr;
- StringMapEntry<T> *e = &h->entries[i];
- e->next = MAP_SENTINEL;
- fr = string_map__find_from_entry(h, e);
- if (fr.entry_prev == MAP_SENTINEL) {
- h->hashes[fr.hash_index] = cast(MapIndex)i;
- } else {
- h->entries[fr.entry_prev].next = cast(MapIndex)i;
- }
- }
-}
-
-template <typename T>
gb_internal void string_map_reserve(StringMap<T> *h, usize cap) {
- if (h->count*2 < h->hashes_count) {
+ if (cap < h->capacity) {
return;
}
- string_map__reserve_entries(h, cap);
- string_map__resize_hashes(h, cap*2);
- string_map_reset_entries(h);
+ cap = next_pow2_isize(cap);
+
+ StringMap<T> new_h = {};
+ new_h.count = 0;
+ new_h.capacity = cast(u32)cap;
+ new_h.entries = gb_alloc_array(string_map_allocator(), StringMapEntry<T>, new_h.capacity);
+
+ if (h->count) {
+ for (u32 i = 0; i < h->capacity; i++) {
+ auto *entry = h->entries+i;
+ if (entry->hash) {
+ string_map__insert(&new_h, entry->hash, entry->key, entry->value);
+ }
+ }
+ }
+ string_map_destroy(h);
+ *h = new_h;
}
template <typename T>
gb_internal T *string_map_get(StringMap<T> *h, u32 hash, String const &key) {
- MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
- if (h->hashes_count != 0) {
- fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
- fr.entry_index = h->hashes[fr.hash_index];
- while (fr.entry_index != MAP_SENTINEL) {
- auto *entry = &h->entries[fr.entry_index];
- if (entry->hash == hash && entry->key == key) {
- return &entry->value;
- }
- fr.entry_prev = fr.entry_index;
- fr.entry_index = entry->next;
- }
+ if (h->count == 0) {
+ return nullptr;
}
+ u32 mask = (h->capacity-1);
+ u32 index = hash & mask;
+ u32 original_index = index;
+ do {
+ auto *entry = h->entries+index;
+ u32 curr_hash = entry->hash;
+ if (curr_hash == 0) {
+ // NOTE(bill): no found, but there isn't any key removal for this hash map
+ return nullptr;
+ } else if (curr_hash == hash && entry->key == key) {
+ return &entry->value;
+ }
+ index = (index+1) & mask;
+ } while (original_index != index);
return nullptr;
}
@@ -216,9 +178,9 @@ gb_internal gb_inline T *string_map_get(StringMap<T> *h, char const *key) {
template <typename T>
gb_internal T &string_map_must_get(StringMap<T> *h, u32 hash, String const &key) {
- isize index = string_map__find(h, hash, key).entry_index;
- GB_ASSERT(index != MAP_SENTINEL);
- return h->entries[index].value;
+ T *found = string_map_get(h, hash, key);
+ GB_ASSERT(found != nullptr);
+ return *found;
}
template <typename T>
@@ -239,27 +201,15 @@ gb_internal gb_inline T &string_map_must_get(StringMap<T> *h, char const *key) {
template <typename T>
gb_internal void string_map_set(StringMap<T> *h, u32 hash, String const &key, T const &value) {
- MapIndex index;
- MapFindResult fr;
- if (h->hashes_count == 0) {
+ if (h->count == 0) {
string_map_grow(h);
}
- fr = string_map__find(h, hash, key);
- if (fr.entry_index != MAP_SENTINEL) {
- index = fr.entry_index;
- } else {
- index = string_map__add_entry(h, hash, key);
- if (fr.entry_prev != MAP_SENTINEL) {
- h->entries[fr.entry_prev].next = index;
- } else {
- h->hashes[fr.hash_index] = index;
- }
- }
- h->entries[index].value = value;
-
- if (string_map__full(h)) {
- string_map_grow(h);
+ auto *found = string_map_get(h, hash, key);
+ if (found) {
+ *found = value;
+ return;
}
+ string_map__insert(h, hash, key, value);
}
template <typename T>
@@ -278,62 +228,80 @@ gb_internal gb_inline void string_map_set(StringMap<T> *h, StringHashKey const &
}
-
-// template <typename T>
-// gb_internal void string_map__erase(StringMap<T> *h, MapFindResult const &fr) {
-// MapFindResult last;
-// if (fr.entry_prev == MAP_SENTINEL) {
-// h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
-// } else {
-// h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next;
-// }
-// if (fr.entry_index == h->count-1) {
-// array_pop(&h->entries);
-// return;
-// }
-// h->entries[fr.entry_index] = h->entries[h->count-1];
-// last = string_map__find(h, h->entries[fr.entry_index].key);
-// if (last.entry_prev != MAP_SENTINEL) {
-// h->entries[last.entry_prev].next = fr.entry_index;
-// } else {
-// h->hashes[last.hash_index] = fr.entry_index;
-// }
-// }
-
-// template <typename T>
-// gb_internal void string_map_remove(StringMap<T> *h, StringHashKey const &key) {
-// MapFindResult fr = string_map__find(h, key);
-// if (fr.entry_index != MAP_SENTINEL) {
-// string_map__erase(h, fr);
-// }
-// }
-
template <typename T>
gb_internal gb_inline void string_map_clear(StringMap<T> *h) {
h->count = 0;
- for (u32 i = 0; i < h->hashes_count; i++) {
- h->hashes[i] = MAP_SENTINEL;
- }
+ gb_zero_array(h->entries, h->capacity);
}
+template <typename T>
+struct StringMapIterator {
+ StringMap<T> *map;
+ MapIndex index;
+
+ StringMapIterator<T> &operator++() noexcept {
+ for (;;) {
+ ++index;
+ if (map->capacity == index) {
+ return *this;
+ }
+ StringMapEntry<T> *entry = map->entries+index;
+ if (entry->hash != 0) {
+ return *this;
+ }
+ }
+ }
+
+ bool operator==(StringMapIterator<T> const &other) const noexcept {
+ return this->map == other->map && this->index == other->index;
+ }
+
+ operator StringMapEntry<T> *() const {
+ return map->entries+index;
+ }
+};
+
template <typename T>
-gb_internal StringMapEntry<T> *begin(StringMap<T> &m) noexcept {
- return m.entries;
+gb_internal StringMapIterator<T> end(StringMap<T> &m) noexcept {
+ return StringMapIterator<T>{&m, m.capacity};
}
+
template <typename T>
-gb_internal StringMapEntry<T> const *begin(StringMap<T> const &m) noexcept {
- return m.entries;
+gb_internal StringMapIterator<T> const end(StringMap<T> const &m) noexcept {
+ return StringMapIterator<T>{&m, m.capacity};
}
+
template <typename T>
-gb_internal StringMapEntry<T> *end(StringMap<T> &m) {
- return m.entries + m.count;
-}
+gb_internal StringMapIterator<T> begin(StringMap<T> &m) noexcept {
+ if (m.count == 0) {
+ return end(m);
+ }
+ MapIndex index = 0;
+ while (index < m.capacity) {
+ if (m.entries[index].hash) {
+ break;
+ }
+ index++;
+ }
+ return StringMapIterator<T>{&m, index};
+}
template <typename T>
-gb_internal StringMapEntry<T> const *end(StringMap<T> const &m) noexcept {
- return m.entries + m.count;
-} \ No newline at end of file
+gb_internal StringMapIterator<T> const begin(StringMap<T> const &m) noexcept {
+ if (m.count == 0) {
+ return end(m);
+ }
+
+ MapIndex index = 0;
+ while (index < m.capacity) {
+ if (m.entries[index].hash) {
+ break;
+ }
+ index++;
+ }
+ return StringMapIterator<T>{&m, index};
+}
diff --git a/src/string_set.cpp b/src/string_set.cpp
index fb4640c20..a37d8ba80 100644
--- a/src/string_set.cpp
+++ b/src/string_set.cpp
@@ -208,7 +208,9 @@ gb_internal void string_set__erase(StringSet *s, MapFindResult fr) {
}
auto *entry = &s->entries[fr.entry_index];
*entry = s->entries[s->entries.count-1];
- StringHashKey key = {entry->hash, entry->value};
+ StringHashKey key;
+ key.hash = entry->hash;
+ key.string = entry->value;
last = string_set__find(s, key);
if (last.entry_prev != MAP_SENTINEL) {
s->entries[last.entry_prev].next = fr.entry_index;
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index fdff9224a..f7751d840 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -767,9 +767,8 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
}
}
- // TODO(bill): Better Error Handling
if (valid && n != 1) {
- tokenizer_err(t, "Invalid rune literal");
+ tokenizer_err(t, token->pos, "Invalid rune literal");
}
token->string.len = t->curr - token->string.text;
goto semicolon_check;