Merge branch 'master' into windows-llvm-11.1.0

This commit is contained in:
gingerBill
2021-11-05 19:17:00 +00:00
32 changed files with 2782 additions and 790 deletions

View File

@@ -769,6 +769,31 @@ step_dvec2 :: proc "c" (edge, x: dvec2) -> dvec2 { return {step(edge.x, x.x), st
step_dvec3 :: proc "c" (edge, x: dvec3) -> dvec3 { return {step(edge.x, x.x), step(edge.y, x.y), step(edge.z, x.z)} }
step_dvec4 :: proc "c" (edge, x: dvec4) -> dvec4 { return {step(edge.x, x.x), step(edge.y, x.y), step(edge.z, x.z), step(edge.w, x.w)} }
smoothstep :: proc{
smoothstep_f32,
smoothstep_f64,
smoothstep_vec2,
smoothstep_vec3,
smoothstep_vec4,
smoothstep_dvec2,
smoothstep_dvec3,
smoothstep_dvec4,
}
smoothstep_f32 :: proc "c" (edge0, edge1, x: f32) -> f32 {
y := clamp(((x-edge0) / (edge1 - edge0)), 0, 1)
return y * y * (3 - 2*y)
}
smoothstep_f64 :: proc "c" (edge0, edge1, x: f64) -> f64 {
y := clamp(((x-edge0) / (edge1 - edge0)), 0, 1)
return y * y * (3 - 2*y)
}
smoothstep_vec2 :: proc "c" (edge0, edge1, x: vec2) -> vec2 { return {smoothstep(edge0.x, edge1.x, x.x), smoothstep(edge0.y, edge1.y, x.y)} }
smoothstep_vec3 :: proc "c" (edge0, edge1, x: vec3) -> vec3 { return {smoothstep(edge0.x, edge1.x, x.x), smoothstep(edge0.y, edge1.y, x.y), smoothstep(edge0.z, edge1.z, x.z)} }
smoothstep_vec4 :: proc "c" (edge0, edge1, x: vec4) -> vec4 { return {smoothstep(edge0.x, edge1.x, x.x), smoothstep(edge0.y, edge1.y, x.y), smoothstep(edge0.z, edge1.z, x.z), smoothstep(edge0.w, edge1.w, x.w)} }
smoothstep_dvec2 :: proc "c" (edge0, edge1, x: dvec2) -> dvec2 { return {smoothstep(edge0.x, edge1.x, x.x), smoothstep(edge0.y, edge1.y, x.y)} }
smoothstep_dvec3 :: proc "c" (edge0, edge1, x: dvec3) -> dvec3 { return {smoothstep(edge0.x, edge1.x, x.x), smoothstep(edge0.y, edge1.y, x.y), smoothstep(edge0.z, edge1.z, x.z)} }
smoothstep_dvec4 :: proc "c" (edge0, edge1, x: dvec4) -> dvec4 { return {smoothstep(edge0.x, edge1.x, x.x), smoothstep(edge0.y, edge1.y, x.y), smoothstep(edge0.z, edge1.z, x.z), smoothstep(edge0.w, edge1.w, x.w)} }
abs :: proc{
abs_i32,
@@ -1765,16 +1790,24 @@ dquatMulDvec3 :: proc "c" (q: dquat, v: dvec3) -> dvec3 {
inverse_mat2 :: proc "c" (m: mat2) -> mat2 { return builtin.inverse(m) }
inverse_mat3 :: proc "c" (m: mat3) -> mat3 { return builtin.inverse(m) }
inverse_mat4 :: proc "c" (m: mat4) -> mat4 { return builtin.inverse(m) }
inverse_quat :: proc "c" (q: quat) -> quat { return 1/q }
inverse_mat2 :: proc "c" (m: mat2) -> mat2 { return builtin.inverse(m) }
inverse_mat3 :: proc "c" (m: mat3) -> mat3 { return builtin.inverse(m) }
inverse_mat4 :: proc "c" (m: mat4) -> mat4 { return builtin.inverse(m) }
inverse_dmat2 :: proc "c" (m: dmat2) -> dmat2 { return builtin.inverse(m) }
inverse_dmat3 :: proc "c" (m: dmat3) -> dmat3 { return builtin.inverse(m) }
inverse_dmat4 :: proc "c" (m: dmat4) -> dmat4 { return builtin.inverse(m) }
inverse_quat :: proc "c" (q: quat) -> quat { return 1/q }
inverse_dquat :: proc "c" (q: dquat) -> dquat { return 1/q }
inverse :: proc{
inverse_mat2,
inverse_mat3,
inverse_mat4,
inverse_dmat2,
inverse_dmat3,
inverse_dmat4,
inverse_quat,
inverse_dquat,
}
transpose :: builtin.transpose

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
package math_linalg_hlsl
import "core:math"
cos_float :: proc "c" (x: float) -> float { return math.cos(x) }
sin_float :: proc "c" (x: float) -> float { return math.sin(x) }
tan_float :: proc "c" (x: float) -> float { return math.tan(x) }
acos_float :: proc "c" (x: float) -> float { return math.acos(x) }
asin_float :: proc "c" (x: float) -> float { return math.asin(x) }
atan_float :: proc "c" (x: float) -> float { return math.atan(x) }
atan2_float :: proc "c" (y, x: float) -> float { return math.atan2(y, x) }
cosh_float :: proc "c" (x: float) -> float { return math.cosh(x) }
sinh_float :: proc "c" (x: float) -> float { return math.sinh(x) }
tanh_float :: proc "c" (x: float) -> float { return math.tanh(x) }
acosh_float :: proc "c" (x: float) -> float { return math.acosh(x) }
asinh_float :: proc "c" (x: float) -> float { return math.asinh(x) }
atanh_float :: proc "c" (x: float) -> float { return math.atanh(x) }
sqrt_float :: proc "c" (x: float) -> float { return math.sqrt(x) }
rsqrt_float :: proc "c" (x: float) -> float { return 1.0/math.sqrt(x) }
rcp_float :: proc "c" (x: float) -> float { return 1.0/x }
pow_float :: proc "c" (x, y: float) -> float { return math.pow(x, y) }
exp_float :: proc "c" (x: float) -> float { return math.exp(x) }
log_float :: proc "c" (x: float) -> float { return math.ln(x) }
log2_float :: proc "c" (x: float) -> float { return math.log(x, 2) }
log10_float :: proc "c" (x: float) -> float { return math.log(x, 10) }
exp2_float :: proc "c" (x: float) -> float { return math.pow(float(2), x) }
sign_float :: proc "c" (x: float) -> float { return math.sign(x) }
floor_float :: proc "c" (x: float) -> float { return math.floor(x) }
ceil_float :: proc "c" (x: float) -> float { return math.ceil(x) }
fmod_float :: proc "c" (x, y: float) -> float { return math.mod(x, y) }
frac_float :: proc "c" (x: float) -> float {
if x >= 0 {
return x - math.trunc(x)
}
return math.trunc(-x) + x
}
cos_double :: proc "c" (x: double) -> double { return math.cos(x) }
sin_double :: proc "c" (x: double) -> double { return math.sin(x) }
tan_double :: proc "c" (x: double) -> double { return math.tan(x) }
acos_double :: proc "c" (x: double) -> double { return math.acos(x) }
asin_double :: proc "c" (x: double) -> double { return math.asin(x) }
atan_double :: proc "c" (x: double) -> double { return math.atan(x) }
atan2_double :: proc "c" (y, x: double) -> double { return math.atan2(y, x) }
cosh_double :: proc "c" (x: double) -> double { return math.cosh(x) }
sinh_double :: proc "c" (x: double) -> double { return math.sinh(x) }
tanh_double :: proc "c" (x: double) -> double { return math.tanh(x) }
acosh_double :: proc "c" (x: double) -> double { return math.acosh(x) }
asinh_double :: proc "c" (x: double) -> double { return math.asinh(x) }
atanh_double :: proc "c" (x: double) -> double { return math.atanh(x) }
sqrt_double :: proc "c" (x: double) -> double { return math.sqrt(x) }
rsqrt_double :: proc "c" (x: double) -> double { return 1.0/math.sqrt(x) }
rcp_double :: proc "c" (x: double) -> double { return 1.0/x }
pow_double :: proc "c" (x, y: double) -> double { return math.pow(x, y) }
exp_double :: proc "c" (x: double) -> double { return math.exp(x) }
log_double :: proc "c" (x: double) -> double { return math.ln(x) }
log2_double :: proc "c" (x: double) -> double { return math.log(x, 2) }
log10_double :: proc "c" (x: double) -> double { return math.log(x, 10) }
exp2_double :: proc "c" (x: double) -> double { return math.pow(double(2), x) }
sign_double :: proc "c" (x: double) -> double { return math.sign(x) }
floor_double :: proc "c" (x: double) -> double { return math.floor(x) }
ceil_double :: proc "c" (x: double) -> double { return math.ceil(x) }
fmod_double :: proc "c" (x, y: double) -> double { return math.mod(x, y) }
frac_double :: proc "c" (x: double) -> double {
if x >= 0 {
return x - math.trunc(x)
}
return math.trunc(-x) + x
}

View File

@@ -3,7 +3,7 @@ package runtime
import "core:intrinsics"
@(private)
RUNTIME_LINKAGE :: "strong" when (ODIN_USE_SEPARATE_MODULES || ODIN_BUILD_MODE == "dynamic") else "internal"
RUNTIME_LINKAGE :: "strong" when (ODIN_USE_SEPARATE_MODULES || ODIN_BUILD_MODE == "dynamic" || !ODIN_NO_CRT) else "internal"
@(private)
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check {

View File

@@ -1,6 +1,31 @@
package runtime
when ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64" || ODIN_NO_CRT {
when ODIN_NO_CRT && ODIN_OS == "windows" {
foreign import lib "system:NtDll.lib"
@(private="file")
@(default_calling_convention="std")
foreign lib {
RtlMoveMemory :: proc(dst, src: rawptr, length: int) ---
RtlFillMemory :: proc(dst: rawptr, length: int, fill: i32) ---
}
@(link_name="memset", linkage="strong", require)
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
RtlFillMemory(ptr, len, val)
return ptr
}
@(link_name="memmove", linkage="strong", require)
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
RtlMoveMemory(dst, src, len)
return dst
}
@(link_name="memcpy", linkage="strong", require)
memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
RtlMoveMemory(dst, src, len)
return dst
}
} else when ODIN_NO_CRT || (ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64") {
@(link_name="memset", linkage="strong", require)
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
if ptr != nil && len != 0 {

View File

@@ -30,6 +30,7 @@ import bits "core:math/bits"
import fixed "core:math/fixed"
import linalg "core:math/linalg"
import glm "core:math/linalg/glsl"
import hlm "core:math/linalg/hlsl"
import rand "core:math/rand"
import mem "core:mem"
import ast "core:odin/ast"
@@ -86,6 +87,7 @@ _ :: bits
_ :: fixed
_ :: linalg
_ :: glm
_ :: hlm
_ :: rand
_ :: mem
_ :: ast

View File

@@ -146,10 +146,17 @@ void report_windows_product_type(DWORD ProductType) {
#endif
void odin_cpuid(int leaf, int result[]) {
#if defined(GB_COMPILER_MSVC)
__cpuid(result, leaf);
#else
__get_cpuid(leaf, (unsigned int*)&result[0], (unsigned int*)&result[1], (unsigned int*)&result[2], (unsigned int*)&result[3]);
#if defined(GB_CPU_ARM)
return;
#elif defined(GB_CPU_X86)
#if defined(GB_COMPILER_MSVC)
__cpuid(result, leaf);
#else
__get_cpuid(leaf, (unsigned int*)&result[0], (unsigned int*)&result[1], (unsigned int*)&result[2], (unsigned int*)&result[3]);
#endif
#endif
}

View File

@@ -244,7 +244,7 @@ struct BuildContext {
gbAffinity affinity;
isize thread_count;
Map<ExactValue> defined_values; // Key:
PtrMap<char const *, ExactValue> defined_values;
};

View File

@@ -318,6 +318,151 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
operand->mode = Addressing_Constant;
operand->value = exact_value_string(result);
} else if (name == "load_hash") {
if (ce->args.count != 2) {
if (ce->args.count == 0) {
error(ce->close, "'#load_hash' expects 2 argument, got 0");
} else {
error(ce->args[0], "'#load_hash' expects 2 argument, got %td", ce->args.count);
}
return false;
}
Ast *arg0 = ce->args[0];
Ast *arg1 = ce->args[1];
Operand o = {};
check_expr(c, &o, arg0);
if (o.mode != Addressing_Constant) {
error(arg0, "'#load_hash' expected a constant string argument");
return false;
}
if (!is_type_string(o.type)) {
gbString str = type_to_string(o.type);
error(arg0, "'#load_hash' expected a constant string, got %s", str);
gb_string_free(str);
return false;
}
Operand o_hash = {};
check_expr(c, &o_hash, arg1);
if (o_hash.mode != Addressing_Constant) {
error(arg1, "'#load_hash' expected a constant string argument");
return false;
}
if (!is_type_string(o_hash.type)) {
gbString str = type_to_string(o.type);
error(arg1, "'#load_hash' expected a constant string, got %s", str);
gb_string_free(str);
return false;
}
gbAllocator a = heap_allocator();
GB_ASSERT(o.value.kind == ExactValue_String);
GB_ASSERT(o_hash.value.kind == ExactValue_String);
String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id));
String original_string = o.value.value_string;
String hash_kind = o_hash.value.value_string;
String supported_hashes[] = {
str_lit("adler32"),
str_lit("crc32"),
str_lit("crc64"),
str_lit("fnv32"),
str_lit("fnv64"),
str_lit("fnv32a"),
str_lit("fnv64a"),
str_lit("murmur32"),
str_lit("murmur64"),
};
bool hash_found = false;
for (isize i = 0; i < gb_count_of(supported_hashes); i++) {
if (supported_hashes[i] == hash_kind) {
hash_found = true;
break;
}
}
if (!hash_found) {
ERROR_BLOCK();
error(ce->proc, "Invalid hash kind passed to `#load_hash`, got: %.*s", LIT(hash_kind));
error_line("\tAvailable hash kinds:\n");
for (isize i = 0; i < gb_count_of(supported_hashes); i++) {
error_line("\t%.*s\n", LIT(supported_hashes[i]));
}
return false;
}
BlockingMutex *ignore_mutex = nullptr;
String path = {};
bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
gb_unused(ok);
char *c_str = alloc_cstring(a, path);
defer (gb_free(a, c_str));
gbFile f = {};
gbFileError file_err = gb_file_open(&f, c_str);
defer (gb_file_close(&f));
switch (file_err) {
default:
case gbFileError_Invalid:
error(ce->proc, "Failed to `#load_hash` file: %s; invalid file or cannot be found", c_str);
return false;
case gbFileError_NotExists:
error(ce->proc, "Failed to `#load_hash` file: %s; file cannot be found", c_str);
return false;
case gbFileError_Permission:
error(ce->proc, "Failed to `#load_hash` file: %s; file permissions problem", c_str);
return false;
case gbFileError_None:
// Okay
break;
}
// TODO(bill): make these procedures fast :P
u64 hash_value = 0;
String result = {};
isize file_size = cast(isize)gb_file_size(&f);
if (file_size > 0) {
u8 *data = cast(u8 *)gb_alloc(a, file_size);
gb_file_read_at(&f, data, file_size, 0);
if (hash_kind == "adler32") {
hash_value = gb_adler32(data, file_size);
} else if (hash_kind == "crc32") {
hash_value = gb_crc32(data, file_size);
} else if (hash_kind == "crc64") {
hash_value = gb_crc64(data, file_size);
} else if (hash_kind == "fnv32") {
hash_value = gb_fnv32(data, file_size);
} else if (hash_kind == "fnv64") {
hash_value = gb_fnv64(data, file_size);
} else if (hash_kind == "fnv32a") {
hash_value = gb_fnv32a(data, file_size);
} else if (hash_kind == "fnv64a") {
hash_value = gb_fnv64a(data, file_size);
} else if (hash_kind == "murmur32") {
hash_value = gb_murmur32(data, file_size);
} else if (hash_kind == "murmur64") {
hash_value = gb_murmur64(data, file_size);
} else {
compiler_error("unhandled hash kind: %.*s", LIT(hash_kind));
}
gb_free(a, data);
}
operand->type = t_untyped_integer;
operand->mode = Addressing_Constant;
operand->value = exact_value_u64(hash_value);
} else if (name == "load_or") {
if (ce->args.count != 2) {
if (ce->args.count == 0) {

View File

@@ -314,7 +314,7 @@ bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, Entity *base_
return false;
}
auto *found_gen_procs = map_get(&info->gen_procs, hash_pointer(base_entity->identifier));
auto *found_gen_procs = map_get(&info->gen_procs, base_entity->identifier.load());
if (found_gen_procs) {
auto procs = *found_gen_procs;
for_array(i, procs) {
@@ -423,7 +423,7 @@ bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, Entity *base_
} else {
auto array = array_make<Entity *>(heap_allocator());
array_add(&array, entity);
map_set(&info->gen_procs, hash_pointer(base_entity->identifier), array);
map_set(&info->gen_procs, base_entity->identifier.load(), array);
}
if (poly_proc_data) {
@@ -659,8 +659,8 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
}
if (is_type_matrix(dst)) {
Type *elem = base_array_type(dst);
i64 distance = check_distance_between_types(c, operand, elem);
Type *dst_elem = base_array_type(dst);
i64 distance = check_distance_between_types(c, operand, dst_elem);
if (distance >= 0) {
return distance + 7;
}
@@ -2467,7 +2467,9 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
if (is_type_matrix(src) && is_type_matrix(dst)) {
GB_ASSERT(src->kind == Type_Matrix);
GB_ASSERT(dst->kind == Type_Matrix);
if (!are_types_identical(src->Matrix.elem, dst->Matrix.elem)) {
Operand op = *operand;
op.type = src->Matrix.elem;
if (!check_is_castable_to(c, &op, dst->Matrix.elem)) {
return false;
}
@@ -2477,11 +2479,7 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
return src_count == dst_count;
}
if (dst->Matrix.row_count != dst->Matrix.column_count) {
return false;
}
return true;
return is_matrix_square(dst) && is_matrix_square(src);
}
@@ -6108,6 +6106,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr
name == "defined" ||
name == "config" ||
name == "load" ||
name == "load_hash" ||
name == "load_or"
) {
operand->mode = Addressing_Builtin;
@@ -6943,6 +6942,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
name == "defined" ||
name == "config" ||
name == "load" ||
name == "load_hash" ||
name == "load_or"
) {
error(node, "'#%.*s' must be used as a call", LIT(name));

View File

@@ -699,7 +699,7 @@ struct TypeAndToken {
};
void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Operand operand, bool use_expr = true) {
void add_constant_switch_case(CheckerContext *ctx, PtrMap<uintptr, TypeAndToken> *seen, Operand operand, bool use_expr = true) {
if (operand.mode != Addressing_Constant) {
return;
}
@@ -707,7 +707,7 @@ void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Oper
return;
}
HashKey key = hash_exact_value(operand.value);
uintptr key = hash_exact_value(operand.value);
TypeAndToken *found = map_get(seen, key);
if (found != nullptr) {
isize count = multi_map_count(seen, key);
@@ -964,7 +964,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
}
}
Map<TypeAndToken> seen = {}; // NOTE(bill): Multimap, Key: ExactValue
PtrMap<uintptr, TypeAndToken> seen = {}; // NOTE(bill): Multimap, Key: ExactValue
map_init(&seen, heap_allocator());
defer (map_destroy(&seen));
@@ -1133,8 +1133,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
continue;
}
ExactValue v = f->Constant.value;
HashKey key = hash_exact_value(v);
auto found = map_get(&seen, key);
auto found = map_get(&seen, hash_exact_value(v));
if (!found) {
array_add(&unhandled, f);
}

View File

@@ -228,7 +228,7 @@ Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type,
mutex_lock(&ctx->info->gen_types_mutex);
defer (mutex_unlock(&ctx->info->gen_types_mutex));
auto *found_gen_types = map_get(&ctx->info->gen_types, hash_pointer(original_type));
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
if (found_gen_types != nullptr) {
// GB_ASSERT_MSG(ordered_operands.count >= param_count, "%td >= %td", ordered_operands.count, param_count);
@@ -311,13 +311,13 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t
named_type->Named.type_name = e;
mutex_lock(&ctx->info->gen_types_mutex);
auto *found_gen_types = map_get(&ctx->info->gen_types, hash_pointer(original_type));
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
if (found_gen_types) {
array_add(found_gen_types, e);
} else {
auto array = array_make<Entity *>(heap_allocator());
array_add(&array, e);
map_set(&ctx->info->gen_types, hash_pointer(original_type), array);
map_set(&ctx->info->gen_types, original_type, array);
}
mutex_unlock(&ctx->info->gen_types_mutex);
}

View File

@@ -810,7 +810,7 @@ void init_universal(void) {
bool defined_values_double_declaration = false;
for_array(i, bc->defined_values.entries) {
char const *name = cast(char const *)cast(uintptr)bc->defined_values.entries[i].key.key;
char const *name = bc->defined_values.entries[i].key;
ExactValue value = bc->defined_values.entries[i].value;
GB_ASSERT(value.kind != ExactValue_Invalid);
@@ -1086,7 +1086,7 @@ Scope *scope_of_node(Ast *node) {
}
ExprInfo *check_get_expr_info(CheckerContext *c, Ast *expr) {
if (c->untyped != nullptr) {
ExprInfo **found = map_get(c->untyped, hash_pointer(expr));
ExprInfo **found = map_get(c->untyped, expr);
if (found) {
return *found;
}
@@ -1094,7 +1094,7 @@ ExprInfo *check_get_expr_info(CheckerContext *c, Ast *expr) {
} else {
mutex_lock(&c->info->global_untyped_mutex);
defer (mutex_unlock(&c->info->global_untyped_mutex));
ExprInfo **found = map_get(&c->info->global_untyped, hash_pointer(expr));
ExprInfo **found = map_get(&c->info->global_untyped, expr);
if (found) {
return *found;
}
@@ -1104,23 +1104,23 @@ ExprInfo *check_get_expr_info(CheckerContext *c, Ast *expr) {
void check_set_expr_info(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue value) {
if (c->untyped != nullptr) {
map_set(c->untyped, hash_pointer(expr), make_expr_info(mode, type, value, false));
map_set(c->untyped, expr, make_expr_info(mode, type, value, false));
} else {
mutex_lock(&c->info->global_untyped_mutex);
map_set(&c->info->global_untyped, hash_pointer(expr), make_expr_info(mode, type, value, false));
map_set(&c->info->global_untyped, expr, make_expr_info(mode, type, value, false));
mutex_unlock(&c->info->global_untyped_mutex);
}
}
void check_remove_expr_info(CheckerContext *c, Ast *e) {
if (c->untyped != nullptr) {
map_remove(c->untyped, hash_pointer(e));
GB_ASSERT(map_get(c->untyped, hash_pointer(e)) == nullptr);
map_remove(c->untyped, e);
GB_ASSERT(map_get(c->untyped, e) == nullptr);
} else {
auto *untyped = &c->info->global_untyped;
mutex_lock(&c->info->global_untyped_mutex);
map_remove(untyped, hash_pointer(e));
GB_ASSERT(map_get(untyped, hash_pointer(e)) == nullptr);
map_remove(untyped, e);
GB_ASSERT(map_get(untyped, e) == nullptr);
mutex_unlock(&c->info->global_untyped_mutex);
}
}
@@ -1135,8 +1135,7 @@ isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
mutex_lock(&info->type_info_mutex);
isize entry_index = -1;
HashKey key = hash_type(type);
isize *found_entry_index = map_get(&info->type_info_map, key);
isize *found_entry_index = map_get(&info->type_info_map, type);
if (found_entry_index) {
entry_index = *found_entry_index;
}
@@ -1145,11 +1144,10 @@ isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
// TODO(bill): This is O(n) and can be very slow
for_array(i, info->type_info_map.entries){
auto *e = &info->type_info_map.entries[i];
Type *prev_type = cast(Type *)cast(uintptr)e->key.key;
if (are_types_identical(prev_type, type)) {
if (are_types_identical(e->key, type)) {
entry_index = e->value;
// NOTE(bill): Add it to the search map
map_set(&info->type_info_map, key, entry_index);
map_set(&info->type_info_map, type, entry_index);
break;
}
}
@@ -1484,7 +1482,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
add_type_info_dependency(c->decl, t);
auto found = map_get(&c->info->type_info_map, hash_type(t));
auto found = map_get(&c->info->type_info_map, t);
if (found != nullptr) {
// Types have already been added
return;
@@ -1494,8 +1492,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
isize ti_index = -1;
for_array(i, c->info->type_info_map.entries) {
auto *e = &c->info->type_info_map.entries[i];
Type *prev_type = cast(Type *)cast(uintptr)e->key.key;
if (are_types_identical(t, prev_type)) {
if (are_types_identical(t, e->key)) {
// Duplicate entry
ti_index = e->value;
prev = true;
@@ -1508,7 +1505,7 @@ 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(&c->checker->info.type_info_map, hash_type(t), ti_index);
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
@@ -2182,27 +2179,8 @@ bool is_entity_a_dependency(Entity *e) {
return false;
}
void add_entity_dependency_from_procedure_parameters(Map<EntityGraphNode *> *M, EntityGraphNode *n, Type *tuple) {
if (tuple == nullptr) {
return;
}
GB_ASSERT(tuple->kind == Type_Tuple);
TypeTuple *t = &tuple->Tuple;
for_array(i, t->variables) {
Entity *v = t->variables[i];
EntityGraphNode **found = map_get(M, hash_pointer(v));
if (found == nullptr) {
continue;
}
EntityGraphNode *m = *found;
entity_graph_node_set_add(&n->succ, m);
entity_graph_node_set_add(&m->pred, n);
}
}
Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info, gbAllocator allocator) {
Map<EntityGraphNode *> M = {}; // Key: Entity *
PtrMap<Entity *, EntityGraphNode *> M = {};
map_init(&M, allocator, info->entities.count);
defer (map_destroy(&M));
for_array(i, info->entities) {
@@ -2210,7 +2188,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info, gbA
if (is_entity_a_dependency(e)) {
EntityGraphNode *n = gb_alloc_item(allocator, EntityGraphNode);
n->entity = e;
map_set(&M, hash_pointer(e), n);
map_set(&M, e, n);
}
}
@@ -2230,9 +2208,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info, gbA
}
GB_ASSERT(dep != nullptr);
if (is_entity_a_dependency(dep)) {
EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
GB_ASSERT(m_ != nullptr);
EntityGraphNode *m = *m_;
EntityGraphNode *m = map_must_get(&M, dep);
entity_graph_node_set_add(&n->succ, m);
entity_graph_node_set_add(&m->pred, n);
}
@@ -2247,7 +2223,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info, gbA
for_array(i, M.entries) {
auto *entry = &M.entries[i];
auto *e = cast(Entity *)cast(uintptr)entry->key.key;
auto *e = entry->key;
EntityGraphNode *n = entry->value;
if (e->kind == Entity_Procedure) {
@@ -3731,7 +3707,7 @@ String path_to_entity_name(String name, String fullpath, bool strip_extension=tr
#if 1
void add_import_dependency_node(Checker *c, Ast *decl, Map<ImportGraphNode *> *M) {
void add_import_dependency_node(Checker *c, Ast *decl, PtrMap<AstPackage *, ImportGraphNode *> *M) {
AstPackage *parent_pkg = decl->file->pkg;
switch (decl->kind) {
@@ -3755,11 +3731,11 @@ void add_import_dependency_node(Checker *c, Ast *decl, Map<ImportGraphNode *> *M
ImportGraphNode *m = nullptr;
ImportGraphNode *n = nullptr;
found_node = map_get(M, hash_pointer(pkg));
found_node = map_get(M, pkg);
GB_ASSERT(found_node != nullptr);
m = *found_node;
found_node = map_get(M, hash_pointer(parent_pkg));
found_node = map_get(M, parent_pkg);
GB_ASSERT(found_node != nullptr);
n = *found_node;
@@ -3797,14 +3773,14 @@ void add_import_dependency_node(Checker *c, Ast *decl, Map<ImportGraphNode *> *M
}
Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c) {
Map<ImportGraphNode *> M = {}; // Key: AstPackage *
PtrMap<AstPackage *, ImportGraphNode *> M = {};
map_init(&M, heap_allocator(), 2*c->parser->packages.count);
defer (map_destroy(&M));
for_array(i, c->parser->packages) {
AstPackage *pkg = c->parser->packages[i];
ImportGraphNode *n = import_graph_node_create(heap_allocator(), pkg);
map_set(&M, hash_pointer(pkg), n);
map_set(&M, pkg, n);
}
// Calculate edges for graph M
@@ -4510,9 +4486,9 @@ void check_import_entities(Checker *c) {
}
Array<Entity *> find_entity_path(Entity *start, Entity *end, Map<Entity *> *visited = nullptr);
Array<Entity *> find_entity_path(Entity *start, Entity *end, PtrSet<Entity *> *visited = nullptr);
bool find_entity_path_tuple(Type *tuple, Entity *end, Map<Entity *> *visited, Array<Entity *> *path_) {
bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet<Entity *> *visited, Array<Entity *> *path_) {
GB_ASSERT(path_ != nullptr);
if (tuple == nullptr) {
return false;
@@ -4544,26 +4520,24 @@ bool find_entity_path_tuple(Type *tuple, Entity *end, Map<Entity *> *visited, Ar
return false;
}
Array<Entity *> find_entity_path(Entity *start, Entity *end, Map<Entity *> *visited) {
Map<Entity *> visited_ = {};
Array<Entity *> find_entity_path(Entity *start, Entity *end, PtrSet<Entity *> *visited) {
PtrSet<Entity *> visited_ = {};
bool made_visited = false;
if (visited == nullptr) {
made_visited = true;
map_init(&visited_, heap_allocator());
ptr_set_init(&visited_, heap_allocator());
visited = &visited_;
}
defer (if (made_visited) {
map_destroy(&visited_);
ptr_set_destroy(&visited_);
});
Array<Entity *> empty_path = {};
HashKey key = hash_pointer(start);
if (map_get(visited, key) != nullptr) {
if (ptr_set_exists(visited, start)) {
return empty_path;
}
map_set(visited, key, start);
ptr_set_add(visited, start);
DeclInfo *decl = start->decl_info;
if (decl) {
@@ -4955,7 +4929,7 @@ void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped) {
return;
}
for_array(i, untyped->entries) {
Ast *expr = cast(Ast *)cast(uintptr)untyped->entries[i].key.key;
Ast *expr = untyped->entries[i].key;
ExprInfo *info = untyped->entries[i].value;
if (expr != nullptr && info != nullptr) {
mpmc_enqueue(&cinfo->checker->global_untyped_queue, UntypedExprInfo{expr, info});
@@ -5207,6 +5181,17 @@ void check_sort_init_procedures(Checker *c) {
gb_sort_array(c->info.init_procedures.data, c->info.init_procedures.count, init_procedures_cmp);
}
void add_type_info_for_type_definitions(Checker *c) {
for_array(i, c->info.definitions) {
Entity *e = c->info.definitions[i];
if (e->kind == Entity_TypeName && e->type != nullptr) {
i64 align = type_align_of(e->type);
if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) {
add_type_info_type(&c->builtin_ctx, e->type);
}
}
}
}
void check_parsed_files(Checker *c) {
TIME_SECTION("map full filepaths to scope");
@@ -5286,7 +5271,7 @@ void check_parsed_files(Checker *c) {
}
TIME_SECTION("add type information");
TIME_SECTION("add basic type information");
// Add "Basic" type information
for (isize i = 0; i < Basic_COUNT; i++) {
Type *t = &basic_types[i];
@@ -5331,16 +5316,7 @@ void check_parsed_files(Checker *c) {
check_unchecked_bodies(c);
TIME_SECTION("add type info for type definitions");
for_array(i, c->info.definitions) {
Entity *e = c->info.definitions[i];
if (e->kind == Entity_TypeName && e->type != nullptr) {
i64 align = type_align_of(e->type);
if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) {
add_type_info_type(&c->builtin_ctx, e->type);
}
}
}
add_type_info_for_type_definitions(c);
check_merge_queues_into_arrays(c);
TIME_SECTION("check entry point");

View File

@@ -264,7 +264,7 @@ struct UntypedExprInfo {
ExprInfo *info;
};
typedef Map<ExprInfo *> UntypedExprInfoMap; // Key: Ast *
typedef PtrMap<Ast *, ExprInfo *> UntypedExprInfoMap;
typedef MPMCQueue<ProcInfo *> ProcBodyQueue;
// CheckerInfo stores all the symbol information for a type-checked program
@@ -316,12 +316,12 @@ struct CheckerInfo {
RecursiveMutex gen_procs_mutex;
RecursiveMutex gen_types_mutex;
Map<Array<Entity *> > gen_procs; // Key: Ast * | Identifier -> Entity
Map<Array<Entity *> > gen_types; // Key: Type *
PtrMap<Ast *, Array<Entity *> > gen_procs; // Key: Ast * | Identifier -> Entity
PtrMap<Type *, Array<Entity *> > gen_types;
BlockingMutex type_info_mutex; // NOT recursive
Array<Type *> type_info_types;
Map<isize> type_info_map; // Key: Type *
PtrMap<Type *, isize> type_info_map;
BlockingMutex foreign_mutex; // NOT recursive
StringMap<Entity *> foreigns;
@@ -406,13 +406,6 @@ gb_global AstPackage *intrinsics_pkg = nullptr;
gb_global AstPackage *config_pkg = nullptr;
HashKey hash_node (Ast *node) { return hash_pointer(node); }
HashKey hash_ast_file (AstFile *file) { return hash_pointer(file); }
HashKey hash_entity (Entity *e) { return hash_pointer(e); }
HashKey hash_type (Type *t) { return hash_pointer(t); }
HashKey hash_decl_info(DeclInfo *decl) { return hash_pointer(decl); }
// CheckerInfo API
TypeAndValue type_and_value_of_expr (Ast *expr);
Type * type_of_expr (Ast *expr);

View File

@@ -275,9 +275,9 @@ gb_global String global_module_path = {0};
gb_global bool global_module_path_set = false;
#include "string_map.cpp"
#include "map.cpp"
#include "ptr_map.cpp"
#include "ptr_set.cpp"
#include "string_map.cpp"
#include "string_set.cpp"
#include "priority_queue.cpp"
#include "thread_pool.cpp"
@@ -289,13 +289,13 @@ struct StringIntern {
char str[1];
};
Map<StringIntern *> string_intern_map = {}; // Key: u64
PtrMap<uintptr, StringIntern *> string_intern_map = {}; // Key: u64
gb_global 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));
uintptr key = cast(uintptr)(hash ? hash : 1);
StringIntern **found = map_get(&string_intern_map, key);
if (found) {
for (StringIntern *it = *found; it != nullptr; it = it->next) {
if (it->len == len && gb_strncmp(it->str, (char *)text, len) == 0) {
@@ -309,7 +309,7 @@ char const *string_intern(char const *text, isize 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);
map_set(&string_intern_map, key, new_intern);
return new_intern->str;
}

View File

@@ -26,12 +26,10 @@ struct OdinDocWriter {
StringMap<OdinDocString> string_cache;
Map<OdinDocFileIndex> file_cache; // Key: AstFile *
Map<OdinDocPkgIndex> pkg_cache; // Key: AstPackage *
Map<OdinDocEntityIndex> entity_cache; // Key: Entity *
Map<Entity *> entity_id_cache; // Key: OdinDocEntityIndex
Map<OdinDocTypeIndex> type_cache; // Key: Type *
Map<Type *> type_id_cache; // Key: OdinDocTypeIndex
PtrMap<AstFile *, OdinDocFileIndex> file_cache;
PtrMap<AstPackage *, OdinDocPkgIndex> pkg_cache;
PtrMap<Entity *, OdinDocEntityIndex> entity_cache;
PtrMap<Type *, OdinDocTypeIndex> type_cache;
OdinDocWriterItemTracker<OdinDocFile> files;
OdinDocWriterItemTracker<OdinDocPkg> pkgs;
@@ -61,9 +59,7 @@ void odin_doc_writer_prepare(OdinDocWriter *w) {
map_init(&w->file_cache, a);
map_init(&w->pkg_cache, a);
map_init(&w->entity_cache, a);
map_init(&w->entity_id_cache, a);
map_init(&w->type_cache, a);
map_init(&w->type_id_cache, a);
odin_doc_writer_item_tracker_init(&w->files, 1);
odin_doc_writer_item_tracker_init(&w->pkgs, 1);
@@ -81,9 +77,7 @@ void odin_doc_writer_destroy(OdinDocWriter *w) {
map_destroy(&w->file_cache);
map_destroy(&w->pkg_cache);
map_destroy(&w->entity_cache);
map_destroy(&w->entity_id_cache);
map_destroy(&w->type_cache);
map_destroy(&w->type_id_cache);
}
@@ -115,9 +109,7 @@ void odin_doc_writer_start_writing(OdinDocWriter *w) {
map_clear(&w->file_cache);
map_clear(&w->pkg_cache);
map_clear(&w->entity_cache);
map_clear(&w->entity_id_cache);
map_clear(&w->type_cache);
map_clear(&w->type_id_cache);
isize total_size = odin_doc_writer_calc_total_size(w);
total_size = align_formula_isize(total_size, 8);
@@ -267,7 +259,7 @@ OdinDocPosition odin_doc_token_pos_cast(OdinDocWriter *w, TokenPos const &pos) {
if (pos.file_id != 0) {
AstFile *file = get_ast_file_from_id(pos.file_id);
if (file != nullptr) {
OdinDocFileIndex *file_index_found = map_get(&w->file_cache, hash_pointer(file));
OdinDocFileIndex *file_index_found = map_get(&w->file_cache, file);
GB_ASSERT(file_index_found != nullptr);
file_index = *file_index_found;
}
@@ -483,16 +475,16 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
if (type == nullptr) {
return 0;
}
OdinDocTypeIndex *found = map_get(&w->type_cache, hash_pointer(type));
OdinDocTypeIndex *found = map_get(&w->type_cache, type);
if (found) {
return *found;
}
for_array(i, w->type_cache.entries) {
// NOTE(bill): THIS IS SLOW
Type *other = cast(Type *)cast(uintptr)w->type_cache.entries[i].key.key;
Type *other = w->type_cache.entries[i].key;
if (are_types_identical(type, other)) {
OdinDocTypeIndex index = w->type_cache.entries[i].value;
map_set(&w->type_cache, hash_pointer(type), index);
map_set(&w->type_cache, type, index);
return index;
}
}
@@ -502,8 +494,7 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
OdinDocType doc_type = {};
OdinDocTypeIndex type_index = 0;
type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst);
map_set(&w->type_cache, hash_pointer(type), type_index);
map_set(&w->type_id_cache, hash_integer(type_index), type);
map_set(&w->type_cache, type, type_index);
switch (type->kind) {
case Type_Basic:
@@ -776,12 +767,12 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
return 0;
}
OdinDocEntityIndex *prev_index = map_get(&w->entity_cache, hash_pointer(e));
OdinDocEntityIndex *prev_index = map_get(&w->entity_cache, e);
if (prev_index) {
return *prev_index;
}
if (e->pkg != nullptr && map_get(&w->pkg_cache, hash_pointer(e->pkg)) == nullptr) {
if (e->pkg != nullptr && map_get(&w->pkg_cache, e->pkg) == nullptr) {
return 0;
}
@@ -789,8 +780,7 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
OdinDocEntity* dst = nullptr;
OdinDocEntityIndex doc_entity_index = odin_doc_write_item(w, &w->entities, &doc_entity, &dst);
map_set(&w->entity_cache, hash_pointer(e), doc_entity_index);
map_set(&w->entity_id_cache, hash_integer(doc_entity_index), e);
map_set(&w->entity_cache, e, doc_entity_index);
Ast *type_expr = nullptr;
@@ -901,7 +891,7 @@ void odin_doc_update_entities(OdinDocWriter *w) {
defer (array_free(&entities));
for_array(i, w->entity_cache.entries) {
Entity *e = cast(Entity *)cast(uintptr)w->entity_cache.entries[i].key.key;
Entity *e = w->entity_cache.entries[i].key;
entities[i] = e;
}
for_array(i, entities) {
@@ -912,7 +902,7 @@ void odin_doc_update_entities(OdinDocWriter *w) {
}
for_array(i, w->entity_cache.entries) {
Entity *e = cast(Entity *)cast(uintptr)w->entity_cache.entries[i].key.key;
Entity *e = w->entity_cache.entries[i].key;
OdinDocEntityIndex entity_index = w->entity_cache.entries[i].value;
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
@@ -955,7 +945,7 @@ OdinDocArray<OdinDocEntityIndex> odin_doc_add_pkg_entities(OdinDocWriter *w, Ast
if (pkg->scope == nullptr) {
return {};
}
if (map_get(&w->pkg_cache, hash_pointer(pkg)) == nullptr) {
if (map_get(&w->pkg_cache, pkg) == nullptr) {
return {};
}
@@ -1056,7 +1046,7 @@ void odin_doc_write_docs(OdinDocWriter *w) {
OdinDocPkg *dst = nullptr;
OdinDocPkgIndex pkg_index = odin_doc_write_item(w, &w->pkgs, &doc_pkg, &dst);
map_set(&w->pkg_cache, hash_pointer(pkg), pkg_index);
map_set(&w->pkg_cache, pkg, pkg_index);
auto file_indices = array_make<OdinDocFileIndex>(heap_allocator(), 0, pkg->files.count);
defer (array_free(&file_indices));
@@ -1067,7 +1057,7 @@ void odin_doc_write_docs(OdinDocWriter *w) {
doc_file.pkg = pkg_index;
doc_file.name = odin_doc_write_string(w, file->fullpath);
OdinDocFileIndex file_index = odin_doc_write_item(w, &w->files, &doc_file);
map_set(&w->file_cache, hash_pointer(file), file_index);
map_set(&w->file_cache, file, file_index);
array_add(&file_indices, file_index);
}

View File

@@ -63,44 +63,39 @@ struct ExactValue {
gb_global ExactValue const empty_exact_value = {};
HashKey hash_exact_value(ExactValue v) {
uintptr hash_exact_value(ExactValue v) {
mutex_lock(&hash_exact_value_mutex);
defer (mutex_unlock(&hash_exact_value_mutex));
HashKey empty = {};
switch (v.kind) {
case ExactValue_Invalid:
return empty;
return 0;
case ExactValue_Bool:
return hash_integer(u64(v.value_bool));
return gb_fnv32a(&v.value_bool, gb_size_of(v.value_bool));
case ExactValue_String:
{
char const *str = string_intern(v.value_string);
return hash_pointer(str);
}
return ptr_map_hash_key(string_intern(v.value_string));
case ExactValue_Integer:
{
HashKey key = hashing_proc(v.value_integer.dp, gb_size_of(*v.value_integer.dp) * v.value_integer.used);
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;
key.key = (key.key ^ last) * 0x100000001b3ll;
return key;
return (key ^ last) * 0x01000193;
}
case ExactValue_Float:
return hash_f64(v.value_float);
return gb_fnv32a(&v.value_float, gb_size_of(v.value_float));
case ExactValue_Pointer:
return hash_integer(v.value_pointer);
return ptr_map_hash_key(v.value_pointer);
case ExactValue_Complex:
return hashing_proc(v.value_complex, gb_size_of(Complex128));
return gb_fnv32a(v.value_complex, gb_size_of(Complex128));
case ExactValue_Quaternion:
return hashing_proc(v.value_quaternion, gb_size_of(Quaternion256));
return gb_fnv32a(v.value_quaternion, gb_size_of(Quaternion256));
case ExactValue_Compound:
return hash_pointer(v.value_compound);
return ptr_map_hash_key(v.value_compound);
case ExactValue_Procedure:
return hash_pointer(v.value_procedure);
return ptr_map_hash_key(v.value_procedure);
case ExactValue_Typeid:
return hash_pointer(v.value_typeid);
return ptr_map_hash_key(v.value_typeid);
}
return hashing_proc(&v, gb_size_of(ExactValue));
return gb_fnv32a(&v, gb_size_of(ExactValue));
}

View File

@@ -123,8 +123,7 @@ lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) {
Type *pt = alloc_type_pointer(type);
LLVMTypeRef ptr_type = lb_type(m, pt);
auto key = hash_type(type);
lbProcedure **found = map_get(&m->equal_procs, key);
lbProcedure **found = map_get(&m->equal_procs, type);
lbProcedure *compare_proc = nullptr;
if (found) {
compare_proc = *found;
@@ -140,7 +139,7 @@ lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) {
String proc_name = make_string_c(str);
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc);
map_set(&m->equal_procs, key, p);
map_set(&m->equal_procs, type, p);
lb_begin_procedure_body(p);
LLVMValueRef x = LLVMGetParam(p->value, 0);
@@ -279,8 +278,7 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) {
Type *pt = alloc_type_pointer(type);
auto key = hash_type(type);
lbProcedure **found = map_get(&m->hasher_procs, key);
lbProcedure **found = map_get(&m->hasher_procs, type);
if (found) {
GB_ASSERT(*found != nullptr);
return {(*found)->value, (*found)->type};
@@ -294,7 +292,7 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) {
String proc_name = make_string_c(str);
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_hasher_proc);
map_set(&m->hasher_procs, key, p);
map_set(&m->hasher_procs, type, p);
lb_begin_procedure_body(p);
defer (lb_end_procedure_body(p));
@@ -433,7 +431,7 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) {
lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent) {
lbProcedure **found = map_get(&m->gen->anonymous_proc_lits, hash_pointer(expr));
lbProcedure **found = map_get(&m->gen->anonymous_proc_lits, expr);
if (found) {
return lb_find_procedure_value_from_entity(m, (*found)->entity);
}
@@ -473,8 +471,7 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A
string_map_set(&m->members, name, value);
}
map_set(&m->anonymous_proc_lits, hash_pointer(expr), p);
map_set(&m->gen->anonymous_proc_lits, hash_pointer(expr), p);
map_set(&m->gen->anonymous_proc_lits, expr, p);
return value;
}

View File

@@ -114,25 +114,23 @@ struct lbModule {
CheckerInfo *info;
AstPackage *pkg; // associated
Map<LLVMTypeRef> types; // Key: Type *
Map<lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *
Map<Type *> llvm_types; // Key: LLVMTypeRef
PtrMap<Type *, LLVMTypeRef> types;
PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *
i32 internal_type_level;
Map<lbValue> values; // Key: Entity *
Map<lbAddr> soa_values; // Key: Entity *
PtrMap<Entity *, lbValue> values;
PtrMap<Entity *, lbAddr> soa_values;
StringMap<lbValue> members;
StringMap<lbProcedure *> procedures;
Map<Entity *> procedure_values; // Key: LLVMValueRef
PtrMap<LLVMValueRef, Entity *> procedure_values;
Array<lbProcedure *> missing_procedures_to_check;
StringMap<LLVMValueRef> const_strings;
Map<lbProcedure *> anonymous_proc_lits; // Key: Ast *
Map<struct lbFunctionType *> function_type_map; // Key: Type *
PtrMap<Type *, struct lbFunctionType *> function_type_map;
Map<lbProcedure *> equal_procs; // Key: Type *
Map<lbProcedure *> hasher_procs; // Key: Type *
PtrMap<Type *, lbProcedure *> equal_procs;
PtrMap<Type *, lbProcedure *> hasher_procs;
u32 nested_type_name_guid;
@@ -143,7 +141,7 @@ struct lbModule {
LLVMDIBuilderRef debug_builder;
LLVMMetadataRef debug_compile_unit;
Map<LLVMMetadataRef> debug_values; // Key: Pointer
PtrMap<void *, LLVMMetadataRef> debug_values;
Array<lbIncompleteDebugType> debug_incomplete_types;
};
@@ -155,11 +153,11 @@ struct lbGenerator {
Array<String> output_temp_paths;
String output_base;
String output_name;
Map<lbModule *> modules; // Key: AstPackage *
Map<lbModule *> modules_through_ctx; // Key: LLVMContextRef *
PtrMap<AstPackage *, lbModule *> modules;
PtrMap<LLVMContextRef, lbModule *> modules_through_ctx;
lbModule default_module;
Map<lbProcedure *> anonymous_proc_lits; // Key: Ast *
PtrMap<Ast *, lbProcedure *> anonymous_proc_lits;
std::atomic<u32> global_array_index;
std::atomic<u32> global_generated_index;

View File

@@ -2,7 +2,7 @@ LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) {
if (key == nullptr) {
return nullptr;
}
auto found = map_get(&m->debug_values, hash_pointer(key));
auto found = map_get(&m->debug_values, key);
if (found) {
return *found;
}
@@ -10,7 +10,7 @@ LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) {
}
void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef value) {
if (key != nullptr) {
map_set(&m->debug_values, hash_pointer(key), value);
map_set(&m->debug_values, key, value);
}
}

View File

@@ -3142,7 +3142,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
}
lbAddr lb_get_soa_variable_addr(lbProcedure *p, Entity *e) {
return map_must_get(&p->module->soa_values, hash_entity(e));
return map_must_get(&p->module->soa_values, e);
}
lbValue lb_get_using_variable(lbProcedure *p, Entity *e) {
GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using);
@@ -3150,7 +3150,7 @@ lbValue lb_get_using_variable(lbProcedure *p, Entity *e) {
Entity *parent = e->using_parent;
Selection sel = lookup_field(parent->type, name, false);
GB_ASSERT(sel.entity != nullptr);
lbValue *pv = map_get(&p->module->values, hash_entity(parent));
lbValue *pv = map_get(&p->module->values, parent);
lbValue v = {};
@@ -3190,7 +3190,7 @@ lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) {
lbValue v = {};
lbValue *found = map_get(&p->module->values, hash_entity(e));
lbValue *found = map_get(&p->module->values, e);
if (found) {
v = *found;
} else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {

View File

@@ -57,14 +57,12 @@ void lb_init_module(lbModule *m, Checker *c) {
gbAllocator a = heap_allocator();
map_init(&m->types, a);
map_init(&m->struct_field_remapping, a);
map_init(&m->llvm_types, a);
map_init(&m->values, a);
map_init(&m->soa_values, a);
string_map_init(&m->members, a);
map_init(&m->procedure_values, a);
string_map_init(&m->procedures, a);
string_map_init(&m->const_strings, a);
map_init(&m->anonymous_proc_lits, a);
map_init(&m->function_type_map, a);
map_init(&m->equal_procs, a);
map_init(&m->hasher_procs, a);
@@ -133,20 +131,20 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) {
auto m = gb_alloc_item(permanent_allocator(), lbModule);
m->pkg = pkg;
m->gen = gen;
map_set(&gen->modules, hash_pointer(pkg), m);
map_set(&gen->modules, pkg, m);
lb_init_module(m, c);
}
}
gen->default_module.gen = gen;
map_set(&gen->modules, hash_pointer(nullptr), &gen->default_module);
map_set(&gen->modules, cast(AstPackage *)nullptr, &gen->default_module);
lb_init_module(&gen->default_module, c);
for_array(i, gen->modules.entries) {
lbModule *m = gen->modules.entries[i].value;
LLVMContextRef ctx = LLVMGetModuleContext(m->mod);
map_set(&gen->modules_through_ctx, hash_pointer(ctx), m);
map_set(&gen->modules_through_ctx, ctx, m);
}
return true;
@@ -251,7 +249,7 @@ bool lb_is_instr_terminating(LLVMValueRef instr) {
lbModule *lb_pkg_module(lbGenerator *gen, AstPackage *pkg) {
auto *found = map_get(&gen->modules, hash_pointer(pkg));
auto *found = map_get(&gen->modules, pkg);
if (found) {
return *found;
}
@@ -1590,7 +1588,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
return lb_type_internal(m, base);
}
LLVMTypeRef *found = map_get(&m->types, hash_type(base));
LLVMTypeRef *found = map_get(&m->types, base);
if (found) {
LLVMTypeKind kind = LLVMGetTypeKind(*found);
if (kind == LLVMStructTypeKind) {
@@ -1600,7 +1598,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
return llvm_type;
}
llvm_type = LLVMStructCreateNamed(ctx, name);
map_set(&m->types, hash_type(type), llvm_type);
map_set(&m->types, type, llvm_type);
lb_clone_struct_type(llvm_type, *found);
return llvm_type;
}
@@ -1616,7 +1614,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
return llvm_type;
}
llvm_type = LLVMStructCreateNamed(ctx, name);
map_set(&m->types, hash_type(type), llvm_type);
map_set(&m->types, type, llvm_type);
lb_clone_struct_type(llvm_type, lb_type(m, base));
return llvm_type;
}
@@ -1697,7 +1695,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
for_array(i, entries_field_remapping) {
entries_field_remapping[i] = cast(i32)i;
}
map_set(&m->struct_field_remapping, hash_pointer(fields[1]), entries_field_remapping);
map_set(&m->struct_field_remapping, cast(void *)fields[1], entries_field_remapping);
}
return LLVMStructTypeInContext(ctx, fields, field_count, false);
@@ -1721,8 +1719,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
field_remapping[0] = 0;
LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false);
map_set(&m->struct_field_remapping, hash_pointer(struct_type), field_remapping);
map_set(&m->struct_field_remapping, hash_pointer(type), field_remapping);
map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping);
map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);
return struct_type;
}
@@ -1768,8 +1766,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
}
LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, type->Struct.is_packed);
map_set(&m->struct_field_remapping, hash_pointer(struct_type), field_remapping);
map_set(&m->struct_field_remapping, hash_pointer(type), field_remapping);
map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping);
map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);
#if 0
GB_ASSERT_MSG(lb_sizeof(struct_type) == full_type_size,
"(%lld) %s vs (%lld) %s",
@@ -1930,7 +1928,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
}
map_set(&m->function_type_map, hash_type(type), ft);
map_set(&m->function_type_map, type, ft);
LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg);
LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type);
@@ -1991,7 +1989,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
LLVMTypeRef lb_type(lbModule *m, Type *type) {
type = default_type(type);
LLVMTypeRef *found = map_get(&m->types, hash_type(type));
LLVMTypeRef *found = map_get(&m->types, type);
if (found) {
return *found;
}
@@ -2002,21 +2000,18 @@ LLVMTypeRef lb_type(lbModule *m, Type *type) {
llvm_type = lb_type_internal(m, type);
m->internal_type_level -= 1;
if (m->internal_type_level == 0) {
map_set(&m->types, hash_type(type), llvm_type);
if (is_type_named(type)) {
map_set(&m->llvm_types, hash_pointer(llvm_type), type);
}
map_set(&m->types, type, llvm_type);
}
return llvm_type;
}
lbFunctionType *lb_get_function_type(lbModule *m, lbProcedure *p, Type *pt) {
lbFunctionType **ft_found = nullptr;
ft_found = map_get(&m->function_type_map, hash_type(pt));
ft_found = map_get(&m->function_type_map, pt);
if (!ft_found) {
LLVMTypeRef llvm_proc_type = lb_type(p->module, pt);
gb_unused(llvm_proc_type);
ft_found = map_get(&m->function_type_map, hash_type(pt));
ft_found = map_get(&m->function_type_map, pt);
}
GB_ASSERT(ft_found != nullptr);
@@ -2027,12 +2022,11 @@ void lb_ensure_abi_function_type(lbModule *m, lbProcedure *p) {
if (p->abi_function_type != nullptr) {
return;
}
auto hash = hash_type(p->type);
lbFunctionType **ft_found = map_get(&m->function_type_map, hash);
lbFunctionType **ft_found = map_get(&m->function_type_map, p->type);
if (ft_found == nullptr) {
LLVMTypeRef llvm_proc_type = lb_type(p->module, p->type);
gb_unused(llvm_proc_type);
ft_found = map_get(&m->function_type_map, hash);
ft_found = map_get(&m->function_type_map, p->type);
}
GB_ASSERT(ft_found != nullptr);
p->abi_function_type = *ft_found;
@@ -2041,7 +2035,7 @@ void lb_ensure_abi_function_type(lbModule *m, lbProcedure *p) {
void lb_add_entity(lbModule *m, Entity *e, lbValue val) {
if (e != nullptr) {
map_set(&m->values, hash_entity(e), val);
map_set(&m->values, e, val);
}
}
void lb_add_member(lbModule *m, String const &name, lbValue val) {
@@ -2054,7 +2048,7 @@ void lb_add_member(lbModule *m, StringHashKey const &key, lbValue val) {
}
void lb_add_procedure_value(lbModule *m, lbProcedure *p) {
if (p->entity != nullptr) {
map_set(&m->procedure_values, hash_pointer(p->value), p->entity);
map_set(&m->procedure_values, p->value, p->entity);
}
string_map_set(&m->procedures, p->name, p);
}
@@ -2368,7 +2362,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *expr) {
auto *found = map_get(&m->values, hash_entity(e));
auto *found = map_get(&m->values, e);
if (found) {
auto v = *found;
// NOTE(bill): This is because pointers are already pointers in LLVM
@@ -2417,7 +2411,7 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
e = strip_entity_wrapping(e);
GB_ASSERT(e != nullptr);
auto *found = map_get(&m->values, hash_entity(e));
auto *found = map_get(&m->values, e);
if (found) {
return *found;
}
@@ -2437,7 +2431,7 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
if (!ignore_body) {
array_add(&m->missing_procedures_to_check, missing_proc);
}
found = map_get(&m->values, hash_entity(e));
found = map_get(&m->values, e);
if (found) {
return *found;
}
@@ -2501,7 +2495,7 @@ lbValue lb_find_value_from_entity(lbModule *m, Entity *e) {
return lb_find_procedure_value_from_entity(m, e);
}
auto *found = map_get(&m->values, hash_entity(e));
auto *found = map_get(&m->values, e);
if (found) {
return *found;
}

View File

@@ -387,7 +387,7 @@ void lb_run_remove_unused_function_pass(lbModule *m) {
continue;
}
Entity **found = map_get(&m->procedure_values, hash_pointer(curr_func));
Entity **found = map_get(&m->procedure_values, curr_func);
if (found && *found) {
Entity *e = *found;
bool is_required = (e->flags & EntityFlag_Require) == EntityFlag_Require;

View File

@@ -948,7 +948,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
}
Entity **found = map_get(&p->module->procedure_values, hash_pointer(value.value));
Entity **found = map_get(&p->module->procedure_values, value.value);
if (found != nullptr) {
Entity *e = *found;
if (e != nullptr && entity_has_deferred_procedure(e)) {

View File

@@ -83,7 +83,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
DeclInfo *decl = decl_info_of_entity(e);
ast_node(pl, ProcLit, decl->proc_lit);
if (pl->body != nullptr) {
auto *found = map_get(&info->gen_procs, hash_pointer(ident));
auto *found = map_get(&info->gen_procs, ident);
if (found) {
auto procs = *found;
for_array(i, procs) {
@@ -670,7 +670,7 @@ void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *sco
Entity *e = entity_of_node(rs->vals[0]);
if (e != nullptr) {
lbAddr soa_val = lb_addr_soa_variable(array.addr, lb_addr_load(p, index), nullptr);
map_set(&p->module->soa_values, hash_entity(e), soa_val);
map_set(&p->module->soa_values, e, soa_val);
}
}
if (val_types[1]) {
@@ -1525,7 +1525,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
} else if (return_count == 1) {
Entity *e = tuple->variables[0];
if (res_count == 0) {
lbValue found = map_must_get(&p->module->values, hash_entity(e));
lbValue found = map_must_get(&p->module->values, e);
res = lb_emit_load(p, found);
} else {
res = lb_build_expr(p, return_results[0]);
@@ -1534,7 +1534,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
if (p->type->Proc.has_named_results) {
// NOTE(bill): store the named values before returning
if (e->token.string != "") {
lbValue found = map_must_get(&p->module->values, hash_entity(e));
lbValue found = map_must_get(&p->module->values, e);
lb_emit_store(p, found, lb_emit_conv(p, res, e->type));
}
}
@@ -1558,7 +1558,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
} else {
for (isize res_index = 0; res_index < return_count; res_index++) {
Entity *e = tuple->variables[res_index];
lbValue found = map_must_get(&p->module->values, hash_entity(e));
lbValue found = map_must_get(&p->module->values, e);
lbValue res = lb_emit_load(p, found);
array_add(&results, res);
}
@@ -1580,7 +1580,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
if (e->token.string == "") {
continue;
}
named_results[i] = map_must_get(&p->module->values, hash_entity(e));
named_results[i] = map_must_get(&p->module->values, e);
values[i] = lb_emit_conv(p, results[i], e->type);
}

View File

@@ -401,7 +401,7 @@ lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
GB_ASSERT(end_entity->token.string.len != 0);
// NOTE(bill): store the named values before returning
lbValue found = map_must_get(&p->module->values, hash_entity(end_entity));
lbValue found = map_must_get(&p->module->values, end_entity);
lb_emit_store(p, found, rhs);
lb_build_return_stmt(p, {});
@@ -811,9 +811,9 @@ lbValue lb_address_from_load(lbProcedure *p, lbValue value) {
lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) {
t = base_type(t);
LLVMTypeRef struct_type = lb_type(m, t);
auto *field_remapping = map_get(&m->struct_field_remapping, hash_pointer(struct_type));
auto *field_remapping = map_get(&m->struct_field_remapping, cast(void *)struct_type);
if (field_remapping == nullptr) {
field_remapping = map_get(&m->struct_field_remapping, hash_pointer(t));
field_remapping = map_get(&m->struct_field_remapping, cast(void *)t);
}
GB_ASSERT(field_remapping != nullptr);
return *field_remapping;

View File

@@ -1109,7 +1109,7 @@ bool parse_build_flags(Array<String> args) {
break;
}
HashKey key = hash_pointer(string_intern(name));
char const *key = string_intern(name);
if (map_get(&build_context.defined_values, key) != nullptr) {
gb_printf_err("Defined constant '%.*s' already exists\n", LIT(name));

View File

@@ -1,358 +0,0 @@
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
// with the use of the `multi_*` procedures.
// TODO(bill): I should probably allow the `multi_map_*` stuff to be #ifdefed out
#define MAP_ENABLE_MULTI_MAP 1
#ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF
// NOTE(bill): This util stuff is the same for every `Map`
struct MapFindResult {
isize hash_index;
isize entry_prev;
isize entry_index;
};
struct HashKey {
u64 key;
};
GB_STATIC_ASSERT(gb_size_of(u64) >= gb_size_of(void *));
gb_inline HashKey hashing_proc(void const *data, isize len) {
HashKey h = {};
h.key = fnv64a(data, len);
return h;
}
gb_inline HashKey hash_pointer(void const *ptr) {
HashKey h = {};
h.key = cast(u64)cast(uintptr)ptr;
return h;
}
gb_inline HashKey hash_integer(u64 u) {
HashKey h = {};
h.key = u;
return h;
}
gb_inline HashKey hash_f64(f64 f) {
HashKey h = {};
h.key = bit_cast<u64>(f);
return h;
}
gb_inline bool hash_key_equal(HashKey a, HashKey b) {
return a.key == b.key;
}
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
template <typename T>
struct MapEntry {
HashKey key;
isize next;
T value;
};
template <typename T>
struct Map {
Slice<isize> hashes;
Array<MapEntry<T> > entries;
};
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> T * map_get (Map<T> *h, HashKey const &key);
template <typename T> T & map_must_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_grow (Map<T> *h);
template <typename T> void map_rehash (Map<T> *h, isize new_count);
#if MAP_ENABLE_MULTI_MAP
// Mutlivalued map procedure
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> 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
template <typename T>
gb_inline void map_init(Map<T> *h, gbAllocator a, isize capacity) {
capacity = next_pow2_isize(capacity);
slice_init(&h->hashes, a, capacity);
array_init(&h->entries, a, 0, capacity);
for (isize i = 0; i < capacity; i++) {
h->hashes.data[i] = -1;
}
}
template <typename T>
gb_inline void map_destroy(Map<T> *h) {
slice_free(&h->hashes, h->entries.allocator);
array_free(&h->entries);
}
template <typename T>
gb_internal isize map__add_entry(Map<T> *h, HashKey const &key) {
MapEntry<T> e = {};
e.key = key;
e.next = -1;
array_add(&h->entries, e);
return h->entries.count-1;
}
template <typename T>
gb_internal MapFindResult map__find(Map<T> *h, HashKey const &key) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count == 0) {
return fr;
}
fr.hash_index = key.key & (h->hashes.count-1);
fr.entry_index = h->hashes.data[fr.hash_index];
while (fr.entry_index >= 0) {
if (hash_key_equal(h->entries.data[fr.entry_index].key, key)) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.data[fr.entry_index].next;
}
return fr;
}
template <typename T>
gb_internal MapFindResult map__find_from_entry(Map<T> *h, MapEntry<T> *e) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count == 0) {
return fr;
}
fr.hash_index = e->key.key & (h->hashes.count-1);
fr.entry_index = h->hashes.data[fr.hash_index];
while (fr.entry_index >= 0) {
if (&h->entries.data[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.data[fr.entry_index].next;
}
return fr;
}
template <typename T>
gb_internal b32 map__full(Map<T> *h) {
return 0.75f * h->hashes.count <= h->entries.count;
}
template <typename T>
gb_inline void map_grow(Map<T> *h) {
isize new_count = gb_max(h->hashes.count<<1, 16);
map_rehash(h, new_count);
}
template <typename T>
void map_rehash(Map<T> *h, isize new_count) {
isize i, j;
Map<T> nh = {};
new_count = next_pow2_isize(new_count);
nh.hashes = h->hashes;
nh.entries.allocator = h->entries.allocator;
slice_resize(&nh.hashes, h->entries.allocator, new_count);
for (i = 0; i < new_count; i++) {
nh.hashes.data[i] = -1;
}
array_reserve(&nh.entries, ARRAY_GROW_FORMULA(h->entries.count));
for (i = 0; i < h->entries.count; i++) {
MapEntry<T> *e = &h->entries.data[i];
MapFindResult fr;
if (nh.hashes.count == 0) {
map_grow(&nh);
}
fr = map__find(&nh, e->key);
j = map__add_entry(&nh, e->key);
if (fr.entry_prev < 0) {
nh.hashes.data[fr.hash_index] = j;
} else {
nh.entries.data[fr.entry_prev].next = j;
}
nh.entries.data[j].next = fr.entry_index;
nh.entries.data[j].value = e->value;
if (map__full(&nh)) {
map_grow(&nh);
}
}
array_free(&h->entries);
*h = nh;
}
template <typename T>
T *map_get(Map<T> *h, HashKey const &key) {
isize index = map__find(h, key).entry_index;
if (index >= 0) {
return &h->entries.data[index].value;
}
return nullptr;
}
template <typename T>
T &map_must_get(Map<T> *h, HashKey const &key) {
isize index = map__find(h, key).entry_index;
GB_ASSERT(index >= 0);
return h->entries.data[index].value;
}
template <typename T>
void map_set(Map<T> *h, HashKey const &key, T const &value) {
isize index;
MapFindResult fr;
if (h->hashes.count == 0) {
map_grow(h);
}
fr = map__find(h, key);
if (fr.entry_index >= 0) {
index = fr.entry_index;
} else {
index = map__add_entry(h, key);
if (fr.entry_prev >= 0) {
h->entries.data[fr.entry_prev].next = index;
} else {
h->hashes.data[fr.hash_index] = index;
}
}
h->entries.data[index].value = value;
if (map__full(h)) {
map_grow(h);
}
}
template <typename T>
void map__erase(Map<T> *h, MapFindResult const &fr) {
MapFindResult last;
if (fr.entry_prev < 0) {
h->hashes.data[fr.hash_index] = h->entries.data[fr.entry_index].next;
} else {
h->entries.data[fr.entry_prev].next = h->entries.data[fr.entry_index].next;
}
if (fr.entry_index == h->entries.count-1) {
array_pop(&h->entries);
return;
}
h->entries.data[fr.entry_index] = h->entries.data[h->entries.count-1];
array_pop(&h->entries);
last = map__find(h, h->entries.data[fr.entry_index].key);
if (last.entry_prev >= 0) {
h->entries.data[last.entry_prev].next = fr.entry_index;
} else {
h->hashes.data[last.hash_index] = fr.entry_index;
}
}
template <typename T>
void map_remove(Map<T> *h, HashKey const &key) {
MapFindResult fr = map__find(h, key);
if (fr.entry_index >= 0) {
map__erase(h, fr);
}
}
template <typename T>
gb_inline void map_clear(Map<T> *h) {
array_clear(&h->entries);
for (isize i = 0; i < h->hashes.count; i++) {
h->hashes.data[i] = -1;
}
}
#if MAP_ENABLE_MULTI_MAP
template <typename T>
MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey const &key) {
isize i = map__find(h, key).entry_index;
if (i < 0) {
return nullptr;
}
return &h->entries.data[i];
}
template <typename T>
MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) {
isize i = e->next;
while (i >= 0) {
if (hash_key_equal(h->entries.data[i].key, e->key)) {
return &h->entries.data[i];
}
i = h->entries.data[i].next;
}
return nullptr;
}
template <typename T>
isize multi_map_count(Map<T> *h, HashKey const &key) {
isize count = 0;
MapEntry<T> *e = multi_map_find_first(h, key);
while (e != nullptr) {
count++;
e = multi_map_find_next(h, e);
}
return count;
}
template <typename T>
void multi_map_get_all(Map<T> *h, HashKey const &key, T *items) {
isize i = 0;
MapEntry<T> *e = multi_map_find_first(h, key);
while (e != nullptr) {
items[i++] = e->value;
e = multi_map_find_next(h, e);
}
}
template <typename T>
void multi_map_insert(Map<T> *h, HashKey const &key, T const &value) {
MapFindResult fr;
isize 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 < 0) {
h->hashes.data[fr.hash_index] = i;
} else {
h->entries.data[fr.entry_prev].next = i;
}
h->entries.data[i].next = fr.entry_index;
h->entries.data[i].value = value;
// Grow if needed
if (map__full(h)) {
map_grow(h);
}
}
template <typename T>
void multi_map_remove(Map<T> *h, HashKey const &key, MapEntry<T> *e) {
MapFindResult fr = map__find_from_entry(h, e);
if (fr.entry_index >= 0) {
map__erase(h, fr);
}
}
template <typename T>
void multi_map_remove_all(Map<T> *h, HashKey const &key) {
while (map_get(h, key) != nullptr) {
map_remove(h, key);
}
}
#endif

339
src/ptr_map.cpp Normal file
View File

@@ -0,0 +1,339 @@
#define PTR_MAP_ENABLE_MULTI_MAP 1
typedef u32 MapIndex;
struct MapFindResult {
MapIndex hash_index;
MapIndex entry_prev;
MapIndex entry_index;
};
enum : MapIndex { MAP_SENTINEL = ~(MapIndex)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;
};
template <typename K, typename V>
struct PtrMap {
Slice<MapIndex> hashes;
Array<PtrMapEntry<K, V> > entries;
};
u32 ptr_map_hash_key(uintptr key) {
#if defined(GB_ARCH_64_BIT)
u64 x = (u64)key;
u8 count = (u8)(x >> 59);
x ^= x >> (5 + count);
x *= 12605985483714917081ull;
return (u32)(x ^ (x >> 43));
#elif defined(GB_ARCH_32_BIT)
u32 state = ((u32)key) * 747796405u + 2891336453u;
u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
#endif
}
u32 ptr_map_hash_key(void const *key) {
return ptr_map_hash_key((uintptr)key);
}
template <typename K, typename V> void map_init (PtrMap<K, V> *h, gbAllocator a, isize capacity = 16);
template <typename K, typename V> void map_destroy (PtrMap<K, V> *h);
template <typename K, typename V> V * map_get (PtrMap<K, V> *h, K key);
template <typename K, typename V> void map_set (PtrMap<K, V> *h, K key, V const &value);
template <typename K, typename V> void map_remove (PtrMap<K, V> *h, K key);
template <typename K, typename V> void map_clear (PtrMap<K, V> *h);
template <typename K, typename V> void map_grow (PtrMap<K, V> *h);
template <typename K, typename V> void map_rehash (PtrMap<K, V> *h, isize new_count);
template <typename K, typename V> void map_reserve (PtrMap<K, V> *h, isize cap);
#if PTR_MAP_ENABLE_MULTI_MAP
// Mutlivalued map procedure
template <typename K, typename V> PtrMapEntry<K, V> * multi_map_find_first(PtrMap<K, V> *h, K key);
template <typename K, typename V> PtrMapEntry<K, V> * multi_map_find_next (PtrMap<K, V> *h, PtrMapEntry<K, V> *e);
template <typename K, typename V> isize multi_map_count (PtrMap<K, V> *h, K key);
template <typename K, typename V> void multi_map_get_all (PtrMap<K, V> *h, K key, V *items);
template <typename K, typename V> void multi_map_insert (PtrMap<K, V> *h, K key, V const &value);
template <typename K, typename V> void multi_map_remove (PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e);
template <typename K, typename V> void multi_map_remove_all(PtrMap<K, V> *h, K key);
#endif
template <typename K, typename V>
gb_inline void map_init(PtrMap<K, V> *h, gbAllocator a, isize capacity) {
capacity = next_pow2_isize(capacity);
slice_init(&h->hashes, a, capacity);
array_init(&h->entries, a, 0, capacity);
for (isize i = 0; i < capacity; i++) {
h->hashes.data[i] = MAP_SENTINEL;
}
}
template <typename K, typename V>
gb_inline void map_destroy(PtrMap<K, V> *h) {
slice_free(&h->hashes, h->entries.allocator);
array_free(&h->entries);
}
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;
array_add(&h->entries, e);
return cast(MapIndex)(h->entries.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;
}
u32 hash = ptr_map_hash_key(key);
fr.hash_index = cast(MapIndex)(hash & (h->hashes.count-1));
fr.entry_index = h->hashes.data[fr.hash_index];
while (fr.entry_index != MAP_SENTINEL) {
if (h->entries.data[fr.entry_index].key == key) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.data[fr.entry_index].next;
}
return fr;
}
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.data[fr.hash_index];
while (fr.entry_index != MAP_SENTINEL) {
if (&h->entries.data[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.data[fr.entry_index].next;
}
return fr;
}
template <typename K, typename V>
gb_internal b32 map__full(PtrMap<K, V> *h) {
return 0.75f * h->hashes.count <= h->entries.count;
}
template <typename K, typename V>
gb_inline void map_grow(PtrMap<K, V> *h) {
isize new_count = gb_max(h->hashes.count<<1, 16);
map_rehash(h, new_count);
}
template <typename K, typename V>
void map_reset_entries(PtrMap<K, V> *h) {
for (isize i = 0; i < h->hashes.count; i++) {
h->hashes.data[i] = MAP_SENTINEL;
}
for (isize i = 0; i < h->entries.count; i++) {
MapFindResult fr;
PtrMapEntry<K, V> *e = &h->entries.data[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;
}
}
}
template <typename K, typename V>
void map_reserve(PtrMap<K, V> *h, isize cap) {
array_reserve(&h->entries, cap);
if (h->entries.count*2 < h->hashes.count) {
return;
}
slice_resize(&h->hashes, h->entries.allocator, cap*2);
map_reset_entries(h);
}
template <typename K, typename V>
void map_rehash(PtrMap<K, V> *h, isize new_count) {
map_reserve(h, new_count);
}
template <typename K, typename V>
V *map_get(PtrMap<K, V> *h, K key) {
MapIndex index = map__find(h, key).entry_index;
if (index != MAP_SENTINEL) {
return &h->entries.data[index].value;
}
return nullptr;
}
template <typename K, typename V>
V &map_must_get(PtrMap<K, V> *h, K key) {
MapIndex index = map__find(h, key).entry_index;
GB_ASSERT(index != MAP_SENTINEL);
return h->entries.data[index].value;
}
template <typename K, typename V>
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.data[fr.entry_prev].next = index;
} else {
h->hashes.data[fr.hash_index] = index;
}
}
h->entries.data[index].value = value;
if (map__full(h)) {
map_grow(h);
}
}
template <typename K, typename V>
void map__erase(PtrMap<K, V> *h, MapFindResult const &fr) {
MapFindResult last;
if (fr.entry_prev == MAP_SENTINEL) {
h->hashes.data[fr.hash_index] = h->entries.data[fr.entry_index].next;
} else {
h->entries.data[fr.entry_prev].next = h->entries.data[fr.entry_index].next;
}
if (fr.entry_index == h->entries.count-1) {
array_pop(&h->entries);
return;
}
h->entries.data[fr.entry_index] = h->entries.data[h->entries.count-1];
array_pop(&h->entries);
last = map__find(h, h->entries.data[fr.entry_index].key);
if (last.entry_prev != MAP_SENTINEL) {
h->entries.data[last.entry_prev].next = fr.entry_index;
} else {
h->hashes.data[last.hash_index] = fr.entry_index;
}
}
template <typename K, typename V>
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);
}
}
template <typename K, typename V>
gb_inline void map_clear(PtrMap<K, V> *h) {
array_clear(&h->entries);
for (isize i = 0; i < h->hashes.count; i++) {
h->hashes.data[i] = MAP_SENTINEL;
}
}
#if PTR_MAP_ENABLE_MULTI_MAP
template <typename K, typename V>
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) {
return nullptr;
}
return &h->entries.data[i];
}
template <typename K, typename V>
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.data[i].key == e->key) {
return &h->entries.data[i];
}
i = h->entries.data[i].next;
}
return nullptr;
}
template <typename K, typename V>
isize multi_map_count(PtrMap<K, V> *h, K key) {
isize count = 0;
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
while (e != nullptr) {
count++;
e = multi_map_find_next(h, e);
}
return count;
}
template <typename K, typename V>
void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
isize i = 0;
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
while (e != nullptr) {
items[i++] = e->value;
e = multi_map_find_next(h, e);
}
}
template <typename K, typename V>
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.data[fr.hash_index] = i;
} else {
h->entries.data[fr.entry_prev].next = i;
}
h->entries.data[i].next = fr.entry_index;
h->entries.data[i].value = value;
// Grow if needed
if (map__full(h)) {
map_grow(h);
}
}
template <typename K, typename V>
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>
void multi_map_remove_all(PtrMap<K, V> *h, K key) {
while (map_get(h, key) != nullptr) {
map_remove(h, key);
}
}
#endif

View File

@@ -1,23 +1,12 @@
typedef u32 PtrSetIndex;
struct PtrSetFindResult {
PtrSetIndex hash_index;
PtrSetIndex entry_prev;
PtrSetIndex entry_index;
};
enum : PtrSetIndex { PTR_SET_SENTINEL = ~(PtrSetIndex)0 };
template <typename T>
struct PtrSetEntry {
T ptr;
PtrSetIndex next;
T ptr;
MapIndex next;
};
template <typename T>
struct PtrSet {
Array<PtrSetIndex> hashes;
Slice<MapIndex> hashes;
Array<PtrSetEntry<T>> entries;
};
@@ -30,44 +19,44 @@ template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
template <typename T> void ptr_set_clear (PtrSet<T> *s);
template <typename T> void ptr_set_grow (PtrSet<T> *s);
template <typename T> void ptr_set_rehash (PtrSet<T> *s, isize new_count);
template <typename T> void ptr_set_reserve(PtrSet<T> *h, isize cap);
template <typename T>
void ptr_set_init(PtrSet<T> *s, gbAllocator a, isize capacity) {
capacity = next_pow2_isize(gb_max(16, capacity));
array_init(&s->hashes, a, capacity);
slice_init(&s->hashes, a, capacity);
array_init(&s->entries, a, 0, capacity);
for (isize i = 0; i < capacity; i++) {
s->hashes.data[i] = PTR_SET_SENTINEL;
s->hashes.data[i] = MAP_SENTINEL;
}
}
template <typename T>
void ptr_set_destroy(PtrSet<T> *s) {
array_free(&s->hashes);
slice_free(&s->hashes, s->entries.allocator);
array_free(&s->entries);
}
template <typename T>
gb_internal PtrSetIndex ptr_set__add_entry(PtrSet<T> *s, T ptr) {
gb_internal MapIndex ptr_set__add_entry(PtrSet<T> *s, T ptr) {
PtrSetEntry<T> e = {};
e.ptr = ptr;
e.next = PTR_SET_SENTINEL;
e.next = MAP_SENTINEL;
array_add(&s->entries, e);
return cast(PtrSetIndex)(s->entries.count-1);
return cast(MapIndex)(s->entries.count-1);
}
template <typename T>
gb_internal PtrSetFindResult ptr_set__find(PtrSet<T> *s, T ptr) {
PtrSetFindResult fr = {PTR_SET_SENTINEL, PTR_SET_SENTINEL, PTR_SET_SENTINEL};
gb_internal MapFindResult ptr_set__find(PtrSet<T> *s, T ptr) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (s->hashes.count != 0) {
u64 hash = 0xcbf29ce484222325ull ^ cast(u64)cast(uintptr)ptr;
u64 n = cast(u64)s->hashes.count;
fr.hash_index = cast(PtrSetIndex)(hash & (n-1));
u32 hash = ptr_map_hash_key(ptr);
fr.hash_index = cast(MapIndex)(hash & (s->hashes.count-1));
fr.entry_index = s->hashes.data[fr.hash_index];
while (fr.entry_index != PTR_SET_SENTINEL) {
while (fr.entry_index != MAP_SENTINEL) {
if (s->entries.data[fr.entry_index].ptr == ptr) {
return fr;
}
@@ -78,6 +67,24 @@ gb_internal PtrSetFindResult ptr_set__find(PtrSet<T> *s, T ptr) {
return fr;
}
template <typename T>
gb_internal MapFindResult ptr_set__find_from_entry(PtrSet<T> *s, PtrSetEntry<T> *e) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (s->hashes.count != 0) {
u32 hash = ptr_map_hash_key(e->ptr);
fr.hash_index = cast(MapIndex)(hash & (s->hashes.count-1));
fr.entry_index = s->hashes.data[fr.hash_index];
while (fr.entry_index != MAP_SENTINEL) {
if (&s->entries.data[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries.data[fr.entry_index].next;
}
}
return fr;
}
template <typename T>
gb_internal bool ptr_set__full(PtrSet<T> *s) {
return 0.75f * s->hashes.count <= s->entries.count;
@@ -85,60 +92,62 @@ gb_internal bool ptr_set__full(PtrSet<T> *s) {
template <typename T>
gb_inline void ptr_set_grow(PtrSet<T> *s) {
isize new_count = s->hashes.count*2;
isize new_count = gb_max(s->hashes.count<<1, 16);
ptr_set_rehash(s, new_count);
}
template <typename T>
void ptr_set_rehash(PtrSet<T> *s, isize new_count) {
isize i, j;
PtrSet<T> ns = {};
ptr_set_init(&ns, s->hashes.allocator);
array_resize(&ns.hashes, new_count);
array_reserve(&ns.entries, s->entries.count);
for (i = 0; i < new_count; i++) {
ns.hashes.data[i] = PTR_SET_SENTINEL;
void ptr_set_reset_entries(PtrSet<T> *s) {
for (isize i = 0; i < s->hashes.count; i++) {
s->hashes.data[i] = MAP_SENTINEL;
}
for (i = 0; i < s->entries.count; i++) {
for (isize i = 0; i < s->entries.count; i++) {
MapFindResult fr;
PtrSetEntry<T> *e = &s->entries.data[i];
PtrSetFindResult fr;
if (ns.hashes.count == 0) {
ptr_set_grow(&ns);
}
fr = ptr_set__find(&ns, e->ptr);
j = ptr_set__add_entry(&ns, e->ptr);
if (fr.entry_prev == PTR_SET_SENTINEL) {
ns.hashes.data[fr.hash_index] = cast(PtrSetIndex)j;
e->next = MAP_SENTINEL;
fr = ptr_set__find_from_entry(s, e);
if (fr.entry_prev == MAP_SENTINEL) {
s->hashes[fr.hash_index] = cast(MapIndex)i;
} else {
ns.entries.data[fr.entry_prev].next = cast(PtrSetIndex)j;
}
ns.entries.data[j].next = fr.entry_index;
if (ptr_set__full(&ns)) {
ptr_set_grow(&ns);
s->entries[fr.entry_prev].next = cast(MapIndex)i;
}
}
ptr_set_destroy(s);
*s = ns;
}
template <typename T>
void ptr_set_reserve(PtrSet<T> *s, isize cap) {
array_reserve(&s->entries, cap);
if (s->entries.count*2 < s->hashes.count) {
return;
}
slice_resize(&s->hashes, s->entries.allocator, cap*2);
ptr_set_reset_entries(s);
}
template <typename T>
void ptr_set_rehash(PtrSet<T> *s, isize new_count) {
ptr_set_reserve(s, new_count);
}
template <typename T>
gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
isize index = ptr_set__find(s, ptr).entry_index;
return index != PTR_SET_SENTINEL;
return index != MAP_SENTINEL;
}
// Returns true if it already exists
template <typename T>
T ptr_set_add(PtrSet<T> *s, T ptr) {
PtrSetIndex index;
PtrSetFindResult fr;
MapIndex index;
MapFindResult fr;
if (s->hashes.count == 0) {
ptr_set_grow(s);
}
fr = ptr_set__find(s, ptr);
if (fr.entry_index == PTR_SET_SENTINEL) {
if (fr.entry_index == MAP_SENTINEL) {
index = ptr_set__add_entry(s, ptr);
if (fr.entry_prev != PTR_SET_SENTINEL) {
if (fr.entry_prev != MAP_SENTINEL) {
s->entries.data[fr.entry_prev].next = index;
} else {
s->hashes.data[fr.hash_index] = index;
@@ -153,17 +162,17 @@ T ptr_set_add(PtrSet<T> *s, T ptr) {
template <typename T>
bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it previously existsed
bool exists = false;
PtrSetIndex index;
PtrSetFindResult fr;
MapIndex index;
MapFindResult fr;
if (s->hashes.count == 0) {
ptr_set_grow(s);
}
fr = ptr_set__find(s, ptr);
if (fr.entry_index != PTR_SET_SENTINEL) {
if (fr.entry_index != MAP_SENTINEL) {
exists = true;
} else {
index = ptr_set__add_entry(s, ptr);
if (fr.entry_prev != PTR_SET_SENTINEL) {
if (fr.entry_prev != MAP_SENTINEL) {
s->entries.data[fr.entry_prev].next = index;
} else {
s->hashes.data[fr.hash_index] = index;
@@ -178,9 +187,9 @@ bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it previously exis
template <typename T>
void ptr_set__erase(PtrSet<T> *s, PtrSetFindResult fr) {
PtrSetFindResult last;
if (fr.entry_prev == PTR_SET_SENTINEL) {
void ptr_set__erase(PtrSet<T> *s, MapFindResult fr) {
MapFindResult last;
if (fr.entry_prev == MAP_SENTINEL) {
s->hashes.data[fr.hash_index] = s->entries.data[fr.entry_index].next;
} else {
s->entries.data[fr.entry_prev].next = s->entries.data[fr.entry_index].next;
@@ -191,7 +200,7 @@ void ptr_set__erase(PtrSet<T> *s, PtrSetFindResult fr) {
}
s->entries.data[fr.entry_index] = s->entries.data[s->entries.count-1];
last = ptr_set__find(s, s->entries.data[fr.entry_index].ptr);
if (last.entry_prev != PTR_SET_SENTINEL) {
if (last.entry_prev != MAP_SENTINEL) {
s->entries.data[last.entry_prev].next = fr.entry_index;
} else {
s->hashes.data[last.hash_index] = fr.entry_index;
@@ -200,14 +209,16 @@ void ptr_set__erase(PtrSet<T> *s, PtrSetFindResult fr) {
template <typename T>
void ptr_set_remove(PtrSet<T> *s, T ptr) {
PtrSetFindResult fr = ptr_set__find(s, ptr);
if (fr.entry_index != PTR_SET_SENTINEL) {
MapFindResult fr = ptr_set__find(s, ptr);
if (fr.entry_index != MAP_SENTINEL) {
ptr_set__erase(s, fr);
}
}
template <typename T>
gb_inline void ptr_set_clear(PtrSet<T> *s) {
array_clear(&s->hashes);
array_clear(&s->entries);
for (isize i = 0; i < s->hashes.count; i++) {
s->hashes.data[i] = MAP_SENTINEL;
}
}

View File

@@ -1,22 +1,11 @@
// 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;
u32 hash;
String string;
};
u64 string_hashing_proc(void const *data, isize len) {
return fnv64a(data, len);
}
gb_inline StringHashKey string_hash_string(String const &s) {
StringHashKey hash_key = {};
hash_key.hash = string_hashing_proc(s.text, s.len);
hash_key.hash = fnv32a(s.text, s.len);
hash_key.string = s;
return hash_key;
}
@@ -35,13 +24,13 @@ bool operator!=(StringHashKey const &a, StringHashKey const &b) { return !string
template <typename T>
struct StringMapEntry {
StringHashKey key;
isize next;
MapIndex next;
T value;
};
template <typename T>
struct StringMap {
Slice<isize> hashes;
Slice<MapIndex> hashes;
Array<StringMapEntry<T> > entries;
};
@@ -65,6 +54,7 @@ template <typename T> void string_map_remove (StringMap<T> *h, StringH
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> void string_map_reserve (StringMap<T> *h, isize cap);
template <typename T>
gb_inline void string_map_init(StringMap<T> *h, gbAllocator a, isize capacity) {
@@ -72,7 +62,7 @@ gb_inline void string_map_init(StringMap<T> *h, gbAllocator a, isize capacity) {
slice_init(&h->hashes, a, capacity);
array_init(&h->entries, a, 0, capacity);
for (isize i = 0; i < capacity; i++) {
h->hashes.data[i] = -1;
h->hashes.data[i] = MAP_SENTINEL;
}
}
@@ -83,21 +73,21 @@ gb_inline void string_map_destroy(StringMap<T> *h) {
}
template <typename T>
gb_internal isize string_map__add_entry(StringMap<T> *h, StringHashKey const &key) {
gb_internal MapIndex string_map__add_entry(StringMap<T> *h, StringHashKey const &key) {
StringMapEntry<T> e = {};
e.key = key;
e.next = -1;
e.next = MAP_SENTINEL;
array_add(&h->entries, e);
return h->entries.count-1;
return cast(MapIndex)(h->entries.count-1);
}
template <typename T>
gb_internal StringMapFindResult string_map__find(StringMap<T> *h, StringHashKey const &key) {
StringMapFindResult fr = {-1, -1, -1};
gb_internal MapFindResult string_map__find(StringMap<T> *h, StringHashKey const &key) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (h->hashes.count != 0) {
fr.hash_index = key.hash & (h->hashes.count-1);
fr.hash_index = cast(MapIndex)(key.hash & (h->hashes.count-1));
fr.entry_index = h->hashes.data[fr.hash_index];
while (fr.entry_index >= 0) {
while (fr.entry_index != MAP_SENTINEL) {
if (string_hash_key_equal(h->entries.data[fr.entry_index].key, key)) {
return fr;
}
@@ -109,12 +99,12 @@ gb_internal StringMapFindResult string_map__find(StringMap<T> *h, StringHashKey
}
template <typename T>
gb_internal StringMapFindResult string_map__find_from_entry(StringMap<T> *h, StringMapEntry<T> *e) {
StringMapFindResult fr = {-1, -1, -1};
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 = e->key.hash & (h->hashes.count-1);
fr.hash_index = cast(MapIndex)(e->key.hash & (h->hashes.count-1));
fr.entry_index = h->hashes.data[fr.hash_index];
while (fr.entry_index >= 0) {
while (fr.entry_index != MAP_SENTINEL) {
if (&h->entries.data[fr.entry_index] == e) {
return fr;
}
@@ -136,45 +126,45 @@ gb_inline void string_map_grow(StringMap<T> *h) {
string_map_rehash(h, new_count);
}
template <typename T>
void string_map_reset_entries(StringMap<T> *h) {
for (isize i = 0; i < h->hashes.count; i++) {
h->hashes.data[i] = MAP_SENTINEL;
}
for (isize i = 0; i < h->entries.count; i++) {
MapFindResult fr;
StringMapEntry<T> *e = &h->entries.data[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>
void string_map_reserve(StringMap<T> *h, isize cap) {
array_reserve(&h->entries, cap);
if (h->entries.count*2 < h->hashes.count) {
return;
}
slice_resize(&h->hashes, h->entries.allocator, cap*2);
string_map_reset_entries(h);
}
template <typename T>
void string_map_rehash(StringMap<T> *h, isize new_count) {
isize i, j;
StringMap<T> nh = {};
new_count = next_pow2_isize(new_count);
nh.hashes = h->hashes;
nh.entries.allocator = h->entries.allocator;
slice_resize(&nh.hashes, h->entries.allocator, new_count);
for (i = 0; i < new_count; i++) {
nh.hashes.data[i] = -1;
}
array_reserve(&nh.entries, ARRAY_GROW_FORMULA(h->entries.count));
for (i = 0; i < h->entries.count; i++) {
StringMapEntry<T> *e = &h->entries.data[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.data[fr.hash_index] = j;
} else {
nh.entries.data[fr.entry_prev].next = j;
}
nh.entries.data[j].next = fr.entry_index;
nh.entries.data[j].value = e->value;
if (string_map__full(&nh)) {
string_map_grow(&nh);
}
}
array_free(&h->entries);
*h = nh;
string_map_reserve(h, new_count);
}
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) {
if (index != MAP_SENTINEL) {
return &h->entries.data[index].value;
}
return nullptr;
@@ -193,7 +183,7 @@ gb_inline T *string_map_get(StringMap<T> *h, char const *key) {
template <typename T>
T &string_map_must_get(StringMap<T> *h, StringHashKey const &key) {
isize index = string_map__find(h, key).entry_index;
GB_ASSERT(index >= 0);
GB_ASSERT(index != MAP_SENTINEL);
return h->entries.data[index].value;
}
@@ -209,17 +199,17 @@ gb_inline T &string_map_must_get(StringMap<T> *h, char const *key) {
template <typename T>
void string_map_set(StringMap<T> *h, StringHashKey const &key, T const &value) {
isize index;
StringMapFindResult fr;
MapIndex index;
MapFindResult fr;
if (h->hashes.count == 0) {
string_map_grow(h);
}
fr = string_map__find(h, key);
if (fr.entry_index >= 0) {
if (fr.entry_index != MAP_SENTINEL) {
index = fr.entry_index;
} else {
index = string_map__add_entry(h, key);
if (fr.entry_prev >= 0) {
if (fr.entry_prev != MAP_SENTINEL) {
h->entries.data[fr.entry_prev].next = index;
} else {
h->hashes.data[fr.hash_index] = index;
@@ -244,9 +234,9 @@ gb_inline void string_map_set(StringMap<T> *h, char const *key, T const &value)
template <typename T>
void string_map__erase(StringMap<T> *h, StringMapFindResult const &fr) {
StringMapFindResult last;
if (fr.entry_prev < 0) {
void string_map__erase(StringMap<T> *h, MapFindResult const &fr) {
MapFindResult last;
if (fr.entry_prev == MAP_SENTINEL) {
h->hashes.data[fr.hash_index] = h->entries.data[fr.entry_index].next;
} else {
h->entries.data[fr.entry_prev].next = h->entries.data[fr.entry_index].next;
@@ -257,7 +247,7 @@ void string_map__erase(StringMap<T> *h, StringMapFindResult const &fr) {
}
h->entries.data[fr.entry_index] = h->entries.data[h->entries.count-1];
last = string_map__find(h, h->entries.data[fr.entry_index].key);
if (last.entry_prev >= 0) {
if (last.entry_prev != MAP_SENTINEL) {
h->entries.data[last.entry_prev].next = fr.entry_index;
} else {
h->hashes.data[last.hash_index] = fr.entry_index;
@@ -266,8 +256,8 @@ void string_map__erase(StringMap<T> *h, StringMapFindResult const &fr) {
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) {
MapFindResult fr = string_map__find(h, key);
if (fr.entry_index != MAP_SENTINEL) {
string_map__erase(h, fr);
}
}
@@ -276,7 +266,7 @@ template <typename T>
gb_inline void string_map_clear(StringMap<T> *h) {
array_clear(&h->entries);
for (isize i = 0; i < h->hashes.count; i++) {
h->hashes.data[i] = -1;
h->hashes.data[i] = MAP_SENTINEL;
}
}

View File

@@ -1,17 +1,11 @@
struct StringSetFindResult {
isize hash_index;
isize entry_prev;
isize entry_index;
};
struct StringSetEntry {
u64 hash;
isize next;
String value;
u32 hash;
MapIndex next;
String value;
};
struct StringSet {
Array<isize> hashes;
Slice<MapIndex> hashes;
Array<StringSetEntry> entries;
};
@@ -27,31 +21,35 @@ void string_set_rehash (StringSet *s, isize new_count);
gb_inline void string_set_init(StringSet *s, gbAllocator a, isize capacity) {
array_init(&s->hashes, a);
array_init(&s->entries, a);
capacity = next_pow2_isize(gb_max(16, capacity));
slice_init(&s->hashes, a, capacity);
array_init(&s->entries, a, 0, capacity);
for (isize i = 0; i < capacity; i++) {
s->hashes.data[i] = MAP_SENTINEL;
}
}
gb_inline void string_set_destroy(StringSet *s) {
slice_free(&s->hashes, s->entries.allocator);
array_free(&s->entries);
array_free(&s->hashes);
}
gb_internal isize string_set__add_entry(StringSet *s, StringHashKey const &key) {
gb_internal MapIndex string_set__add_entry(StringSet *s, StringHashKey const &key) {
StringSetEntry e = {};
e.hash = key.hash;
e.next = -1;
e.next = MAP_SENTINEL;
e.value = key.string;
array_add(&s->entries, e);
return s->entries.count-1;
return cast(MapIndex)(s->entries.count-1);
}
gb_internal StringSetFindResult string_set__find(StringSet *s, StringHashKey const &key) {
StringSetFindResult fr = {-1, -1, -1};
gb_internal MapFindResult string_set__find(StringSet *s, StringHashKey const &key) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (s->hashes.count > 0) {
// fr.hash_index = u128_to_i64(key.key % u128_from_i64(s->hashes.count));
fr.hash_index = key.hash % s->hashes.count;
fr.hash_index = cast(MapIndex)(((u64)key.hash) % s->hashes.count);
fr.entry_index = s->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
while (fr.entry_index != MAP_SENTINEL) {
auto const &entry = s->entries[fr.entry_index];
if (entry.hash == key.hash && entry.value == key.string) {
return fr;
@@ -62,68 +60,83 @@ gb_internal StringSetFindResult string_set__find(StringSet *s, StringHashKey con
}
return fr;
}
gb_internal MapFindResult string_set__find_from_entry(StringSet *s, StringSetEntry *e) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (s->hashes.count > 0) {
fr.hash_index = cast(MapIndex)(e->hash % s->hashes.count);
fr.entry_index = s->hashes[fr.hash_index];
while (fr.entry_index != MAP_SENTINEL) {
if (&s->entries[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries[fr.entry_index].next;
}
}
return fr;
}
gb_internal b32 string_set__full(StringSet *s) {
return 0.75f * s->hashes.count <= s->entries.count;
}
gb_inline void string_set_grow(StringSet *s) {
isize new_count = ARRAY_GROW_FORMULA(s->entries.count);
isize new_count = gb_max(s->hashes.count<<1, 16);
string_set_rehash(s, new_count);
}
void string_set_rehash(StringSet *s, isize new_count) {
isize i, j;
StringSet ns = {};
string_set_init(&ns, s->hashes.allocator);
array_resize(&ns.hashes, new_count);
array_reserve(&ns.entries, s->entries.count);
for (i = 0; i < new_count; i++) {
ns.hashes[i] = -1;
void string_set_reset_entries(StringSet *s) {
for (isize i = 0; i < s->hashes.count; i++) {
s->hashes.data[i] = MAP_SENTINEL;
}
for (i = 0; i < s->entries.count; i++) {
StringSetEntry *e = &s->entries[i];
StringSetFindResult fr;
if (ns.hashes.count == 0) {
string_set_grow(&ns);
}
StringHashKey key = {e->hash, e->value};
fr = string_set__find(&ns, key);
j = string_set__add_entry(&ns, key);
if (fr.entry_prev < 0) {
ns.hashes[fr.hash_index] = j;
for (isize i = 0; i < s->entries.count; i++) {
MapFindResult fr;
StringSetEntry *e = &s->entries.data[i];
e->next = MAP_SENTINEL;
fr = string_set__find_from_entry(s, e);
if (fr.entry_prev == MAP_SENTINEL) {
s->hashes[fr.hash_index] = cast(MapIndex)i;
} else {
ns.entries[fr.entry_prev].next = j;
}
ns.entries[j].next = fr.entry_index;
ns.entries[j].value = e->value;
if (string_set__full(&ns)) {
string_set_grow(&ns);
s->entries[fr.entry_prev].next = cast(MapIndex)i;
}
}
string_set_destroy(s);
*s = ns;
}
void string_set_reserve(StringSet *s, isize cap) {
array_reserve(&s->entries, cap);
if (s->entries.count*2 < s->hashes.count) {
return;
}
slice_resize(&s->hashes, s->entries.allocator, cap*2);
string_set_reset_entries(s);
}
void string_set_rehash(StringSet *s, isize new_count) {
string_set_reserve(s, new_count);
}
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;
return index >= 0;
return index != MAP_SENTINEL;
}
void string_set_add(StringSet *s, String const &str) {
isize index;
StringSetFindResult fr;
MapIndex index;
MapFindResult fr;
StringHashKey key = string_hash_string(str);
if (s->hashes.count == 0) {
string_set_grow(s);
}
fr = string_set__find(s, key);
if (fr.entry_index >= 0) {
if (fr.entry_index != MAP_SENTINEL) {
index = fr.entry_index;
} else {
index = string_set__add_entry(s, key);
if (fr.entry_prev >= 0) {
if (fr.entry_prev != MAP_SENTINEL) {
s->entries[fr.entry_prev].next = index;
} else {
s->hashes[fr.hash_index] = index;
@@ -137,9 +150,9 @@ void string_set_add(StringSet *s, String const &str) {
}
void string_set__erase(StringSet *s, StringSetFindResult fr) {
StringSetFindResult last;
if (fr.entry_prev < 0) {
void string_set__erase(StringSet *s, MapFindResult fr) {
MapFindResult last;
if (fr.entry_prev == MAP_SENTINEL) {
s->hashes[fr.hash_index] = s->entries[fr.entry_index].next;
} else {
s->entries[fr.entry_prev].next = s->entries[fr.entry_index].next;
@@ -152,7 +165,7 @@ void string_set__erase(StringSet *s, StringSetFindResult fr) {
*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 != MAP_SENTINEL) {
s->entries[last.entry_prev].next = fr.entry_index;
} else {
s->hashes[last.hash_index] = fr.entry_index;
@@ -161,13 +174,15 @@ void string_set__erase(StringSet *s, StringSetFindResult fr) {
void string_set_remove(StringSet *s, String const &str) {
StringHashKey key = string_hash_string(str);
StringSetFindResult fr = string_set__find(s, key);
if (fr.entry_index >= 0) {
MapFindResult fr = string_set__find(s, key);
if (fr.entry_index != MAP_SENTINEL) {
string_set__erase(s, fr);
}
}
gb_inline void string_set_clear(StringSet *s) {
array_clear(&s->hashes);
array_clear(&s->entries);
for_array(i, s->hashes) {
s->hashes.data[i] = MAP_SENTINEL;
}
}