Browse Source

Simplify compiler's `Map` and create a `StringMap` specifically for strings

gingerBill 5 years ago
parent
commit
f09b6a4c90
19 changed files with 524 additions and 277 deletions
  1. 10 10
      src/check_decl.cpp
  2. 9 11
      src/check_expr.cpp
  3. 3 3
      src/check_stmt.cpp
  4. 36 44
      src/checker.cpp
  5. 7 7
      src/checker.hpp
  6. 51 7
      src/common.cpp
  7. 4 1
      src/exact_value.cpp
  8. 43 45
      src/ir.cpp
  9. 4 4
      src/ir_print.cpp
  10. 18 20
      src/llvm_backend.cpp
  11. 3 3
      src/llvm_backend.hpp
  12. 2 1
      src/main.cpp
  13. 33 82
      src/map.cpp
  14. 5 5
      src/parser.cpp
  15. 10 10
      src/parser.hpp
  16. 2 2
      src/query_data.cpp
  17. 257 0
      src/string_map.cpp
  18. 26 21
      src/string_set.cpp
  19. 1 1
      src/types.cpp

+ 10 - 10
src/check_decl.cpp

@@ -349,7 +349,7 @@ void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
 
 
 	// GB_ASSERT_MSG(found_entity == original_entity, "%.*s == %.*s", LIT(found_entity->token.string), LIT(new_entity->token.string));
 	// GB_ASSERT_MSG(found_entity == original_entity, "%.*s == %.*s", LIT(found_entity->token.string), LIT(new_entity->token.string));
 
 
-	map_set(&found_scope->elements, hash_string(original_name), new_entity);
+	string_map_set(&found_scope->elements, original_name, new_entity);
 }
 }
 
 
 
 
@@ -777,8 +777,8 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 		init_entity_foreign_library(ctx, e);
 		init_entity_foreign_library(ctx, e);
 
 
 		auto *fp = &ctx->info->foreigns;
 		auto *fp = &ctx->info->foreigns;
-		HashKey key = hash_string(name);
-		Entity **found = map_get(fp, key);
+		StringHashKey key = string_hash_string(name);
+		Entity **found = string_map_get(fp, key);
 		if (found) {
 		if (found) {
 			Entity *f = *found;
 			Entity *f = *found;
 			TokenPos pos = f->token.pos;
 			TokenPos pos = f->token.pos;
@@ -800,7 +800,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 		} else if (name == "main") {
 		} else if (name == "main") {
 			error(d->proc_lit, "The link name 'main' is reserved for internal use");
 			error(d->proc_lit, "The link name 'main' is reserved for internal use");
 		} else {
 		} else {
-			map_set(fp, key, e);
+			string_map_set(fp, key, e);
 		}
 		}
 	} else {
 	} else {
 		String name = e->token.string;
 		String name = e->token.string;
@@ -809,8 +809,8 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 		}
 		}
 		if (e->Procedure.link_name.len > 0 || is_export) {
 		if (e->Procedure.link_name.len > 0 || is_export) {
 			auto *fp = &ctx->info->foreigns;
 			auto *fp = &ctx->info->foreigns;
-			HashKey key = hash_string(name);
-			Entity **found = map_get(fp, key);
+			StringHashKey key = string_hash_string(name);
+			Entity **found = string_map_get(fp, key);
 			if (found) {
 			if (found) {
 				Entity *f = *found;
 				Entity *f = *found;
 				TokenPos pos = f->token.pos;
 				TokenPos pos = f->token.pos;
@@ -822,7 +822,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 			} else if (name == "main") {
 			} else if (name == "main") {
 				error(d->proc_lit, "The link name 'main' is reserved for internal use");
 				error(d->proc_lit, "The link name 'main' is reserved for internal use");
 			} else {
 			} else {
-				map_set(fp, key, e);
+				string_map_set(fp, key, e);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -898,8 +898,8 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr,
 		}
 		}
 
 
 		auto *fp = &ctx->info->foreigns;
 		auto *fp = &ctx->info->foreigns;
-		HashKey key = hash_string(name);
-		Entity **found = map_get(fp, key);
+		StringHashKey key = string_hash_string(name);
+		Entity **found = string_map_get(fp, key);
 		if (found) {
 		if (found) {
 			Entity *f = *found;
 			Entity *f = *found;
 			TokenPos pos = f->token.pos;
 			TokenPos pos = f->token.pos;
@@ -912,7 +912,7 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr,
 				      LIT(name), LIT(pos.file), pos.line, pos.column);
 				      LIT(name), LIT(pos.file), pos.line, pos.column);
 			}
 			}
 		} else {
 		} else {
-			map_set(fp, key, e);
+			string_map_set(fp, key, e);
 		}
 		}
 	}
 	}
 
 

+ 9 - 11
src/check_expr.cpp

@@ -1065,8 +1065,6 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
 		}
 		}
 	}
 	}
 
 
-	HashKey key = hash_string(e->token.string);
-
 	if (e->kind == Entity_ProcGroup) {
 	if (e->kind == Entity_ProcGroup) {
 		auto *pge = &e->ProcGroup;
 		auto *pge = &e->ProcGroup;
 
 
@@ -6421,9 +6419,9 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
 		// NOTE(bill): This is give type hints for the named parameters
 		// NOTE(bill): This is give type hints for the named parameters
 		// in order to improve the type inference system
 		// in order to improve the type inference system
 
 
-		Map<Type *> type_hint_map = {}; // Key: String
-		map_init(&type_hint_map, heap_allocator(), 2*ce->args.count);
-		defer (map_destroy(&type_hint_map));
+		StringMap<Type *> type_hint_map = {}; // Key: String
+		string_map_init(&type_hint_map, heap_allocator(), 2*ce->args.count);
+		defer (string_map_destroy(&type_hint_map));
 
 
 		Type *ptype = nullptr;
 		Type *ptype = nullptr;
 		bool single_case = true;
 		bool single_case = true;
@@ -6453,7 +6451,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
 						if (is_blank_ident(e->token)) {
 						if (is_blank_ident(e->token)) {
 							continue;
 							continue;
 						}
 						}
-						map_set(&type_hint_map, hash_string(e->token.string), e->type);
+						string_map_set(&type_hint_map, e->token.string, e->type);
 					}
 					}
 				}
 				}
 			}
 			}
@@ -6475,8 +6473,8 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
 						if (is_blank_ident(e->token)) {
 						if (is_blank_ident(e->token)) {
 							continue;
 							continue;
 						}
 						}
-						HashKey key = hash_string(e->token.string);
-						Type **found = map_get(&type_hint_map, key);
+						StringHashKey key = string_hash_string(e->token.string);
+						Type **found = string_map_get(&type_hint_map, key);
 						if (found) {
 						if (found) {
 							Type *t = *found;
 							Type *t = *found;
 							if (t == nullptr) {
 							if (t == nullptr) {
@@ -6487,10 +6485,10 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
 								// NOTE(bill): No need to set again
 								// NOTE(bill): No need to set again
 							} else {
 							} else {
 								// NOTE(bill): Ambiguous named parameter across all types so set it to a nullptr
 								// NOTE(bill): Ambiguous named parameter across all types so set it to a nullptr
-								map_set(&type_hint_map, key, cast(Type *)nullptr);
+								string_map_set(&type_hint_map, key, cast(Type *)nullptr);
 							}
 							}
 						} else {
 						} else {
-							map_set(&type_hint_map, key, e->type);
+							string_map_set(&type_hint_map, key, e->type);
 						}
 						}
 					}
 					}
 				}
 				}
@@ -6508,7 +6506,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
 
 
 			if (field != nullptr && field->kind == Ast_Ident) {
 			if (field != nullptr && field->kind == Ast_Ident) {
 				String key = field->Ident.token.string;
 				String key = field->Ident.token.string;
-				Type **found = map_get(&type_hint_map, hash_string(key));
+				Type **found = string_map_get(&type_hint_map, key);
 				if (found) {
 				if (found) {
 					type_hint = *found;
 					type_hint = *found;
 				}
 				}

+ 3 - 3
src/check_stmt.cpp

@@ -1959,8 +1959,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 					init_entity_foreign_library(ctx, e);
 					init_entity_foreign_library(ctx, e);
 
 
 					auto *fp = &ctx->checker->info.foreigns;
 					auto *fp = &ctx->checker->info.foreigns;
-					HashKey key = hash_string(name);
-					Entity **found = map_get(fp, key);
+					StringHashKey key = string_hash_string(name);
+					Entity **found = string_map_get(fp, key);
 					if (found) {
 					if (found) {
 						Entity *f = *found;
 						Entity *f = *found;
 						TokenPos pos = f->token.pos;
 						TokenPos pos = f->token.pos;
@@ -1973,7 +1973,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 							      LIT(name), LIT(pos.file), pos.line, pos.column);
 							      LIT(name), LIT(pos.file), pos.line, pos.column);
 						}
 						}
 					} else {
 					} else {
-						map_set(fp, key, e);
+						string_map_set(fp, key, e);
 					}
 					}
 				} else if (e->flags & EntityFlag_Static) {
 				} else if (e->flags & EntityFlag_Static) {
 					if (vd->values.count > 0) {
 					if (vd->values.count > 0) {

+ 36 - 44
src/checker.cpp

@@ -29,14 +29,14 @@ void scope_reset(Scope *scope) {
 
 
 	scope->first_child = nullptr;
 	scope->first_child = nullptr;
 	scope->last_child  = nullptr;
 	scope->last_child  = nullptr;
-	map_clear    (&scope->elements);
+	string_map_clear(&scope->elements);
 	ptr_set_clear(&scope->imported);
 	ptr_set_clear(&scope->imported);
 }
 }
 
 
 void scope_reserve(Scope *scope, isize capacity) {
 void scope_reserve(Scope *scope, isize capacity) {
 	isize cap = 2*capacity;
 	isize cap = 2*capacity;
 	if (cap > scope->elements.hashes.count) {
 	if (cap > scope->elements.hashes.count) {
-		map_rehash(&scope->elements, capacity);
+		string_map_rehash(&scope->elements, capacity);
 	}
 	}
 }
 }
 
 
@@ -221,7 +221,7 @@ bool decl_info_has_init(DeclInfo *d) {
 Scope *create_scope(Scope *parent, gbAllocator allocator, isize init_elements_capacity=16) {
 Scope *create_scope(Scope *parent, gbAllocator allocator, isize init_elements_capacity=16) {
 	Scope *s = gb_alloc_item(allocator, Scope);
 	Scope *s = gb_alloc_item(allocator, Scope);
 	s->parent = parent;
 	s->parent = parent;
-	map_init(&s->elements, heap_allocator(), init_elements_capacity);
+	string_map_init(&s->elements, heap_allocator(), init_elements_capacity);
 	ptr_set_init(&s->imported, heap_allocator(), 0);
 	ptr_set_init(&s->imported, heap_allocator(), 0);
 
 
 	s->delayed_imports.allocator = heap_allocator();
 	s->delayed_imports.allocator = heap_allocator();
@@ -295,7 +295,7 @@ void destroy_scope(Scope *scope) {
 		destroy_scope(child);
 		destroy_scope(child);
 	}
 	}
 
 
-	map_destroy(&scope->elements);
+	string_map_destroy(&scope->elements);
 	array_free(&scope->delayed_imports);
 	array_free(&scope->delayed_imports);
 	array_free(&scope->delayed_directives);
 	array_free(&scope->delayed_directives);
 	ptr_set_destroy(&scope->imported);
 	ptr_set_destroy(&scope->imported);
@@ -340,21 +340,20 @@ void check_close_scope(CheckerContext *c) {
 }
 }
 
 
 
 
-Entity *scope_lookup_current(Scope *s, String name) {
-	HashKey key = hash_string(name);
-	Entity **found = map_get(&s->elements, key);
+Entity *scope_lookup_current(Scope *s, String const &name) {
+	Entity **found = string_map_get(&s->elements, name);
 	if (found) {
 	if (found) {
 		return *found;
 		return *found;
 	}
 	}
 	return nullptr;
 	return nullptr;
 }
 }
 
 
-void scope_lookup_parent(Scope *scope, String name, Scope **scope_, Entity **entity_) {
+void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_) {
 	bool gone_thru_proc = false;
 	bool gone_thru_proc = false;
 	bool gone_thru_package = false;
 	bool gone_thru_package = false;
-	HashKey key = hash_string(name);
+	StringHashKey key = string_hash_string(name);
 	for (Scope *s = scope; s != nullptr; s = s->parent) {
 	for (Scope *s = scope; s != nullptr; s = s->parent) {
-		Entity **found = map_get(&s->elements, key);
+		Entity **found = string_map_get(&s->elements, key);
 		if (found) {
 		if (found) {
 			Entity *e = *found;
 			Entity *e = *found;
 			if (gone_thru_proc) {
 			if (gone_thru_proc) {
@@ -386,7 +385,7 @@ void scope_lookup_parent(Scope *scope, String name, Scope **scope_, Entity **ent
 	if (scope_) *scope_ = nullptr;
 	if (scope_) *scope_ = nullptr;
 }
 }
 
 
-Entity *scope_lookup(Scope *s, String name) {
+Entity *scope_lookup(Scope *s, String const &name) {
 	Entity *entity = nullptr;
 	Entity *entity = nullptr;
 	scope_lookup_parent(s, name, nullptr, &entity);
 	scope_lookup_parent(s, name, nullptr, &entity);
 	return entity;
 	return entity;
@@ -394,18 +393,18 @@ Entity *scope_lookup(Scope *s, String name) {
 
 
 
 
 
 
-Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) {
+Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity) {
 	if (name == "") {
 	if (name == "") {
 		return nullptr;
 		return nullptr;
 	}
 	}
-	HashKey key = hash_string(name);
-	Entity **found = map_get(&s->elements, key);
+	StringHashKey key = string_hash_string(name);
+	Entity **found = string_map_get(&s->elements, key);
 
 
 	if (found) {
 	if (found) {
 		return *found;
 		return *found;
 	}
 	}
 	if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) {
 	if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) {
-		Entity **found = map_get(&s->parent->elements, key);
+		Entity **found = string_map_get(&s->parent->elements, key);
 		if (found) {
 		if (found) {
 			if ((*found)->flags & EntityFlag_Result) {
 			if ((*found)->flags & EntityFlag_Result) {
 				return *found;
 				return *found;
@@ -413,7 +412,7 @@ Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) {
 		}
 		}
 	}
 	}
 
 
-	map_set(&s->elements, key, entity);
+	string_map_set(&s->elements, key, entity);
 	if (entity->scope == nullptr) {
 	if (entity->scope == nullptr) {
 		entity->scope = s;
 		entity->scope = s;
 	}
 	}
@@ -611,8 +610,7 @@ AstPackage *get_core_package(CheckerInfo *info, String name) {
 	gbAllocator a = heap_allocator();
 	gbAllocator a = heap_allocator();
 	String path = get_fullpath_core(a, name);
 	String path = get_fullpath_core(a, name);
 	defer (gb_free(a, path.text));
 	defer (gb_free(a, path.text));
-	HashKey key = hash_string(path);
-	auto found = map_get(&info->packages, key);
+	auto found = string_map_get(&info->packages, path);
 	GB_ASSERT_MSG(found != nullptr, "Missing core package %.*s", LIT(name));
 	GB_ASSERT_MSG(found != nullptr, "Missing core package %.*s", LIT(name));
 	return *found;
 	return *found;
 }
 }
@@ -744,7 +742,7 @@ void init_universal(void) {
 
 
 	bool defined_values_double_declaration = false;
 	bool defined_values_double_declaration = false;
 	for_array(i, bc->defined_values.entries) {
 	for_array(i, bc->defined_values.entries) {
-		String name = bc->defined_values.entries[i].key.string;
+		char const *name = cast(char const *)cast(uintptr)bc->defined_values.entries[i].key.key;
 		ExactValue value = bc->defined_values.entries[i].value;
 		ExactValue value = bc->defined_values.entries[i].value;
 		GB_ASSERT(value.kind != ExactValue_Invalid);
 		GB_ASSERT(value.kind != ExactValue_Invalid);
 
 
@@ -770,7 +768,7 @@ void init_universal(void) {
 		Entity *entity = alloc_entity_constant(nullptr, make_token_ident(name), type, value);
 		Entity *entity = alloc_entity_constant(nullptr, make_token_ident(name), type, value);
 		entity->state = EntityState_Resolved;
 		entity->state = EntityState_Resolved;
 		if (scope_insert(builtin_pkg->scope, entity)) {
 		if (scope_insert(builtin_pkg->scope, entity)) {
-			error(entity->token, "'%.*s' defined as an argument is already declared at the global scope", LIT(name));
+			error(entity->token, "'%s' defined as an argument is already declared at the global scope", name);
 			defined_values_double_declaration = true;
 			defined_values_double_declaration = true;
 			// NOTE(bill): Just exit early before anything, even though the compiler will do that anyway
 			// NOTE(bill): Just exit early before anything, even though the compiler will do that anyway
 		}
 		}
@@ -797,13 +795,13 @@ void init_checker_info(CheckerInfo *i) {
 	array_init(&i->definitions,   a);
 	array_init(&i->definitions,   a);
 	array_init(&i->entities,      a);
 	array_init(&i->entities,      a);
 	map_init(&i->untyped,         a);
 	map_init(&i->untyped,         a);
-	map_init(&i->foreigns,        a);
+	string_map_init(&i->foreigns, a);
 	map_init(&i->gen_procs,       a);
 	map_init(&i->gen_procs,       a);
 	map_init(&i->gen_types,       a);
 	map_init(&i->gen_types,       a);
 	array_init(&i->type_info_types, a);
 	array_init(&i->type_info_types, a);
 	map_init(&i->type_info_map,   a);
 	map_init(&i->type_info_map,   a);
-	map_init(&i->files,           a);
-	map_init(&i->packages,        a);
+	string_map_init(&i->files,    a);
+	string_map_init(&i->packages, a);
 	array_init(&i->variable_init_order, a);
 	array_init(&i->variable_init_order, a);
 	array_init(&i->required_foreign_imports_through_force, a);
 	array_init(&i->required_foreign_imports_through_force, a);
 	array_init(&i->required_global_variables, a);
 	array_init(&i->required_global_variables, a);
@@ -818,13 +816,13 @@ void destroy_checker_info(CheckerInfo *i) {
 	array_free(&i->definitions);
 	array_free(&i->definitions);
 	array_free(&i->entities);
 	array_free(&i->entities);
 	map_destroy(&i->untyped);
 	map_destroy(&i->untyped);
-	map_destroy(&i->foreigns);
+	string_map_destroy(&i->foreigns);
 	map_destroy(&i->gen_procs);
 	map_destroy(&i->gen_procs);
 	map_destroy(&i->gen_types);
 	map_destroy(&i->gen_types);
 	array_free(&i->type_info_types);
 	array_free(&i->type_info_types);
 	map_destroy(&i->type_info_map);
 	map_destroy(&i->type_info_map);
-	map_destroy(&i->files);
-	map_destroy(&i->packages);
+	string_map_destroy(&i->files);
+	string_map_destroy(&i->packages);
 	array_free(&i->variable_init_order);
 	array_free(&i->variable_init_order);
 	array_free(&i->identifier_uses);
 	array_free(&i->identifier_uses);
 	array_free(&i->required_foreign_imports_through_force);
 	array_free(&i->required_foreign_imports_through_force);
@@ -956,7 +954,7 @@ DeclInfo *decl_info_of_ident(Ast *ident) {
 }
 }
 
 
 AstFile *ast_file_of_filename(CheckerInfo *i, String filename) {
 AstFile *ast_file_of_filename(CheckerInfo *i, String filename) {
-	AstFile **found = map_get(&i->files, hash_string(filename));
+	AstFile **found = string_map_get(&i->files, filename);
 	if (found != nullptr) {
 	if (found != nullptr) {
 		return *found;
 		return *found;
 	}
 	}
@@ -994,7 +992,7 @@ isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
 		// TODO(bill): This is O(n) and can be very slow
 		// TODO(bill): This is O(n) and can be very slow
 		for_array(i, info->type_info_map.entries){
 		for_array(i, info->type_info_map.entries){
 			auto *e = &info->type_info_map.entries[i];
 			auto *e = &info->type_info_map.entries[i];
-			Type *prev_type = cast(Type *)e->key.ptr;
+			Type *prev_type = cast(Type *)cast(uintptr)e->key.key;
 			if (are_types_identical(prev_type, type)) {
 			if (are_types_identical(prev_type, type)) {
 				entry_index = e->value;
 				entry_index = e->value;
 				// NOTE(bill): Add it to the search map
 				// NOTE(bill): Add it to the search map
@@ -1234,7 +1232,7 @@ void add_type_info_type(CheckerContext *c, Type *t) {
 	isize ti_index = -1;
 	isize ti_index = -1;
 	for_array(i, c->info->type_info_map.entries) {
 	for_array(i, c->info->type_info_map.entries) {
 		auto *e = &c->info->type_info_map.entries[i];
 		auto *e = &c->info->type_info_map.entries[i];
-		Type *prev_type = cast(Type *)e->key.ptr;
+		Type *prev_type = cast(Type *)cast(uintptr)e->key.key;
 		if (are_types_identical(t, prev_type)) {
 		if (are_types_identical(t, prev_type)) {
 			// Duplicate entry
 			// Duplicate entry
 			ti_index = e->value;
 			ti_index = e->value;
@@ -1811,7 +1809,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
 	TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 1");
 	TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 1");
 	// Calculate edges for graph M
 	// Calculate edges for graph M
 	for_array(i, M.entries) {
 	for_array(i, M.entries) {
-		Entity *   e = cast(Entity *)M.entries[i].key.ptr;
+		Entity *   e = cast(Entity *)cast(uintptr)M.entries[i].key.key;
 		EntityGraphNode *n = M.entries[i].value;
 		EntityGraphNode *n = M.entries[i].value;
 
 
 		DeclInfo *decl = decl_info_of_entity(e);
 		DeclInfo *decl = decl_info_of_entity(e);
@@ -1838,7 +1836,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
 
 
 	for_array(i, M.entries) {
 	for_array(i, M.entries) {
 		auto *entry = &M.entries[i];
 		auto *entry = &M.entries[i];
-		auto *e = cast(Entity *)entry->key.ptr;
+		auto *e = cast(Entity *)cast(uintptr)entry->key.key;
 		EntityGraphNode *n = entry->value;
 		EntityGraphNode *n = entry->value;
 
 
 		if (e->kind == Entity_Procedure) {
 		if (e->kind == Entity_Procedure) {
@@ -3072,8 +3070,7 @@ void add_import_dependency_node(Checker *c, Ast *decl, Map<ImportGraphNode *> *M
 		if (is_package_name_reserved(path)) {
 		if (is_package_name_reserved(path)) {
 			return;
 			return;
 		}
 		}
-		HashKey key = hash_string(path);
-		AstPackage **found = map_get(&c->info.packages, key);
+		AstPackage **found = string_map_get(&c->info.packages, path);
 		if (found == nullptr) {
 		if (found == nullptr) {
 			for_array(pkg_index, c->info.packages.entries) {
 			for_array(pkg_index, c->info.packages.entries) {
 				AstPackage *pkg = c->info.packages.entries[pkg_index].value;
 				AstPackage *pkg = c->info.packages.entries[pkg_index].value;
@@ -3185,8 +3182,7 @@ Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start, AstPackage
 
 
 
 
 	String path = start->fullpath;
 	String path = start->fullpath;
-	HashKey key = hash_string(path);
-	AstPackage **found = map_get(&c->info.packages, key);
+	AstPackage **found = string_map_get(&c->info.packages, path);
 	if (found) {
 	if (found) {
 		AstPackage *pkg = *found;
 		AstPackage *pkg = *found;
 		GB_ASSERT(pkg != nullptr);
 		GB_ASSERT(pkg != nullptr);
@@ -3248,8 +3244,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
 		scope = intrinsics_pkg->scope;
 		scope = intrinsics_pkg->scope;
 		intrinsics_pkg->used = true;
 		intrinsics_pkg->used = true;
 	} else {
 	} else {
-		HashKey key = hash_string(id->fullpath);
-		AstPackage **found = map_get(pkgs, key);
+		AstPackage **found = string_map_get(pkgs, id->fullpath);
 		if (found == nullptr) {
 		if (found == nullptr) {
 			for_array(pkg_index, pkgs->entries) {
 			for_array(pkg_index, pkgs->entries) {
 				AstPackage *pkg = pkgs->entries[pkg_index].value;
 				AstPackage *pkg = pkgs->entries[pkg_index].value;
@@ -3398,8 +3393,7 @@ bool collect_checked_packages_from_decl_list(Checker *c, Array<Ast *> const &dec
 		Ast *decl = decls[i];
 		Ast *decl = decls[i];
 		switch (decl->kind) {
 		switch (decl->kind) {
 		case_ast_node(id, ImportDecl, decl);
 		case_ast_node(id, ImportDecl, decl);
-			HashKey key = hash_string(id->fullpath);
-			AstPackage **found = map_get(&c->info.packages, key);
+			AstPackage **found = string_map_get(&c->info.packages, id->fullpath);
 			if (found == nullptr) {
 			if (found == nullptr) {
 				continue;
 				continue;
 			}
 			}
@@ -3907,8 +3901,7 @@ void check_parsed_files(Checker *c) {
 		AstPackage *p = c->parser->packages[i];
 		AstPackage *p = c->parser->packages[i];
 		Scope *scope = create_scope_from_package(&c->init_ctx, p);
 		Scope *scope = create_scope_from_package(&c->init_ctx, p);
 		p->decl_info = make_decl_info(c->allocator, scope, c->init_ctx.decl);
 		p->decl_info = make_decl_info(c->allocator, scope, c->init_ctx.decl);
-		HashKey key = hash_string(p->fullpath);
-		map_set(&c->info.packages, key, p);
+		string_map_set(&c->info.packages, p->fullpath, p);
 
 
 		if (scope->flags&ScopeFlag_Init) {
 		if (scope->flags&ScopeFlag_Init) {
 			c->info.init_scope = scope;
 			c->info.init_scope = scope;
@@ -3932,8 +3925,7 @@ void check_parsed_files(Checker *c) {
 		for_array(j, pkg->files) {
 		for_array(j, pkg->files) {
 			AstFile *f = pkg->files[j];
 			AstFile *f = pkg->files[j];
 			create_scope_from_file(&ctx, f);
 			create_scope_from_file(&ctx, f);
-			HashKey key = hash_string(f->fullpath);
-			map_set(&c->info.files, key, f);
+			string_map_set(&c->info.files, f->fullpath, f);
 
 
 			add_curr_ast_file(&ctx, f);
 			add_curr_ast_file(&ctx, f);
 			check_collect_entities(&ctx, f->decls);
 			check_collect_entities(&ctx, f->decls);
@@ -3978,7 +3970,7 @@ void check_parsed_files(Checker *c) {
 	for_array(i, c->info.untyped.entries) {
 	for_array(i, c->info.untyped.entries) {
 		auto *entry = &c->info.untyped.entries[i];
 		auto *entry = &c->info.untyped.entries[i];
 		HashKey key = entry->key;
 		HashKey key = entry->key;
-		Ast *expr = cast(Ast *)key.ptr;
+		Ast *expr = cast(Ast *)cast(uintptr)key.key;
 		ExprInfo *info = &entry->value;
 		ExprInfo *info = &entry->value;
 		if (info != nullptr && expr != nullptr) {
 		if (info != nullptr && expr != nullptr) {
 			if (is_type_typed(info->type)) {
 			if (is_type_typed(info->type)) {

+ 7 - 7
src/checker.hpp

@@ -172,7 +172,7 @@ struct Scope {
 	Scope *       next;
 	Scope *       next;
 	Scope *       first_child;
 	Scope *       first_child;
 	Scope *       last_child;
 	Scope *       last_child;
-	Map<Entity *> elements; // Key: String
+	StringMap<Entity *> elements; 
 
 
 	Array<Ast *>    delayed_directives;
 	Array<Ast *>    delayed_directives;
 	Array<Ast *>    delayed_imports;
 	Array<Ast *>    delayed_imports;
@@ -238,9 +238,9 @@ struct CheckerInfo {
 	Map<ExprInfo>         untyped; // Key: Ast * | Expression -> ExprInfo
 	Map<ExprInfo>         untyped; // Key: Ast * | Expression -> ExprInfo
 	                               // NOTE(bill): This needs to be a map and not on the Ast
 	                               // NOTE(bill): This needs to be a map and not on the Ast
 	                               // as it needs to be iterated across
 	                               // as it needs to be iterated across
-	Map<AstFile *>        files;           // Key: String (full path)
-	Map<AstPackage *>     packages;        // Key: String (full path)
-	Map<Entity *>         foreigns;        // Key: String
+	StringMap<AstFile *>    files;    // Key (full path)
+	StringMap<AstPackage *> packages; // Key (full path)
+	StringMap<Entity *>     foreigns; 
 	Array<Entity *>       definitions;
 	Array<Entity *>       definitions;
 	Array<Entity *>       entities;
 	Array<Entity *>       entities;
 	Array<DeclInfo *>     variable_init_order;
 	Array<DeclInfo *>     variable_init_order;
@@ -346,9 +346,9 @@ isize        type_info_index        (CheckerInfo *i, Type *type, bool error_on_f
 Entity *entity_of_node(Ast *expr);
 Entity *entity_of_node(Ast *expr);
 
 
 
 
-Entity *scope_lookup_current(Scope *s, String name);
-Entity *scope_lookup (Scope *s, String name);
-void    scope_lookup_parent (Scope *s, String name, Scope **scope_, Entity **entity_);
+Entity *scope_lookup_current(Scope *s, String const &name);
+Entity *scope_lookup (Scope *s, String const &name);
+void    scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_);
 Entity *scope_insert (Scope *s, Entity *entity);
 Entity *scope_insert (Scope *s, Entity *entity);
 
 
 
 

+ 51 - 7
src/common.cpp

@@ -340,13 +340,6 @@ void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
 
 
 
 
 
 
-#include "map.cpp"
-#include "ptr_set.cpp"
-#include "string_set.cpp"
-#include "priority_queue.cpp"
-#include "thread_pool.cpp"
-
-
 gb_global String global_module_path = {0};
 gb_global String global_module_path = {0};
 gb_global bool global_module_path_set = false;
 gb_global bool global_module_path_set = false;
 
 
@@ -465,6 +458,57 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) {
 
 
 
 
 
 
+
+#include "string_map.cpp"
+#include "map.cpp"
+#include "ptr_set.cpp"
+#include "string_set.cpp"
+#include "priority_queue.cpp"
+#include "thread_pool.cpp"
+
+
+struct StringIntern {
+	isize len;
+	StringIntern *next;
+	char str[1];
+};
+
+Map<StringIntern *> string_intern_map = {}; // Key: u64
+Arena string_intern_arena = {};
+
+char const *string_intern(char const *text, isize len) {
+	u64 hash = gb_fnv64a(text, len);
+	u64 key = hash ? hash : 1;
+	StringIntern **found = map_get(&string_intern_map, hash_integer(key));
+	if (found) {
+		for (StringIntern *it = *found; it != nullptr; it = it->next) {
+			if (it->len == len && gb_strncmp(it->str, (char *)text, len) == 0) {
+				return it->str;
+			}
+		}
+	}
+
+	StringIntern *new_intern = cast(StringIntern *)arena_alloc(&string_intern_arena, gb_offset_of(StringIntern, str) + len + 1, gb_align_of(StringIntern));
+	new_intern->len = len;
+	new_intern->next = found ? *found : nullptr;
+	gb_memmove(new_intern->str, text, len);
+	new_intern->str[len] = 0;
+	map_set(&string_intern_map, hash_integer(key), new_intern);
+	return new_intern->str;
+}
+
+char const *string_intern(String const &string) {
+	return string_intern(cast(char const *)string.text, string.len);
+}
+
+void init_string_interner(void) {
+	map_init(&string_intern_map, heap_allocator());
+	arena_init(&string_intern_arena, heap_allocator());
+}
+
+
+
+
 i32 next_pow2(i32 n) {
 i32 next_pow2(i32 n) {
 	if (n <= 0) {
 	if (n <= 0) {
 		return 0;
 		return 0;

+ 4 - 1
src/exact_value.cpp

@@ -69,7 +69,10 @@ HashKey hash_exact_value(ExactValue v) {
 	case ExactValue_Bool:
 	case ExactValue_Bool:
 		return hash_integer(u64(v.value_bool));
 		return hash_integer(u64(v.value_bool));
 	case ExactValue_String:
 	case ExactValue_String:
-		return hash_string(v.value_string);
+		{
+			char const *str = string_intern(v.value_string);
+			return hash_pointer(str);
+		}
 	case ExactValue_Integer:
 	case ExactValue_Integer:
 		{
 		{
 			HashKey key = hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64));
 			HashKey key = hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64));

+ 43 - 45
src/ir.cpp

@@ -20,7 +20,7 @@ struct irModule {
 
 
 	PtrSet<Entity *>      min_dep_set;
 	PtrSet<Entity *>      min_dep_set;
 	Map<irValue *>        values;              // Key: Entity *
 	Map<irValue *>        values;              // Key: Entity *
-	Map<irValue *>        members;             // Key: String
+	StringMap<irValue *>  members;             
 	Map<String>           entity_names;        // Key: Entity * of the typename
 	Map<String>           entity_names;        // Key: Entity * of the typename
 	Map<irDebugInfo *>    debug_info;          // Key: Unique pointer
 	Map<irDebugInfo *>    debug_info;          // Key: Unique pointer
 	Map<irValue *>        anonymous_proc_lits; // Key: Ast *
 	Map<irValue *>        anonymous_proc_lits; // Key: Ast *
@@ -37,8 +37,8 @@ struct irModule {
 
 
 	// NOTE(bill): To prevent strings from being copied a lot
 	// NOTE(bill): To prevent strings from being copied a lot
 	// Mainly used for file names
 	// Mainly used for file names
-	Map<irValue *>        const_strings; // Key: String
-	Map<irValue *>        const_string_byte_slices; // Key: String
+	StringMap<irValue *>  const_strings;
+	StringMap<irValue *>  const_string_byte_slices;
 	Map<irValue *>        constant_value_to_global; // Key: irValue *
 	Map<irValue *>        constant_value_to_global; // Key: irValue *
 
 
 
 
@@ -1509,7 +1509,7 @@ irValue *ir_generate_array(irModule *m, Type *elem_type, i64 count, String prefi
 	irValue *value = ir_value_global(e, nullptr);
 	irValue *value = ir_value_global(e, nullptr);
 	value->Global.is_private = true;
 	value->Global.is_private = true;
 	ir_module_add_value(m, e, value);
 	ir_module_add_value(m, e, value);
-	map_set(&m->members, hash_string(s), value);
+	string_map_set(&m->members, s, value);
 	return value;
 	return value;
 }
 }
 
 
@@ -1626,7 +1626,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) {
 			Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
 			Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
 			irValue *g = ir_value_global(e, backing_array);
 			irValue *g = ir_value_global(e, backing_array);
 			ir_module_add_value(m, e, g);
 			ir_module_add_value(m, e, g);
-			map_set(&m->members, hash_string(name), g);
+			string_map_set(&m->members, name, g);
 
 
 			return ir_value_constant_slice(type, g, count);
 			return ir_value_constant_slice(type, g, count);
 		}
 		}
@@ -1639,8 +1639,7 @@ irValue *ir_add_global_string_array(irModule *m, String string) {
 
 
 	irValue *global_constant_value = nullptr;
 	irValue *global_constant_value = nullptr;
 	{
 	{
-		HashKey key = hash_string(string);
-		irValue **found = map_get(&m->const_string_byte_slices, key);
+		irValue **found = string_map_get(&m->const_string_byte_slices, string);
 		if (found != nullptr) {
 		if (found != nullptr) {
 			global_constant_value = *found;
 			global_constant_value = *found;
 
 
@@ -1677,7 +1676,7 @@ irValue *ir_add_global_string_array(irModule *m, String string) {
 
 
 
 
 	ir_module_add_value(m, entity, g);
 	ir_module_add_value(m, entity, g);
-	map_set(&m->members, hash_string(name), g);
+	string_map_set(&m->members, name, g);
 
 
 	return g;
 	return g;
 }
 }
@@ -1760,8 +1759,8 @@ irValue *ir_add_local_for_identifier(irProcedure *proc, Ast *ident, bool zero_in
 				name = e->Variable.link_name;
 				name = e->Variable.link_name;
 			}
 			}
 
 
-			HashKey key = hash_string(name);
-			irValue **prev_value = map_get(&proc->module->members, key);
+			StringHashKey key = string_hash_string(name);
+			irValue **prev_value = string_map_get(&proc->module->members, key);
 			if (prev_value == nullptr) {
 			if (prev_value == nullptr) {
 				ir_add_foreign_library_path(proc->module, e->Variable.foreign_library);
 				ir_add_foreign_library_path(proc->module, e->Variable.foreign_library);
 				// NOTE(bill): Don't do mutliple declarations in the IR
 				// NOTE(bill): Don't do mutliple declarations in the IR
@@ -1769,7 +1768,7 @@ irValue *ir_add_local_for_identifier(irProcedure *proc, Ast *ident, bool zero_in
 				g->Global.name = name;
 				g->Global.name = name;
 				g->Global.is_foreign = true;
 				g->Global.is_foreign = true;
 				ir_module_add_value(proc->module, e, g);
 				ir_module_add_value(proc->module, e, g);
-				map_set(&proc->module->members, key, g);
+				string_map_set(&proc->module->members, key, g);
 				return g;
 				return g;
 			} else {
 			} else {
 				return *prev_value;
 				return *prev_value;
@@ -1807,7 +1806,7 @@ irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) {
 	Entity *e = alloc_entity_variable(scope, make_token_ident(name), type);
 	Entity *e = alloc_entity_variable(scope, make_token_ident(name), type);
 	irValue *g = ir_value_global(e, value);
 	irValue *g = ir_value_global(e, value);
 	ir_module_add_value(m, e, g);
 	ir_module_add_value(m, e, g);
-	map_set(&m->members, hash_string(name), g);
+	string_map_set(&m->members, name, g);
 	return g;
 	return g;
 }
 }
 
 
@@ -5162,26 +5161,26 @@ irValue *ir_add_local_slice(irProcedure *proc, Type *slice_type, irValue *base,
 
 
 
 
 irValue *ir_find_or_add_entity_string(irModule *m, String str) {
 irValue *ir_find_or_add_entity_string(irModule *m, String str) {
-	HashKey key = hash_string(str);
-	irValue **found = map_get(&m->const_strings, key);
+	StringHashKey key = string_hash_string(str);
+	irValue **found = string_map_get(&m->const_strings, key);
 	if (found != nullptr) {
 	if (found != nullptr) {
 		return *found;
 		return *found;
 	}
 	}
 	irValue *v = ir_value_constant(t_string, exact_value_string(str));
 	irValue *v = ir_value_constant(t_string, exact_value_string(str));
-	map_set(&m->const_strings, key, v);
+	string_map_set(&m->const_strings, key, v);
 	return v;
 	return v;
 
 
 }
 }
 
 
 irValue *ir_find_or_add_entity_string_byte_slice(irModule *m, String str) {
 irValue *ir_find_or_add_entity_string_byte_slice(irModule *m, String str) {
-	HashKey key = hash_string(str);
-	irValue **found = map_get(&m->const_string_byte_slices, key);
+	StringHashKey key = string_hash_string(str);
+	irValue **found = string_map_get(&m->const_string_byte_slices, key);
 	if (found != nullptr) {
 	if (found != nullptr) {
 		return *found;
 		return *found;
 	}
 	}
 	Type *t = t_u8_slice;
 	Type *t = t_u8_slice;
 	irValue *v = ir_value_constant(t, exact_value_string(str));
 	irValue *v = ir_value_constant(t, exact_value_string(str));
-	map_set(&m->const_string_byte_slices, key, v);
+	string_map_set(&m->const_string_byte_slices, key, v);
 	return v;
 	return v;
 
 
 }
 }
@@ -6337,7 +6336,7 @@ irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, i
 	if (proc != nullptr) {
 	if (proc != nullptr) {
 		array_add(&proc->children, &value->Proc);
 		array_add(&proc->children, &value->Proc);
 	} else {
 	} else {
-		map_set(&m->members, hash_string(name), value);
+		string_map_set(&m->members, name, value);
 	}
 	}
 
 
 	map_set(&m->anonymous_proc_lits, hash_pointer(expr), value);
 	map_set(&m->anonymous_proc_lits, hash_pointer(expr), value);
@@ -6384,7 +6383,7 @@ void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
 	}
 	}
 	irValue *t = ir_value_type_name(name, e->type);
 	irValue *t = ir_value_type_name(name, e->type);
 	ir_module_add_value(m, e, t);
 	ir_module_add_value(m, e, t);
-	map_set(&m->members, hash_string(name), t);
+	string_map_set(&m->members, name, t);
 
 
 	// if (bt->kind == Type_Struct) {
 	// if (bt->kind == Type_Struct) {
 	// 	Scope *s = bt->Struct.scope;
 	// 	Scope *s = bt->Struct.scope;
@@ -9196,8 +9195,8 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) {
 					name = e->Procedure.link_name;
 					name = e->Procedure.link_name;
 				}
 				}
 
 
-				HashKey key = hash_string(name);
-				irValue **prev_value = map_get(&proc->module->members, key);
+				StringHashKey key = string_hash_string(name);
+				irValue **prev_value = string_map_get(&proc->module->members, key);
 				if (prev_value != nullptr) {
 				if (prev_value != nullptr) {
 					// NOTE(bill): Don't do mutliple declarations in the IR
 					// NOTE(bill): Don't do mutliple declarations in the IR
 					return;
 					return;
@@ -9210,7 +9209,7 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) {
 				value->Proc.inlining = pl->inlining;
 				value->Proc.inlining = pl->inlining;
 
 
 				if (value->Proc.is_foreign || value->Proc.is_export) {
 				if (value->Proc.is_foreign || value->Proc.is_export) {
-					map_set(&proc->module->members, key, value);
+					string_map_set(&proc->module->members, key, value);
 				} else {
 				} else {
 					array_add(&proc->children, &value->Proc);
 					array_add(&proc->children, &value->Proc);
 				}
 				}
@@ -9721,7 +9720,6 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
 						mangled_name.len = gb_string_length(str);
 						mangled_name.len = gb_string_length(str);
 					}
 					}
 
 
-					HashKey key = hash_string(mangled_name);
 					ir_add_entity_name(m, e, mangled_name);
 					ir_add_entity_name(m, e, mangled_name);
 
 
 					irValue *g = ir_value_global(e, value);
 					irValue *g = ir_value_global(e, value);
@@ -9733,7 +9731,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
 						g->Global.is_internal = true;
 						g->Global.is_internal = true;
 					}
 					}
 					ir_module_add_value(proc->module, e, g);
 					ir_module_add_value(proc->module, e, g);
-					map_set(&proc->module->members, key, g);
+					string_map_set(&proc->module->members, mangled_name, g);
 				}
 				}
 				return;
 				return;
 			}
 			}
@@ -11083,15 +11081,15 @@ void ir_init_module(irModule *m, Checker *c) {
 	}
 	}
 
 
 	map_init(&m->values,                   heap_allocator());
 	map_init(&m->values,                   heap_allocator());
-	map_init(&m->members,                  heap_allocator());
+	string_map_init(&m->members,           heap_allocator());
 	map_init(&m->debug_info,               heap_allocator());
 	map_init(&m->debug_info,               heap_allocator());
 	map_init(&m->entity_names,             heap_allocator());
 	map_init(&m->entity_names,             heap_allocator());
 	map_init(&m->anonymous_proc_lits,      heap_allocator());
 	map_init(&m->anonymous_proc_lits,      heap_allocator());
 	array_init(&m->procs,                  heap_allocator());
 	array_init(&m->procs,                  heap_allocator());
 	array_init(&m->procs_to_generate,      heap_allocator());
 	array_init(&m->procs_to_generate,      heap_allocator());
 	array_init(&m->foreign_library_paths,  heap_allocator());
 	array_init(&m->foreign_library_paths,  heap_allocator());
-	map_init(&m->const_strings,            heap_allocator());
-	map_init(&m->const_string_byte_slices, heap_allocator());
+	string_map_init(&m->const_strings,     heap_allocator());
+	string_map_init(&m->const_string_byte_slices, heap_allocator());
 	map_init(&m->constant_value_to_global, heap_allocator());
 	map_init(&m->constant_value_to_global, heap_allocator());
 
 
 	// Default states
 	// Default states
@@ -11108,7 +11106,7 @@ void ir_init_module(irModule *m, Checker *c) {
 			irValue *g = ir_value_global(e, nullptr);
 			irValue *g = ir_value_global(e, nullptr);
 			g->Global.is_private = true;
 			g->Global.is_private = true;
 			ir_module_add_value(m, e, g);
 			ir_module_add_value(m, e, g);
-			map_set(&m->members, hash_string(name), g);
+			string_map_set(&m->members, name, g);
 			ir_global_type_info_data = g;
 			ir_global_type_info_data = g;
 		}
 		}
 
 
@@ -11145,7 +11143,7 @@ void ir_init_module(irModule *m, Checker *c) {
 					                                  alloc_type_array(t_type_info_ptr, count));
 					                                  alloc_type_array(t_type_info_ptr, count));
 					irValue *g = ir_value_global(e, nullptr);
 					irValue *g = ir_value_global(e, nullptr);
 					ir_module_add_value(m, e, g);
 					ir_module_add_value(m, e, g);
-					map_set(&m->members, hash_string(name), g);
+					string_map_set(&m->members, name, g);
 					ir_global_type_info_member_types = g;
 					ir_global_type_info_member_types = g;
 				}
 				}
 				{
 				{
@@ -11154,7 +11152,7 @@ void ir_init_module(irModule *m, Checker *c) {
 					                                  alloc_type_array(t_string, count));
 					                                  alloc_type_array(t_string, count));
 					irValue *g = ir_value_global(e, nullptr);
 					irValue *g = ir_value_global(e, nullptr);
 					ir_module_add_value(m, e, g);
 					ir_module_add_value(m, e, g);
-					map_set(&m->members, hash_string(name), g);
+					string_map_set(&m->members, name, g);
 					ir_global_type_info_member_names = g;
 					ir_global_type_info_member_names = g;
 				}
 				}
 				{
 				{
@@ -11163,7 +11161,7 @@ void ir_init_module(irModule *m, Checker *c) {
 					                                  alloc_type_array(t_uintptr, count));
 					                                  alloc_type_array(t_uintptr, count));
 					irValue *g = ir_value_global(e, nullptr);
 					irValue *g = ir_value_global(e, nullptr);
 					ir_module_add_value(m, e, g);
 					ir_module_add_value(m, e, g);
-					map_set(&m->members, hash_string(name), g);
+					string_map_set(&m->members, name, g);
 					ir_global_type_info_member_offsets = g;
 					ir_global_type_info_member_offsets = g;
 				}
 				}
 
 
@@ -11173,7 +11171,7 @@ void ir_init_module(irModule *m, Checker *c) {
 					                                  alloc_type_array(t_bool, count));
 					                                  alloc_type_array(t_bool, count));
 					irValue *g = ir_value_global(e, nullptr);
 					irValue *g = ir_value_global(e, nullptr);
 					ir_module_add_value(m, e, g);
 					ir_module_add_value(m, e, g);
-					map_set(&m->members, hash_string(name), g);
+					string_map_set(&m->members, name, g);
 					ir_global_type_info_member_usings = g;
 					ir_global_type_info_member_usings = g;
 				}
 				}
 
 
@@ -11183,7 +11181,7 @@ void ir_init_module(irModule *m, Checker *c) {
 					                                  alloc_type_array(t_string, count));
 					                                  alloc_type_array(t_string, count));
 					irValue *g = ir_value_global(e, nullptr);
 					irValue *g = ir_value_global(e, nullptr);
 					ir_module_add_value(m, e, g);
 					ir_module_add_value(m, e, g);
-					map_set(&m->members, hash_string(name), g);
+					string_map_set(&m->members, name, g);
 					ir_global_type_info_member_tags = g;
 					ir_global_type_info_member_tags = g;
 				}
 				}
 			}
 			}
@@ -11226,12 +11224,12 @@ void ir_init_module(irModule *m, Checker *c) {
 
 
 void ir_destroy_module(irModule *m) {
 void ir_destroy_module(irModule *m) {
 	map_destroy(&m->values);
 	map_destroy(&m->values);
-	map_destroy(&m->members);
+	string_map_destroy(&m->members);
 	map_destroy(&m->entity_names);
 	map_destroy(&m->entity_names);
 	map_destroy(&m->anonymous_proc_lits);
 	map_destroy(&m->anonymous_proc_lits);
 	map_destroy(&m->debug_info);
 	map_destroy(&m->debug_info);
-	map_destroy(&m->const_strings);
-	map_destroy(&m->const_string_byte_slices);
+	string_map_destroy(&m->const_strings);
+	string_map_destroy(&m->const_string_byte_slices);
 	map_destroy(&m->constant_value_to_global);
 	map_destroy(&m->constant_value_to_global);
 	array_free(&m->procs);
 	array_free(&m->procs);
 	array_free(&m->procs_to_generate);
 	array_free(&m->procs_to_generate);
@@ -12020,7 +12018,7 @@ void ir_gen_tree(irGen *s) {
 		array_add(&global_variables, var);
 		array_add(&global_variables, var);
 
 
 		ir_module_add_value(m, e, g);
 		ir_module_add_value(m, e, g);
-		map_set(&m->members, hash_string(name), g);
+		string_map_set(&m->members, name, g);
 	}
 	}
 
 
 	for_array(i, info->entities) {
 	for_array(i, info->entities) {
@@ -12110,9 +12108,9 @@ void ir_gen_tree(irGen *s) {
 			p->Proc.is_export = e->Procedure.is_export;
 			p->Proc.is_export = e->Procedure.is_export;
 
 
 			ir_module_add_value(m, e, p);
 			ir_module_add_value(m, e, p);
-			HashKey hash_name = hash_string(name);
-			if (map_get(&m->members, hash_name) == nullptr) {
-				map_set(&m->members, hash_name, p);
+			StringHashKey hash_name = string_hash_string(name);
+			if (string_map_get(&m->members, hash_name) == nullptr) {
+				string_map_set(&m->members, hash_name, p);
 			}
 			}
 			break;
 			break;
 		}
 		}
@@ -12173,7 +12171,7 @@ void ir_gen_tree(irGen *s) {
 		p->Proc.is_startup = true;
 		p->Proc.is_startup = true;
 
 
 		map_set(&m->values, hash_entity(e), p);
 		map_set(&m->values, hash_entity(e), p);
-		map_set(&m->members, hash_string(name), p);
+		string_map_set(&m->members, name, p);
 
 
 		irProcedure *proc = &p->Proc;
 		irProcedure *proc = &p->Proc;
 		proc->inlining = ProcInlining_no_inline; // TODO(bill): is no_inline a good idea?
 		proc->inlining = ProcInlining_no_inline; // TODO(bill): is no_inline a good idea?
@@ -12254,7 +12252,7 @@ void ir_gen_tree(irGen *s) {
 		p->Proc.is_startup = true;
 		p->Proc.is_startup = true;
 
 
 		map_set(&m->values, hash_entity(e), p);
 		map_set(&m->values, hash_entity(e), p);
-		map_set(&m->members, hash_string(name), p);
+		string_map_set(&m->members, name, p);
 
 
 		irProcedure *proc = &p->Proc;
 		irProcedure *proc = &p->Proc;
 		proc->inlining = ProcInlining_no_inline; // TODO(bill): is no_inline a good idea?
 		proc->inlining = ProcInlining_no_inline; // TODO(bill): is no_inline a good idea?
@@ -12355,7 +12353,7 @@ void ir_gen_tree(irGen *s) {
 			m->entry_point_entity = e;
 			m->entry_point_entity = e;
 
 
 			map_set(&m->values, hash_entity(e), p);
 			map_set(&m->values, hash_entity(e), p);
-			map_set(&m->members, hash_string(name), p);
+			string_map_set(&m->members, name, p);
 
 
 			irProcedure *proc = &p->Proc;
 			irProcedure *proc = &p->Proc;
 			// proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
 			// proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
@@ -12386,7 +12384,7 @@ void ir_gen_tree(irGen *s) {
 		p->Proc.is_startup = true;
 		p->Proc.is_startup = true;
 
 
 		map_set(&m->values, hash_entity(e), p);
 		map_set(&m->values, hash_entity(e), p);
-		map_set(&m->members, hash_string(name), p);
+		string_map_set(&m->members, name, p);
 
 
 
 
 		irProcedure *proc = &p->Proc;
 		irProcedure *proc = &p->Proc;

+ 4 - 4
src/ir_print.cpp

@@ -2651,16 +2651,16 @@ void print_llvm_ir(irGen *ir) {
 
 
 	ir_write_str_lit(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) #3 \n");
 	ir_write_str_lit(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) #3 \n");
 
 
-	if (map_get(&m->members, hash_string(str_lit("llvm.bswap.i16"))) == nullptr) {
+	if (string_map_get(&m->members, str_lit("llvm.bswap.i16")) == nullptr) {
 		ir_write_str_lit(f, "declare i16 @llvm.bswap.i16(i16) \n");
 		ir_write_str_lit(f, "declare i16 @llvm.bswap.i16(i16) \n");
 	}
 	}
-	if (map_get(&m->members, hash_string(str_lit("llvm.bswap.i32"))) == nullptr) {
+	if (string_map_get(&m->members, str_lit("llvm.bswap.i32")) == nullptr) {
 		ir_write_str_lit(f, "declare i32 @llvm.bswap.i32(i32) \n");
 		ir_write_str_lit(f, "declare i32 @llvm.bswap.i32(i32) \n");
 	}
 	}
-	if (map_get(&m->members, hash_string(str_lit("llvm.bswap.i64"))) == nullptr) {
+	if (string_map_get(&m->members, str_lit("llvm.bswap.i64")) == nullptr) {
 		ir_write_str_lit(f, "declare i64 @llvm.bswap.i64(i64) \n");
 		ir_write_str_lit(f, "declare i64 @llvm.bswap.i64(i64) \n");
 	}
 	}
-	if (map_get(&m->members, hash_string(str_lit("llvm.bswap.i128"))) == nullptr) {
+	if (string_map_get(&m->members, str_lit("llvm.bswap.i128")) == nullptr) {
 		ir_write_str_lit(f, "declare i128 @llvm.bswap.i128(i128) \n");
 		ir_write_str_lit(f, "declare i128 @llvm.bswap.i128(i128) \n");
 	}
 	}
 	ir_write_byte(f, '\n');
 	ir_write_byte(f, '\n');

+ 18 - 20
src/llvm_backend.cpp

@@ -1630,17 +1630,17 @@ void lb_add_entity(lbModule *m, Entity *e, lbValue val) {
 }
 }
 void lb_add_member(lbModule *m, String const &name, lbValue val) {
 void lb_add_member(lbModule *m, String const &name, lbValue val) {
 	if (name.len > 0) {
 	if (name.len > 0) {
-		map_set(&m->members, hash_string(name), val);
+		string_map_set(&m->members, name, val);
 	}
 	}
 }
 }
-void lb_add_member(lbModule *m, HashKey const &key, lbValue val) {
-	map_set(&m->members, key, val);
+void lb_add_member(lbModule *m, StringHashKey const &key, lbValue val) {
+	string_map_set(&m->members, key, val);
 }
 }
 void lb_add_procedure_value(lbModule *m, lbProcedure *p) {
 void lb_add_procedure_value(lbModule *m, lbProcedure *p) {
 	if (p->entity != nullptr) {
 	if (p->entity != nullptr) {
 		map_set(&m->procedure_values, hash_pointer(p->value), p->entity);
 		map_set(&m->procedure_values, hash_pointer(p->value), p->entity);
 	}
 	}
-	map_set(&m->procedures, hash_string(p->name), p);
+	string_map_set(&m->procedures, p->name, p);
 }
 }
 
 
 
 
@@ -1688,11 +1688,11 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
 	String link_name = lb_get_entity_name(m, entity);
 	String link_name = lb_get_entity_name(m, entity);
 
 
 	{
 	{
-		HashKey key = hash_string(link_name);
-		lbValue *found = map_get(&m->members, key);
+		StringHashKey key = string_hash_string(link_name);
+		lbValue *found = string_map_get(&m->members, key);
 		if (found) {
 		if (found) {
 			lb_add_entity(m, entity, *found);
 			lb_add_entity(m, entity, *found);
-			lbProcedure **p_found = map_get(&m->procedures, key);
+			lbProcedure **p_found = string_map_get(&m->procedures, key);
 			GB_ASSERT(p_found != nullptr);
 			GB_ASSERT(p_found != nullptr);
 			return *p_found;
 			return *p_found;
 		}
 		}
@@ -1824,8 +1824,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) {
 
 
 lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) {
 lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) {
 	{
 	{
-		HashKey key = hash_string(link_name);
-		lbValue *found = map_get(&m->members, key);
+		lbValue *found = string_map_get(&m->members, link_name);
 		GB_ASSERT(found == nullptr);
 		GB_ASSERT(found == nullptr);
 	}
 	}
 
 
@@ -2493,8 +2492,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
 				name = e->Procedure.link_name;
 				name = e->Procedure.link_name;
 			}
 			}
 
 
-			HashKey key = hash_string(name);
-			lbValue *prev_value = map_get(&p->module->members, key);
+			lbValue *prev_value = string_map_get(&p->module->members, name);
 			if (prev_value != nullptr) {
 			if (prev_value != nullptr) {
 				// NOTE(bill): Don't do mutliple declarations in the IR
 				// NOTE(bill): Don't do mutliple declarations in the IR
 				return;
 				return;
@@ -2513,7 +2511,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
 			if (p != nullptr) {
 			if (p != nullptr) {
 				array_add(&p->children, nested_proc);
 				array_add(&p->children, nested_proc);
 			} else {
 			} else {
-				map_set(&p->module->members, hash_string(name), value);
+				string_map_set(&p->module->members, name, value);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -4140,8 +4138,8 @@ lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue m
 
 
 
 
 LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
 LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
-	HashKey key = hash_string(str);
-	LLVMValueRef *found = map_get(&m->const_strings, key);
+	StringHashKey key = string_hash_string(str);
+	LLVMValueRef *found = string_map_get(&m->const_strings, key);
 	if (found != nullptr) {
 	if (found != nullptr) {
 		return *found;
 		return *found;
 	} else {
 	} else {
@@ -4162,7 +4160,7 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
 		LLVMSetInitializer(global_data, data);
 		LLVMSetInitializer(global_data, data);
 
 
 		LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2);
 		LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2);
-		map_set(&m->const_strings, key, ptr);
+		string_map_set(&m->const_strings, key, ptr);
 		return ptr;
 		return ptr;
 	}
 	}
 }
 }
@@ -8399,7 +8397,7 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A
 	if (parent != nullptr) {
 	if (parent != nullptr) {
 		array_add(&parent->children, p);
 		array_add(&parent->children, p);
 	} else {
 	} else {
-		map_set(&m->members, hash_string(name), value);
+		string_map_set(&m->members, name, value);
 	}
 	}
 
 
 	map_set(&m->anonymous_proc_lits, hash_pointer(expr), p);
 	map_set(&m->anonymous_proc_lits, hash_pointer(expr), p);
@@ -10187,10 +10185,10 @@ void lb_init_module(lbModule *m, Checker *c) {
 	gbAllocator a = heap_allocator();
 	gbAllocator a = heap_allocator();
 	map_init(&m->types, a);
 	map_init(&m->types, a);
 	map_init(&m->values, a);
 	map_init(&m->values, a);
-	map_init(&m->members, a);
+	string_map_init(&m->members, a);
 	map_init(&m->procedure_values, a);
 	map_init(&m->procedure_values, a);
-	map_init(&m->procedures, a);
-	map_init(&m->const_strings, a);
+	string_map_init(&m->procedures, a);
+	string_map_init(&m->const_strings, a);
 	map_init(&m->anonymous_proc_lits, a);
 	map_init(&m->anonymous_proc_lits, a);
 	array_init(&m->procedures_to_generate, a);
 	array_init(&m->procedures_to_generate, a);
 	array_init(&m->foreign_library_paths, a);
 	array_init(&m->foreign_library_paths, a);
@@ -10342,7 +10340,7 @@ lbValue lb_generate_array(lbModule *m, Type *elem_type, i64 count, String prefix
 	g.type = alloc_type_pointer(t);
 	g.type = alloc_type_pointer(t);
 	LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t)));
 	LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t)));
 	LLVMSetLinkage(g.value, LLVMInternalLinkage);
 	LLVMSetLinkage(g.value, LLVMInternalLinkage);
-	map_set(&m->members, hash_string(s), g);
+	string_map_set(&m->members, s, g);
 	return g;
 	return g;
 }
 }
 
 

+ 3 - 3
src/llvm_backend.hpp

@@ -62,11 +62,11 @@ struct lbModule {
 	Map<LLVMTypeRef> types; // Key: Type *
 	Map<LLVMTypeRef> types; // Key: Type *
 
 
 	Map<lbValue>  values;           // Key: Entity *
 	Map<lbValue>  values;           // Key: Entity *
-	Map<lbValue>  members;          // Key: String
-	Map<lbProcedure *> procedures;  // Key: String
+	StringMap<lbValue>  members;          
+	StringMap<lbProcedure *> procedures;  
 	Map<Entity *> procedure_values; // Key: LLVMValueRef
 	Map<Entity *> procedure_values; // Key: LLVMValueRef
 
 
-	Map<LLVMValueRef> const_strings; // Key: String
+	StringMap<LLVMValueRef> const_strings; 
 
 
 	Map<lbProcedure *> anonymous_proc_lits; // Key: Ast *
 	Map<lbProcedure *> anonymous_proc_lits; // Key: Ast *
 
 

+ 2 - 1
src/main.cpp

@@ -919,7 +919,7 @@ bool parse_build_flags(Array<String> args) {
 								break;
 								break;
 							}
 							}
 
 
-							HashKey key = hash_string(name);
+							HashKey key = hash_pointer(string_intern(name));
 
 
 							if (map_get(&build_context.defined_values, key) != nullptr) {
 							if (map_get(&build_context.defined_values, key) != nullptr) {
 								gb_printf_err("Defined constant '%.*s' already exists\n", LIT(name));
 								gb_printf_err("Defined constant '%.*s' already exists\n", LIT(name));
@@ -1431,6 +1431,7 @@ int main(int arg_count, char const **arg_ptr) {
 	defer (timings_destroy(timings));
 	defer (timings_destroy(timings));
 
 
 	init_string_buffer_memory();
 	init_string_buffer_memory();
+	init_string_interner();
 	init_global_error_collector();
 	init_global_error_collector();
 	global_big_int_init();
 	global_big_int_init();
 	arena_init(&global_ast_arena, heap_allocator());
 	arena_init(&global_ast_arena, heap_allocator());

+ 33 - 82
src/map.cpp

@@ -13,91 +13,42 @@ struct MapFindResult {
 	isize entry_index;
 	isize entry_index;
 };
 };
 
 
-enum HashKeyKind {
-	HashKey_Default,
-	HashKey_String,
-	HashKey_Ptr,
-	HashKey_PtrAndId,
-};
-
-struct PtrAndId {
-	void *ptr;
-	u64   id;
-};
 
 
 struct HashKey {
 struct HashKey {
-	HashKeyKind kind;
-	// u128        key;
-	u64         key;
-	union {
-		String   string; // if String, s.len > 0
-		void *   ptr;
-		PtrAndId ptr_and_id;
-	};
+	u64 key;
 };
 };
+GB_STATIC_ASSERT(gb_size_of(u64) >= gb_size_of(void *));
 
 
 gb_inline HashKey hashing_proc(void const *data, isize len) {
 gb_inline HashKey hashing_proc(void const *data, isize len) {
-	HashKey h = {HashKey_Default};
-	h.kind = HashKey_Default;
+	HashKey h = {};
 	// h.key = u128_from_u64(gb_fnv64a(data, len));
 	// h.key = u128_from_u64(gb_fnv64a(data, len));
 	h.key = gb_fnv64a(data, len);
 	h.key = gb_fnv64a(data, len);
 
 
 	return h;
 	return h;
 }
 }
 
 
-gb_inline HashKey hash_string(String s) {
-	HashKey h = hashing_proc(s.text, s.len);
-	h.kind = HashKey_String;
-	h.string = s;
-	return h;
-}
-
-gb_inline HashKey hash_pointer(void *ptr) {
-	HashKey h = {HashKey_Ptr};
-	h.key = cast(u64)cast(uintptr)ptr;
-	// h.key = gb_fnv64a(&ptr, gb_size_of(void *));
-	h.ptr = ptr;
-	return h;
-}
-gb_inline HashKey hash_ptr_and_id(void *ptr, u64 id) {
-	HashKey h = {HashKey_PtrAndId};
+gb_inline HashKey hash_pointer(void const *ptr) {
+	HashKey h = {};
 	h.key = cast(u64)cast(uintptr)ptr;
 	h.key = cast(u64)cast(uintptr)ptr;
-	// h.key = gb_fnv64a(&ptr, gb_size_of(void *));
-	h.ptr_and_id.ptr = ptr;
-	h.ptr_and_id.id  = id;
 	return h;
 	return h;
 }
 }
+
 gb_inline HashKey hash_integer(u64 u) {
 gb_inline HashKey hash_integer(u64 u) {
-	HashKey h = {HashKey_Default};
+	HashKey h = {};
 	h.key = u;
 	h.key = u;
 	return h;
 	return h;
 }
 }
 gb_inline HashKey hash_f64(f64 f) {
 gb_inline HashKey hash_f64(f64 f) {
-	HashKey h = {HashKey_Default};
+	HashKey h = {};
 	h.key = bit_cast<u64>(f);
 	h.key = bit_cast<u64>(f);
 	return h;
 	return h;
 }
 }
 
 
-bool hash_key_equal(HashKey a, HashKey b) {
-	if (a.key == b.key) {
-		// NOTE(bill): If two string's hashes collide, compare the strings themselves
-		if (a.kind == HashKey_String) {
-			if (b.kind == HashKey_String) {
-				return a.string == b.string;
-			}
-			return false;
-		} else if (a.kind == HashKey_PtrAndId) {
-			if (b.kind == HashKey_PtrAndId) {
-				return a.ptr_and_id.id == b.ptr_and_id.id;
-			}
-			return false;
-		}
-		return true;
-	}
-	return false;
+gb_inline bool hash_key_equal(HashKey a, HashKey b) {
+	return a.key == b.key;
 }
 }
-bool operator==(HashKey a, HashKey b) { return hash_key_equal(a, b); }
-bool operator!=(HashKey a, HashKey b) { return !hash_key_equal(a, b); }
+gb_inline bool operator==(HashKey a, HashKey b) { return hash_key_equal(a, b); }
+gb_inline bool operator!=(HashKey a, HashKey b) { return !hash_key_equal(a, b); }
 
 
 #endif
 #endif
 
 
@@ -117,23 +68,23 @@ struct Map {
 
 
 template <typename T> void map_init             (Map<T> *h, gbAllocator a, isize capacity = 16);
 template <typename T> void map_init             (Map<T> *h, gbAllocator a, isize capacity = 16);
 template <typename T> void map_destroy          (Map<T> *h);
 template <typename T> void map_destroy          (Map<T> *h);
-template <typename T> T *  map_get              (Map<T> *h, HashKey key);
-template <typename T> void map_set              (Map<T> *h, HashKey key, T const &value);
-template <typename T> void map_remove           (Map<T> *h, HashKey key);
+template <typename T> T *  map_get              (Map<T> *h, HashKey const &key);
+template <typename T> void map_set              (Map<T> *h, HashKey const &key, T const &value);
+template <typename T> void map_remove           (Map<T> *h, HashKey const &key);
 template <typename T> void map_clear            (Map<T> *h);
 template <typename T> void map_clear            (Map<T> *h);
 template <typename T> void map_grow             (Map<T> *h);
 template <typename T> void map_grow             (Map<T> *h);
 template <typename T> void map_rehash           (Map<T> *h, isize new_count);
 template <typename T> void map_rehash           (Map<T> *h, isize new_count);
 
 
 #if MAP_ENABLE_MULTI_MAP
 #if MAP_ENABLE_MULTI_MAP
 // Mutlivalued map procedure
 // Mutlivalued map procedure
-template <typename T> MapEntry<T> * multi_map_find_first(Map<T> *h, HashKey key);
+template <typename T> MapEntry<T> * multi_map_find_first(Map<T> *h, HashKey const &key);
 template <typename T> MapEntry<T> * multi_map_find_next (Map<T> *h, MapEntry<T> *e);
 template <typename T> MapEntry<T> * multi_map_find_next (Map<T> *h, MapEntry<T> *e);
 
 
-template <typename T> isize multi_map_count     (Map<T> *h, HashKey key);
-template <typename T> void  multi_map_get_all   (Map<T> *h, HashKey key, T *items);
-template <typename T> void  multi_map_insert    (Map<T> *h, HashKey key, T const &value);
-template <typename T> void  multi_map_remove    (Map<T> *h, HashKey key, MapEntry<T> *e);
-template <typename T> void  multi_map_remove_all(Map<T> *h, HashKey key);
+template <typename T> isize multi_map_count     (Map<T> *h, HashKey const &key);
+template <typename T> void  multi_map_get_all   (Map<T> *h, HashKey const &key, T *items);
+template <typename T> void  multi_map_insert    (Map<T> *h, HashKey const &key, T const &value);
+template <typename T> void  multi_map_remove    (Map<T> *h, HashKey const &key, MapEntry<T> *e);
+template <typename T> void  multi_map_remove_all(Map<T> *h, HashKey const &key);
 #endif
 #endif
 
 
 template <typename T>
 template <typename T>
@@ -149,7 +100,7 @@ gb_inline void map_destroy(Map<T> *h) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-gb_internal isize map__add_entry(Map<T> *h, HashKey key) {
+gb_internal isize map__add_entry(Map<T> *h, HashKey const &key) {
 	MapEntry<T> e = {};
 	MapEntry<T> e = {};
 	e.key = key;
 	e.key = key;
 	e.next = -1;
 	e.next = -1;
@@ -158,7 +109,7 @@ gb_internal isize map__add_entry(Map<T> *h, HashKey key) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-gb_internal MapFindResult map__find(Map<T> *h, HashKey key) {
+gb_internal MapFindResult map__find(Map<T> *h, HashKey const &key) {
 	MapFindResult fr = {-1, -1, -1};
 	MapFindResult fr = {-1, -1, -1};
 	if (h->hashes.count > 0) {
 	if (h->hashes.count > 0) {
 		// fr.hash_index  = u128_to_i64(key.key % u128_from_i64(h->hashes.count));
 		// fr.hash_index  = u128_to_i64(key.key % u128_from_i64(h->hashes.count));
@@ -240,7 +191,7 @@ void map_rehash(Map<T> *h, isize new_count) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-gb_inline T *map_get(Map<T> *h, HashKey key) {
+T *map_get(Map<T> *h, HashKey const &key) {
 	isize index = map__find(h, key).entry_index;
 	isize index = map__find(h, key).entry_index;
 	if (index >= 0) {
 	if (index >= 0) {
 		return &h->entries[index].value;
 		return &h->entries[index].value;
@@ -249,7 +200,7 @@ gb_inline T *map_get(Map<T> *h, HashKey key) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-void map_set(Map<T> *h, HashKey key, T const &value) {
+void map_set(Map<T> *h, HashKey const &key, T const &value) {
 	isize index;
 	isize index;
 	MapFindResult fr;
 	MapFindResult fr;
 	if (h->hashes.count == 0) {
 	if (h->hashes.count == 0) {
@@ -275,7 +226,7 @@ void map_set(Map<T> *h, HashKey key, T const &value) {
 
 
 
 
 template <typename T>
 template <typename T>
-void map__erase(Map<T> *h, MapFindResult fr) {
+void map__erase(Map<T> *h, MapFindResult const &fr) {
 	MapFindResult last;
 	MapFindResult last;
 	if (fr.entry_prev < 0) {
 	if (fr.entry_prev < 0) {
 		h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
 		h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
@@ -296,7 +247,7 @@ void map__erase(Map<T> *h, MapFindResult fr) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-void map_remove(Map<T> *h, HashKey key) {
+void map_remove(Map<T> *h, HashKey const &key) {
 	MapFindResult fr = map__find(h, key);
 	MapFindResult fr = map__find(h, key);
 	if (fr.entry_index >= 0) {
 	if (fr.entry_index >= 0) {
 		map__erase(h, fr);
 		map__erase(h, fr);
@@ -312,7 +263,7 @@ gb_inline void map_clear(Map<T> *h) {
 
 
 #if MAP_ENABLE_MULTI_MAP
 #if MAP_ENABLE_MULTI_MAP
 template <typename T>
 template <typename T>
-MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) {
+MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey const &key) {
 	isize i = map__find(h, key).entry_index;
 	isize i = map__find(h, key).entry_index;
 	if (i < 0) {
 	if (i < 0) {
 		return nullptr;
 		return nullptr;
@@ -333,7 +284,7 @@ MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-isize multi_map_count(Map<T> *h, HashKey key) {
+isize multi_map_count(Map<T> *h, HashKey const &key) {
 	isize count = 0;
 	isize count = 0;
 	MapEntry<T> *e = multi_map_find_first(h, key);
 	MapEntry<T> *e = multi_map_find_first(h, key);
 	while (e != nullptr) {
 	while (e != nullptr) {
@@ -344,7 +295,7 @@ isize multi_map_count(Map<T> *h, HashKey key) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-void multi_map_get_all(Map<T> *h, HashKey key, T *items) {
+void multi_map_get_all(Map<T> *h, HashKey const &key, T *items) {
 	isize i = 0;
 	isize i = 0;
 	MapEntry<T> *e = multi_map_find_first(h, key);
 	MapEntry<T> *e = multi_map_find_first(h, key);
 	while (e != nullptr) {
 	while (e != nullptr) {
@@ -354,7 +305,7 @@ void multi_map_get_all(Map<T> *h, HashKey key, T *items) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-void multi_map_insert(Map<T> *h, HashKey key, T const &value) {
+void multi_map_insert(Map<T> *h, HashKey const &key, T const &value) {
 	MapFindResult fr;
 	MapFindResult fr;
 	isize i;
 	isize i;
 	if (h->hashes.count == 0) {
 	if (h->hashes.count == 0) {
@@ -377,7 +328,7 @@ void multi_map_insert(Map<T> *h, HashKey key, T const &value) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-void multi_map_remove(Map<T> *h, HashKey key, MapEntry<T> *e) {
+void multi_map_remove(Map<T> *h, HashKey const &key, MapEntry<T> *e) {
 	MapFindResult fr = map__find_from_entry(h, e);
 	MapFindResult fr = map__find_from_entry(h, e);
 	if (fr.entry_index >= 0) {
 	if (fr.entry_index >= 0) {
 		map__erase(h, fr);
 		map__erase(h, fr);
@@ -385,7 +336,7 @@ void multi_map_remove(Map<T> *h, HashKey key, MapEntry<T> *e) {
 }
 }
 
 
 template <typename T>
 template <typename T>
-void multi_map_remove_all(Map<T> *h, HashKey key) {
+void multi_map_remove_all(Map<T> *h, HashKey const &key) {
 	while (map_get(h, key) != nullptr) {
 	while (map_get(h, key) != nullptr) {
 		map_remove(h, key);
 		map_remove(h, key);
 	}
 	}

+ 5 - 5
src/parser.cpp

@@ -4310,7 +4310,7 @@ void destroy_ast_file(AstFile *f) {
 bool init_parser(Parser *p) {
 bool init_parser(Parser *p) {
 	GB_ASSERT(p != nullptr);
 	GB_ASSERT(p != nullptr);
 	string_set_init(&p->imported_files, heap_allocator());
 	string_set_init(&p->imported_files, heap_allocator());
-	map_init(&p->package_map, heap_allocator());
+	string_map_init(&p->package_map, heap_allocator());
 	array_init(&p->packages, heap_allocator());
 	array_init(&p->packages, heap_allocator());
 	array_init(&p->package_imports, heap_allocator());
 	array_init(&p->package_imports, heap_allocator());
 	gb_mutex_init(&p->file_add_mutex);
 	gb_mutex_init(&p->file_add_mutex);
@@ -4336,7 +4336,7 @@ void destroy_parser(Parser *p) {
 	array_free(&p->packages);
 	array_free(&p->packages);
 	array_free(&p->package_imports);
 	array_free(&p->package_imports);
 	string_set_destroy(&p->imported_files);
 	string_set_destroy(&p->imported_files);
-	map_destroy(&p->package_map);
+	string_map_destroy(&p->package_map);
 	gb_mutex_destroy(&p->file_add_mutex);
 	gb_mutex_destroy(&p->file_add_mutex);
 	gb_mutex_destroy(&p->file_decl_mutex);
 	gb_mutex_destroy(&p->file_decl_mutex);
 }
 }
@@ -4346,8 +4346,8 @@ void parser_add_package(Parser *p, AstPackage *pkg) {
 	pkg->id = p->packages.count+1;
 	pkg->id = p->packages.count+1;
 	array_add(&p->packages, pkg);
 	array_add(&p->packages, pkg);
 	if (pkg->name.len > 0) {
 	if (pkg->name.len > 0) {
-		HashKey key = hash_string(pkg->name);
-		auto found = map_get(&p->package_map, key);
+		StringHashKey key = string_hash_string(pkg->name);
+		auto found = string_map_get(&p->package_map, key);
 		if (found) {
 		if (found) {
 			GB_ASSERT(pkg->files.count > 0);
 			GB_ASSERT(pkg->files.count > 0);
 			AstFile *f = pkg->files[0];
 			AstFile *f = pkg->files[0];
@@ -4356,7 +4356,7 @@ void parser_add_package(Parser *p, AstPackage *pkg) {
 			TokenPos pos = (*found)->files[0]->package_token.pos;
 			TokenPos pos = (*found)->files[0]->package_token.pos;
 			error_line("\tpreviously declared at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column);
 			error_line("\tpreviously declared at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column);
 		} else {
 		} else {
-			map_set(&p->package_map, key, pkg);
+			string_map_set(&p->package_map, key, pkg);
 		}
 		}
 	}
 	}
 }
 }

+ 10 - 10
src/parser.hpp

@@ -131,16 +131,16 @@ struct AstPackage {
 
 
 
 
 struct Parser {
 struct Parser {
-	String                 init_fullpath;
-	StringSet              imported_files; // fullpath
-	Map<AstPackage *>      package_map; // Key: String (package name)
-	Array<AstPackage *>    packages;
-	Array<ImportedPackage> package_imports;
-	isize                  file_to_process_count;
-	isize                  total_token_count;
-	isize                  total_line_count;
-	gbMutex                file_add_mutex;
-	gbMutex                file_decl_mutex;
+	String                  init_fullpath;
+	StringSet               imported_files; // fullpath
+	StringMap<AstPackage *> package_map; // Key(package name)
+	Array<AstPackage *>     packages;
+	Array<ImportedPackage>  package_imports;
+	isize                   file_to_process_count;
+	isize                   total_token_count;
+	isize                   total_line_count;
+	gbMutex                 file_add_mutex;
+	gbMutex                 file_decl_mutex;
 };
 };
 
 
 
 

+ 2 - 2
src/query_data.cpp

@@ -918,7 +918,7 @@ void generate_and_print_query_data_go_to_definitions(Checker *c) {
 		}
 		}
 
 
 
 
-		AstFile **use_file_found = map_get(&c->info.files, hash_string(pos.file));
+		AstFile **use_file_found = string_map_get(&c->info.files, pos.file);
 		GB_ASSERT(use_file_found != nullptr);
 		GB_ASSERT(use_file_found != nullptr);
 		AstFile *use_file = *use_file_found;
 		AstFile *use_file = *use_file_found;
 		GB_ASSERT(use_file != nullptr);
 		GB_ASSERT(use_file != nullptr);
@@ -1008,7 +1008,7 @@ void generate_and_print_query_data_go_to_definitions(Checker *c) {
 			AstFile *def_file = e->file;
 			AstFile *def_file = e->file;
 
 
 			if (def_file == nullptr) {
 			if (def_file == nullptr) {
-				auto *def_file_found = map_get(&c->info.files, hash_string(e->token.pos.file));
+				auto *def_file_found = string_map_get(&c->info.files, e->token.pos.file);
 				if (def_file_found == nullptr) {
 				if (def_file_found == nullptr) {
 					continue;
 					continue;
 				}
 				}

+ 257 - 0
src/string_map.cpp

@@ -0,0 +1,257 @@
+// NOTE(bill): This util stuff is the same for every `Map`
+struct StringMapFindResult {
+	isize hash_index;
+	isize entry_prev;
+	isize entry_index;
+};
+
+struct StringHashKey {
+	u64    hash;
+	String string; 
+};
+
+StringHashKey string_hashing_proc(void const *data, isize len) {
+	StringHashKey h = {};
+	h.hash = gb_fnv64a(data, len);
+	h.string.text = (u8 *)data;
+	h.string.len = len;
+	return h;
+}
+
+gb_inline StringHashKey string_hash_string(String const &s) {
+	return string_hashing_proc(s.text, s.len);
+}
+
+
+bool string_hash_key_equal(StringHashKey a, StringHashKey b) {
+	if (a.hash == b.hash) {
+		// NOTE(bill): If two string's hashes collide, compare the strings themselves
+		return a.string == b.string;
+	}
+	return false;
+}
+bool operator==(StringHashKey a, StringHashKey b) { return string_hash_key_equal(a, b); }
+bool operator!=(StringHashKey a, StringHashKey b) { return !string_hash_key_equal(a, b); }
+
+template <typename T>
+struct StringMapEntry {
+	StringHashKey key;
+	isize         next;
+	T             value;
+};
+
+template <typename T>
+struct StringMap {
+	Array<isize>              hashes;
+	Array<StringMapEntry<T> > entries;
+};
+
+
+template <typename T> void string_map_init             (StringMap<T> *h, gbAllocator a, isize capacity = 16);
+template <typename T> void string_map_destroy          (StringMap<T> *h);
+
+template <typename T> T *  string_map_get              (StringMap<T> *h, char const *key);
+template <typename T> T *  string_map_get              (StringMap<T> *h, String const &key);
+template <typename T> T *  string_map_get              (StringMap<T> *h, StringHashKey const &key);
+
+template <typename T> void string_map_set              (StringMap<T> *h, StringHashKey const &key, T const &value);
+template <typename T> void string_map_set              (StringMap<T> *h, String const &key, T const &value);
+template <typename T> void string_map_set              (StringMap<T> *h, char const *key,   T const &value);
+
+template <typename T> void string_map_remove           (StringMap<T> *h, StringHashKey const &key);
+template <typename T> void string_map_clear            (StringMap<T> *h);
+template <typename T> void string_map_grow             (StringMap<T> *h);
+template <typename T> void string_map_rehash           (StringMap<T> *h, isize new_count);
+
+template <typename T>
+gb_inline void string_map_init(StringMap<T> *h, gbAllocator a, isize capacity) {
+	array_init(&h->hashes,  a, 0, capacity);
+	array_init(&h->entries, a, 0, capacity);
+}
+
+template <typename T>
+gb_inline void string_map_destroy(StringMap<T> *h) {
+	array_free(&h->entries);
+	array_free(&h->hashes);
+}
+
+template <typename T>
+gb_internal isize string_map__add_entry(StringMap<T> *h, StringHashKey const &key) {
+	StringMapEntry<T> e = {};
+	e.key = key;
+	e.next = -1;
+	array_add(&h->entries, e);
+	return h->entries.count-1;
+}
+
+template <typename T>
+gb_internal StringMapFindResult string_map__find(StringMap<T> *h, StringHashKey const &key) {
+	StringMapFindResult fr = {-1, -1, -1};
+	if (h->hashes.count > 0) {
+		fr.hash_index = key.hash % h->hashes.count;
+		fr.entry_index = h->hashes[fr.hash_index];
+		while (fr.entry_index >= 0) {
+			if (string_hash_key_equal(h->entries[fr.entry_index].key, key)) {
+				return fr;
+			}
+			fr.entry_prev = fr.entry_index;
+			fr.entry_index = h->entries[fr.entry_index].next;
+		}
+	}
+	return fr;
+}
+
+template <typename T>
+gb_internal StringMapFindResult string_map__find_from_entry(StringMap<T> *h, StringMapEntry<T> *e) {
+	StringMapFindResult fr = {-1, -1, -1};
+	if (h->hashes.count > 0) {
+		fr.hash_index  = e->key.hash % h->hashes.count;
+		fr.entry_index = h->hashes[fr.hash_index];
+		while (fr.entry_index >= 0) {
+			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;
+}
+
+template <typename T>
+gb_internal b32 string_map__full(StringMap<T> *h) {
+	return 0.75f * h->hashes.count <= h->entries.count;
+}
+
+#define STRING_MAP_ARRAY_GROW_FORMULA(x) (4*(x) + 7)
+GB_STATIC_ASSERT(STRING_MAP_ARRAY_GROW_FORMULA(0) > 0);
+
+template <typename T>
+gb_inline void string_map_grow(StringMap<T> *h) {
+	isize new_count = STRING_MAP_ARRAY_GROW_FORMULA(h->entries.count);
+	string_map_rehash(h, new_count);
+}
+
+template <typename T>
+void string_map_rehash(StringMap<T> *h, isize new_count) {
+	isize i, j;
+	StringMap<T> nh = {};
+	string_map_init(&nh, h->hashes.allocator);
+	array_resize(&nh.hashes, new_count);
+	array_reserve(&nh.entries, h->entries.count);
+	for (i = 0; i < new_count; i++) {
+		nh.hashes[i] = -1;
+	}
+	for (i = 0; i < h->entries.count; i++) {
+		StringMapEntry<T> *e = &h->entries[i];
+		StringMapFindResult fr;
+		if (nh.hashes.count == 0) {
+			string_map_grow(&nh);
+		}
+		fr = string_map__find(&nh, e->key);
+		j = string_map__add_entry(&nh, e->key);
+		if (fr.entry_prev < 0) {
+			nh.hashes[fr.hash_index] = j;
+		} else {
+			nh.entries[fr.entry_prev].next = j;
+		}
+		nh.entries[j].next = fr.entry_index;
+		nh.entries[j].value = e->value;
+		if (string_map__full(&nh)) {
+			string_map_grow(&nh);
+		}
+	}
+	string_map_destroy(h);
+	*h = nh;
+}
+
+template <typename T>
+T *string_map_get(StringMap<T> *h, StringHashKey const &key) {
+	isize index = string_map__find(h, key).entry_index;
+	if (index >= 0) {
+		return &h->entries[index].value;
+	}
+	return nullptr;
+}
+
+template <typename T>
+gb_inline T *string_map_get(StringMap<T> *h, String const &key) {
+	return string_map_get(h, string_hash_string(key));
+}
+
+template <typename T>
+gb_inline T *string_map_get(StringMap<T> *h, char const *key) {
+	return string_map_get(h, string_hash_string(make_string_c(key)));
+}
+
+template <typename T>
+void string_map_set(StringMap<T> *h, StringHashKey const &key, T const &value) {
+	isize index;
+	StringMapFindResult fr;
+	if (h->hashes.count == 0) {
+		string_map_grow(h);
+	}
+	fr = string_map__find(h, key);
+	if (fr.entry_index >= 0) {
+		index = fr.entry_index;
+	} else {
+		index = string_map__add_entry(h, key);
+		if (fr.entry_prev >= 0) {
+			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);
+	}
+}
+
+template <typename T>
+gb_inline void string_map_set(StringMap<T> *h, String const &key, T const &value) {
+	string_map_set(h, string_hash_string(key), value);
+}
+
+template <typename T>
+gb_inline void string_map_set(StringMap<T> *h, char const *key, T const &value) {
+	string_map_set(h, string_hash_string(make_string_c(key)), value);
+}
+
+
+template <typename T>
+void string_map__erase(StringMap<T> *h, StringMapFindResult const &fr) {
+	StringMapFindResult last;
+	if (fr.entry_prev < 0) {
+		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->entries.count-1) {
+		array_pop(&h->entries);
+		return;
+	}
+	h->entries[fr.entry_index] = h->entries[h->entries.count-1];
+	last = string_map__find(h, h->entries[fr.entry_index].key);
+	if (last.entry_prev >= 0) {
+		h->entries[last.entry_prev].next = fr.entry_index;
+	} else {
+		h->hashes[last.hash_index] = fr.entry_index;
+	}
+}
+
+template <typename T>
+void string_map_remove(StringMap<T> *h, StringHashKey const &key) {
+	StringMapFindResult fr = string_map__find(h, key);
+	if (fr.entry_index >= 0) {
+		string_map__erase(h, fr);
+	}
+}
+
+template <typename T>
+gb_inline void string_map_clear(StringMap<T> *h) {
+	array_clear(&h->hashes);
+	array_clear(&h->entries);
+}
+

+ 26 - 21
src/string_set.cpp

@@ -5,9 +5,9 @@ struct StringSetFindResult {
 };
 };
 
 
 struct StringSetEntry {
 struct StringSetEntry {
-	HashKey  key;
-	isize    next;
-	String   value;
+	u64    hash;
+	isize  next;
+	String value;
 };
 };
 
 
 struct StringSet {
 struct StringSet {
@@ -18,9 +18,9 @@ struct StringSet {
 
 
 void string_set_init   (StringSet *s, gbAllocator a, isize capacity = 16);
 void string_set_init   (StringSet *s, gbAllocator a, isize capacity = 16);
 void string_set_destroy(StringSet *s);
 void string_set_destroy(StringSet *s);
-void string_set_add    (StringSet *s, String str);
-bool string_set_exists (StringSet *s, String str);
-void string_set_remove (StringSet *s, String str);
+void string_set_add    (StringSet *s, String const &str);
+bool string_set_exists (StringSet *s, String const &str);
+void string_set_remove (StringSet *s, String const &str);
 void string_set_clear  (StringSet *s);
 void string_set_clear  (StringSet *s);
 void string_set_grow   (StringSet *s);
 void string_set_grow   (StringSet *s);
 void string_set_rehash (StringSet *s, isize new_count);
 void string_set_rehash (StringSet *s, isize new_count);
@@ -36,22 +36,24 @@ gb_inline void string_set_destroy(StringSet *s) {
 	array_free(&s->hashes);
 	array_free(&s->hashes);
 }
 }
 
 
-gb_internal isize string_set__add_entry(StringSet *s, HashKey key) {
+gb_internal isize string_set__add_entry(StringSet *s, StringHashKey const &key) {
 	StringSetEntry e = {};
 	StringSetEntry e = {};
-	e.key = key;
+	e.hash = key.hash;
 	e.next = -1;
 	e.next = -1;
+	e.value = key.string;
 	array_add(&s->entries, e);
 	array_add(&s->entries, e);
 	return s->entries.count-1;
 	return s->entries.count-1;
 }
 }
 
 
-gb_internal StringSetFindResult string_set__find(StringSet *s, HashKey key) {
+gb_internal StringSetFindResult string_set__find(StringSet *s, StringHashKey const &key) {
 	StringSetFindResult fr = {-1, -1, -1};
 	StringSetFindResult fr = {-1, -1, -1};
 	if (s->hashes.count > 0) {
 	if (s->hashes.count > 0) {
 		// fr.hash_index  = u128_to_i64(key.key % u128_from_i64(s->hashes.count));
 		// fr.hash_index  = u128_to_i64(key.key % u128_from_i64(s->hashes.count));
-		fr.hash_index = key.key % s->hashes.count;
+		fr.hash_index = key.hash % s->hashes.count;
 		fr.entry_index = s->hashes[fr.hash_index];
 		fr.entry_index = s->hashes[fr.hash_index];
 		while (fr.entry_index >= 0) {
 		while (fr.entry_index >= 0) {
-			if (hash_key_equal(s->entries[fr.entry_index].key, key)) {
+			auto const &entry = s->entries[fr.entry_index];
+			if (entry.hash == key.hash && entry.value == key.string) {
 				return fr;
 				return fr;
 			}
 			}
 			fr.entry_prev = fr.entry_index;
 			fr.entry_prev = fr.entry_index;
@@ -85,8 +87,9 @@ void string_set_rehash(StringSet *s, isize new_count) {
 		if (ns.hashes.count == 0) {
 		if (ns.hashes.count == 0) {
 			string_set_grow(&ns);
 			string_set_grow(&ns);
 		}
 		}
-		fr = string_set__find(&ns, e->key);
-		j = string_set__add_entry(&ns, e->key);
+		StringHashKey key = {e->hash, e->value};
+		fr = string_set__find(&ns, key);
+		j = string_set__add_entry(&ns, key);
 		if (fr.entry_prev < 0) {
 		if (fr.entry_prev < 0) {
 			ns.hashes[fr.hash_index] = j;
 			ns.hashes[fr.hash_index] = j;
 		} else {
 		} else {
@@ -102,16 +105,16 @@ void string_set_rehash(StringSet *s, isize new_count) {
 	*s = ns;
 	*s = ns;
 }
 }
 
 
-gb_inline bool string_set_exists(StringSet *s, String str) {
-	HashKey key = hash_string(str);
+gb_inline bool string_set_exists(StringSet *s, String const &str) {
+	StringHashKey key = string_hash_string(str);
 	isize index = string_set__find(s, key).entry_index;
 	isize index = string_set__find(s, key).entry_index;
 	return index >= 0;
 	return index >= 0;
 }
 }
 
 
-void string_set_add(StringSet *s, String str) {
+void string_set_add(StringSet *s, String const &str) {
 	isize index;
 	isize index;
 	StringSetFindResult fr;
 	StringSetFindResult fr;
-	HashKey key = hash_string(str);
+	StringHashKey key = string_hash_string(str);
 	if (s->hashes.count == 0) {
 	if (s->hashes.count == 0) {
 		string_set_grow(s);
 		string_set_grow(s);
 	}
 	}
@@ -145,8 +148,10 @@ void string_set__erase(StringSet *s, StringSetFindResult fr) {
 		array_pop(&s->entries);
 		array_pop(&s->entries);
 		return;
 		return;
 	}
 	}
-	s->entries[fr.entry_index] = s->entries[s->entries.count-1];
-	last = string_set__find(s, s->entries[fr.entry_index].key);
+	auto *entry = &s->entries[fr.entry_index];
+	*entry = s->entries[s->entries.count-1];
+	StringHashKey key = {entry->hash, entry->value};
+	last = string_set__find(s, key);
 	if (last.entry_prev >= 0) {
 	if (last.entry_prev >= 0) {
 		s->entries[last.entry_prev].next = fr.entry_index;
 		s->entries[last.entry_prev].next = fr.entry_index;
 	} else {
 	} else {
@@ -154,8 +159,8 @@ void string_set__erase(StringSet *s, StringSetFindResult fr) {
 	}
 	}
 }
 }
 
 
-void string_set_remove(StringSet *s, String str) {
-	HashKey key = hash_string(str);
+void string_set_remove(StringSet *s, String const &str) {
+	StringHashKey key = string_hash_string(str);
 	StringSetFindResult fr = string_set__find(s, key);
 	StringSetFindResult fr = string_set__find(s, key);
 	if (fr.entry_index >= 0) {
 	if (fr.entry_index >= 0) {
 		string_set__erase(s, fr);
 		string_set__erase(s, fr);

+ 1 - 1
src/types.cpp

@@ -2254,7 +2254,7 @@ Selection lookup_field_from_index(Type *type, i64 index) {
 }
 }
 
 
 
 
-Entity *scope_lookup_current(Scope *s, String name);
+Entity *scope_lookup_current(Scope *s, String const &name);
 
 
 Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident) {
 Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident) {
 	GB_ASSERT(type_ != nullptr);
 	GB_ASSERT(type_ != nullptr);