refactor InternPool KeyAdapter
This commit is contained in:
parent
04d281340c
commit
1456bfa1c6
@ -705,7 +705,7 @@ pub fn interpret(
|
||||
const value_namespace = interpreter.ip.indexToKey(value.val).getNamespace();
|
||||
if (value_namespace == .none) return error.InvalidBuiltin;
|
||||
|
||||
const name = interpreter.ip.indexToKey(field_name.val).bytes.data; // TODO add checks
|
||||
const name = interpreter.ip.indexToKey(field_name.val).bytes; // TODO add checks
|
||||
|
||||
const decls = interpreter.namespaces.items(.decls)[@enumToInt(value_namespace)];
|
||||
const has_decl = decls.contains(name);
|
||||
@ -764,7 +764,7 @@ pub fn interpret(
|
||||
.interpreter = interpreter,
|
||||
.node_idx = node_idx,
|
||||
.ty = string_literal_type,
|
||||
.val = try interpreter.ip.get(interpreter.allocator, IPKey{ .bytes = .{ .data = str } }), // TODO
|
||||
.val = try interpreter.ip.get(interpreter.allocator, IPKey{ .bytes = str }), // TODO
|
||||
};
|
||||
|
||||
// TODO: Add type casting, sentinel
|
||||
|
@ -10,26 +10,12 @@ const builtin = @import("builtin");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const KeyAdapter = struct {
|
||||
intern_pool: *const InternPool,
|
||||
|
||||
pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool {
|
||||
_ = b_void;
|
||||
return ctx.intern_pool.indexToKey(@intToEnum(Index, b_map_index)).eql(a);
|
||||
}
|
||||
|
||||
pub fn hash(ctx: @This(), a: Key) u32 {
|
||||
_ = ctx;
|
||||
return a.hash();
|
||||
}
|
||||
};
|
||||
|
||||
pub const Int = struct {
|
||||
pub const Int = packed struct {
|
||||
signedness: std.builtin.Signedness,
|
||||
bits: u16,
|
||||
};
|
||||
|
||||
pub const Pointer = struct {
|
||||
pub const Pointer = packed struct {
|
||||
elem_type: Index,
|
||||
sentinel: Index = .none,
|
||||
alignment: u16 = 0,
|
||||
@ -40,7 +26,7 @@ pub const Pointer = struct {
|
||||
address_space: std.builtin.AddressSpace = .generic,
|
||||
};
|
||||
|
||||
pub const Array = struct {
|
||||
pub const Array = packed struct {
|
||||
// TODO support big int
|
||||
len: u32,
|
||||
child: Index,
|
||||
@ -62,19 +48,15 @@ pub const Struct = struct {
|
||||
};
|
||||
};
|
||||
|
||||
pub const Optional = struct {
|
||||
pub const Optional = packed struct {
|
||||
payload_type: Index,
|
||||
};
|
||||
|
||||
pub const ErrorUnion = struct {
|
||||
pub const ErrorUnion = packed struct {
|
||||
error_set_type: Index,
|
||||
payload_type: Index,
|
||||
};
|
||||
|
||||
// pub const Error = struct {
|
||||
// name: []const u8,
|
||||
// };
|
||||
|
||||
pub const ErrorSet = struct {
|
||||
/// must be sorted
|
||||
names: []const []const u8,
|
||||
@ -104,11 +86,11 @@ pub const Fn = struct {
|
||||
return_type: Index,
|
||||
args: []const Param,
|
||||
|
||||
pub const Param = struct {
|
||||
pub const Param = packed struct {
|
||||
arg_type: Index,
|
||||
is_comptime: bool = false,
|
||||
is_generic: bool = false,
|
||||
is_noalias: bool = false,
|
||||
arg_type: Index,
|
||||
};
|
||||
};
|
||||
|
||||
@ -127,31 +109,27 @@ pub const Union = struct {
|
||||
|
||||
pub const Tuple = struct {
|
||||
types: []const Index,
|
||||
/// unreachable_value elements are used to indicate runtime-known.
|
||||
/// Index.none elements are used to indicate runtime-known.
|
||||
values: []const Index,
|
||||
};
|
||||
|
||||
pub const Vector = struct {
|
||||
pub const Vector = packed struct {
|
||||
// TODO support big int
|
||||
len: u32,
|
||||
child: Index,
|
||||
};
|
||||
|
||||
pub const AnyFrame = struct {
|
||||
pub const AnyFrame = packed struct {
|
||||
child: Index,
|
||||
};
|
||||
|
||||
pub const BigInt = std.math.big.int.Const;
|
||||
|
||||
pub const Bytes = struct {
|
||||
data: []const u8,
|
||||
};
|
||||
pub const Bytes = []const u8;
|
||||
|
||||
pub const Aggregate = struct {
|
||||
data: []const Index,
|
||||
};
|
||||
pub const Aggregate = []const Index;
|
||||
|
||||
pub const UnionValue = struct {
|
||||
pub const UnionValue = packed struct {
|
||||
tag: Index,
|
||||
val: Index,
|
||||
};
|
||||
@ -165,14 +143,13 @@ pub const Key = union(enum) {
|
||||
struct_type: Struct,
|
||||
optional_type: Optional,
|
||||
error_union_type: ErrorUnion,
|
||||
// error_type: Error,
|
||||
error_set_type: ErrorSet,
|
||||
enum_type: Enum,
|
||||
function_type: Fn,
|
||||
union_type: Union,
|
||||
tuple_type: Tuple,
|
||||
vector_type: Vector,
|
||||
anyframe_t_type: AnyFrame,
|
||||
anyframe_type: AnyFrame,
|
||||
|
||||
int_u64_value: u64,
|
||||
int_i64_value: i64,
|
||||
@ -182,10 +159,8 @@ pub const Key = union(enum) {
|
||||
float_64_value: f64,
|
||||
float_80_value: f80,
|
||||
float_128_value: f128,
|
||||
// type_value: Index,
|
||||
|
||||
bytes: Bytes,
|
||||
// one_pointer: Index,
|
||||
aggregate: Aggregate,
|
||||
union_value: UnionValue,
|
||||
|
||||
@ -193,98 +168,10 @@ pub const Key = union(enum) {
|
||||
// error
|
||||
// error union
|
||||
|
||||
pub fn hash(key: Key) u32 {
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
std.hash.autoHash(&hasher, std.meta.activeTag(key));
|
||||
switch (key) {
|
||||
.float_16_value => |f| std.hash.autoHash(&hasher, @bitCast(u16, f)),
|
||||
.float_32_value => |f| std.hash.autoHash(&hasher, @bitCast(u32, f)),
|
||||
.float_64_value => |f| std.hash.autoHash(&hasher, @bitCast(u64, f)),
|
||||
.float_80_value => |f| std.hash.autoHash(&hasher, @bitCast(u80, f)),
|
||||
.float_128_value => |f| std.hash.autoHash(&hasher, @bitCast(u128, f)),
|
||||
inline else => |info| std.hash.autoHashStrat(&hasher, info, .Deep), // TODO sad stage1 noises :(
|
||||
}
|
||||
return @truncate(u32, hasher.final());
|
||||
}
|
||||
|
||||
pub fn eql(a: Key, b: Key) bool {
|
||||
const KeyTag = std.meta.Tag(Key);
|
||||
const a_tag: KeyTag = a;
|
||||
const b_tag: KeyTag = b;
|
||||
if (a_tag != b_tag) return false;
|
||||
return switch (a) {
|
||||
.struct_type => |struct_info| {
|
||||
if (struct_info.layout != b.struct_type.layout) return false;
|
||||
if (struct_info.fields.len != b.struct_type.fields.len) return false;
|
||||
for (struct_info.fields) |field, i| {
|
||||
if (!std.meta.eql(field, b.struct_type.fields[i])) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// .error_type => |error_info| std.mem.eql(u8, error_info.name, b.error_type.name),
|
||||
.error_set_type => |error_set_info| {
|
||||
if (error_set_info.names.len != b.error_set_type.names.len) return false;
|
||||
for (error_set_info.names) |a_name, i| {
|
||||
const b_name = b.error_set_type.names[i];
|
||||
if (!std.mem.eql(u8, a_name, b_name)) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
.enum_type => |enum_info| {
|
||||
if (enum_info.tag_type != b.enum_type.tag_type) return false;
|
||||
if (enum_info.tag_type_infered != b.enum_type.tag_type_infered) return false;
|
||||
if (enum_info.fields.len != b.enum_type.fields.len) return false;
|
||||
@panic("TODO: implement field equality check");
|
||||
},
|
||||
.function_type => |function_info| {
|
||||
if (function_info.calling_convention != b.function_type.calling_convention) return false;
|
||||
if (function_info.alignment != b.function_type.alignment) return false;
|
||||
if (function_info.is_generic != b.function_type.is_generic) return false;
|
||||
if (function_info.is_var_args != b.function_type.is_var_args) return false;
|
||||
if (function_info.return_type != b.function_type.return_type) return false;
|
||||
if (function_info.args.len != b.function_type.args.len) return false;
|
||||
|
||||
for (function_info.args) |arg, i| {
|
||||
if (!std.meta.eql(arg, b.function_type.args[i])) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
.union_type => |union_info| {
|
||||
if (union_info.tag_type != b.union_type.tag_type) return false;
|
||||
if (union_info.layout != b.union_type.layout) return false;
|
||||
if (union_info.fields.len != b.union_type.fields.len) return false;
|
||||
for (union_info.fields) |field, i| {
|
||||
if (!std.meta.eql(field, b.union_type.fields[i])) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
.tuple_type => |tuple_info| {
|
||||
std.debug.assert(tuple_info.types.len == tuple_info.values.len);
|
||||
std.debug.assert(b.tuple_type.types.len == b.tuple_type.values.len);
|
||||
if (tuple_info.types.len != b.tuple_type.types.len) return false;
|
||||
for (tuple_info.types) |ty, i| {
|
||||
if (ty != b.tuple_type.types[i]) return false;
|
||||
}
|
||||
for (tuple_info.values) |val, i| {
|
||||
if (val != b.tuple_type.values[i]) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
.bytes => |bytes| std.mem.eql(u8, bytes.data, b.bytes.data),
|
||||
.aggregate => |aggregate| {
|
||||
if (aggregate.data.len != b.aggregate.data.len) return false;
|
||||
for (aggregate.data) |ty, i| {
|
||||
if (ty != b.aggregate.data[i]) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
else => std.meta.eql(a, b),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn tag(key: Key) Tag {
|
||||
return switch (key) {
|
||||
.simple => .simple,
|
||||
|
||||
.int_type => |int_info| switch (int_info.signedness) {
|
||||
.signed => .type_int_signed,
|
||||
.unsigned => .type_int_unsigned,
|
||||
@ -294,14 +181,13 @@ pub const Key = union(enum) {
|
||||
.struct_type => .type_struct,
|
||||
.optional_type => .type_optional,
|
||||
.error_union_type => .type_error_union,
|
||||
// .error_type => .type_error,
|
||||
.error_set_type => .type_error_set,
|
||||
.enum_type => .type_enum,
|
||||
.function_type => .type_function,
|
||||
.union_type => .type_union,
|
||||
.tuple_type => .type_tuple,
|
||||
.vector_type => .type_vector,
|
||||
.anyframe_t_type => .type_anyframe_t,
|
||||
.anyframe_type => .type_anyframe,
|
||||
|
||||
.int_u64_value => |int| if (int <= std.math.maxInt(u32)) .int_u32 else .int_u64,
|
||||
.int_i64_value => |int| if (std.math.maxInt(i32) <= int and int <= std.math.maxInt(i32)) .int_i32 else .int_i64,
|
||||
@ -311,10 +197,8 @@ pub const Key = union(enum) {
|
||||
.float_64_value => .float_f64,
|
||||
.float_80_value => .float_f80,
|
||||
.float_128_value => .float_f128,
|
||||
// .type_value => .type,
|
||||
|
||||
.bytes => .bytes,
|
||||
// .one_pointer => .one_pointer,
|
||||
.aggregate => .aggregate,
|
||||
.union_value => .union_value,
|
||||
};
|
||||
@ -378,7 +262,7 @@ pub const Key = union(enum) {
|
||||
.union_type => .Union,
|
||||
.tuple_type => .Struct, // TODO this correct?
|
||||
.vector_type => .Vector,
|
||||
.anyframe_t_type => .AnyFrame,
|
||||
.anyframe_type => .AnyFrame,
|
||||
|
||||
.int_u64_value,
|
||||
.int_i64_value,
|
||||
@ -500,7 +384,7 @@ pub const Key = union(enum) {
|
||||
.array_type => |array_info| array_info.child,
|
||||
.optional_type => |optional_info| optional_info.payload_type,
|
||||
.vector_type => |vector_info| vector_info.child,
|
||||
.anyframe_t_type => |anyframe_t_info| anyframe_t_info.child,
|
||||
.anyframe_type => |anyframe_info| anyframe_info.child,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
@ -717,7 +601,7 @@ pub const Key = union(enum) {
|
||||
vector_info.child.fmtType(ip),
|
||||
});
|
||||
},
|
||||
.anyframe_t_type => |anyframe_info| {
|
||||
.anyframe_type => |anyframe_info| {
|
||||
try writer.writeAll("anyframe->");
|
||||
try printType(anyframe_info.child, ip, writer);
|
||||
},
|
||||
@ -813,7 +697,7 @@ pub const Key = union(enum) {
|
||||
.union_type,
|
||||
.tuple_type,
|
||||
.vector_type,
|
||||
.anyframe_t_type,
|
||||
.anyframe_type,
|
||||
=> unreachable,
|
||||
|
||||
.int_u64_value => |int| try std.fmt.formatIntValue(int, "", .{}, writer),
|
||||
@ -826,19 +710,19 @@ pub const Key = union(enum) {
|
||||
.float_128_value => |float| try writer.print("{d}", .{@floatCast(f64, float)}),
|
||||
|
||||
// .type_value => |tty| tty.fmtType(ip),
|
||||
.bytes => |data| try writer.print("\"{}\"", .{std.zig.fmtEscapes(data.data)}),
|
||||
.bytes => |bytes| try writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)}),
|
||||
// .one_pointer => unreachable,
|
||||
.aggregate => |aggregate| {
|
||||
const struct_info = ip.indexToKey(ty).struct_type;
|
||||
std.debug.assert(aggregate.data.len == struct_info.fields.len);
|
||||
std.debug.assert(aggregate.len == struct_info.fields.len);
|
||||
|
||||
try writer.writeAll(".{");
|
||||
var i: u32 = 0;
|
||||
while (i < aggregate.data.len) : (i += 1) {
|
||||
while (i < aggregate.len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
|
||||
try writer.print(".{s} = ", .{struct_info.fields[i].name});
|
||||
try printValue(aggregate.data[i], struct_info.fields[i].ty, ip, writer);
|
||||
try printValue(aggregate[i], struct_info.fields[i].ty, ip, writer);
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
},
|
||||
@ -917,9 +801,6 @@ pub const Tag = enum(u8) {
|
||||
/// An error union type.
|
||||
/// data is payload to ErrorUnion.
|
||||
type_error_union,
|
||||
/// An error type.
|
||||
/// data is payload to Error.
|
||||
type_error,
|
||||
/// An error set type.
|
||||
/// data is payload to ErrorSet.
|
||||
type_error_set,
|
||||
@ -940,7 +821,7 @@ pub const Tag = enum(u8) {
|
||||
type_vector,
|
||||
/// An anyframe->T type.
|
||||
/// data is index to type
|
||||
type_anyframe_t,
|
||||
type_anyframe,
|
||||
|
||||
/// An unsigned integer value that can be represented by u32.
|
||||
/// data is integer value
|
||||
@ -975,16 +856,10 @@ pub const Tag = enum(u8) {
|
||||
/// A float value that can be represented by f128.
|
||||
/// data is payload to f128.
|
||||
float_f128,
|
||||
// /// A type value.
|
||||
// /// data is Index.
|
||||
// type,
|
||||
|
||||
/// A byte sequence value.
|
||||
/// data is payload to data begin and length.
|
||||
bytes,
|
||||
// /// A single pointer value.
|
||||
// /// data is index to value.
|
||||
// one_pointer,
|
||||
/// A aggregate (struct) value.
|
||||
/// data is index to Aggregate.
|
||||
aggregate,
|
||||
@ -1039,12 +914,12 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
|
||||
|
||||
// TODO deinit fields
|
||||
}
|
||||
|
||||
pub fn indexToKey(ip: InternPool, index: Index) Key {
|
||||
const item = ip.items.get(@enumToInt(index));
|
||||
const data = item.data;
|
||||
return switch (item.tag) {
|
||||
.simple => .{ .simple = @intToEnum(Simple, data) },
|
||||
|
||||
.type_int_signed => .{ .int_type = .{
|
||||
.signedness = .signed,
|
||||
.bits = @intCast(u16, data),
|
||||
@ -1057,9 +932,8 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
||||
.type_array => .{ .array_type = ip.extraData(Array, data) },
|
||||
.type_struct => .{ .struct_type = ip.extraData(Struct, data) },
|
||||
.type_optional => .{ .optional_type = .{ .payload_type = @intToEnum(Index, data) } },
|
||||
.type_anyframe_t => .{ .anyframe_t_type = .{ .child = @intToEnum(Index, data) } },
|
||||
.type_anyframe => .{ .anyframe_type = .{ .child = @intToEnum(Index, data) } },
|
||||
.type_error_union => .{ .error_union_type = ip.extraData(ErrorUnion, data) },
|
||||
// .type_error => .{ .error_type = ip.extraData(Error, data) },
|
||||
.type_error_set => .{ .error_set_type = ip.extraData(ErrorSet, data) },
|
||||
.type_enum => .{ .enum_type = ip.extraData(Enum, data) },
|
||||
.type_function => .{ .function_type = ip.extraData(Fn, data) },
|
||||
@ -1071,59 +945,51 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
||||
.int_i32 => .{ .int_i64_value = @bitCast(i32, data) },
|
||||
.int_u64 => .{ .int_u64_value = ip.extraData(u64, data) },
|
||||
.int_i64 => .{ .int_i64_value = ip.extraData(i64, data) },
|
||||
.int_big_positive => unreachable,
|
||||
.int_big_negative => unreachable,
|
||||
.int_big_positive => .{ .int_big_value = .{
|
||||
.positive = true,
|
||||
.limbs = ip.extraData([]const std.math.big.Limb, data),
|
||||
} },
|
||||
.int_big_negative => .{ .int_big_value = .{
|
||||
.positive = true,
|
||||
.limbs = ip.extraData([]const std.math.big.Limb, data),
|
||||
} },
|
||||
.float_f16 => .{ .float_16_value = @bitCast(f16, @intCast(u16, data)) },
|
||||
.float_f32 => .{ .float_32_value = @bitCast(f32, data) },
|
||||
.float_f64 => .{ .float_64_value = ip.extraData(f64, data) },
|
||||
.float_f80 => .{ .float_80_value = ip.extraData(f80, data) },
|
||||
.float_f128 => .{ .float_128_value = ip.extraData(f128, data) },
|
||||
// .type => .{ .type_value = @intToEnum(Index, data) },
|
||||
|
||||
.bytes => unreachable, // TODO
|
||||
// .one_pointer => .{ .one_pointer = @intToEnum(Index, data) },
|
||||
else => @panic("TODO"),
|
||||
.bytes => .{ .bytes = ip.extraData([]const u8, data) },
|
||||
.aggregate => .{ .aggregate = ip.extraData(Aggregate, data) },
|
||||
.union_value => .{ .union_value = ip.extraData(UnionValue, data) },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
const adapter: KeyAdapter = .{ .intern_pool = ip };
|
||||
const adapter: KeyAdapter = .{ .ip = ip };
|
||||
const gop = try ip.map.getOrPutAdapted(gpa, key, adapter);
|
||||
if (gop.found_existing) return @intToEnum(Index, gop.index);
|
||||
|
||||
const item: Item = switch (key) {
|
||||
.simple => |simple| .{ .tag = .simple, .data = @enumToInt(simple) },
|
||||
.int_type => |int_ty| .{
|
||||
.tag = switch (int_ty.signedness) {
|
||||
.signed => .type_int_signed,
|
||||
.unsigned => .type_int_unsigned,
|
||||
},
|
||||
.data = int_ty.bits,
|
||||
},
|
||||
.optional_type => |optional_ty| .{ .tag = .type_optional, .data = @enumToInt(optional_ty.payload_type) },
|
||||
.anyframe_t_type => |anyframe_t| .{ .tag = .type_anyframe_t, .data = @enumToInt(anyframe_t.child) },
|
||||
.int_u64_value => |int_val| if (int_val <= std.math.maxInt(u32)) .{
|
||||
.tag = .int_u32,
|
||||
.data = @intCast(u32, int_val),
|
||||
} else .{
|
||||
.tag = .int_u64,
|
||||
.data = try ip.addExtra(gpa, int_val),
|
||||
},
|
||||
.int_i64_value => |int_val| if (std.math.maxInt(i32) <= int_val and int_val <= std.math.maxInt(i32)) .{
|
||||
.tag = .int_i32,
|
||||
.data = @bitCast(u32, @intCast(u32, int_val)),
|
||||
} else .{
|
||||
.tag = .int_i64,
|
||||
.data = try ip.addExtra(gpa, int_val),
|
||||
},
|
||||
.float_16_value => |float_val| .{ .tag = .float_f16, .data = @bitCast(u16, float_val) },
|
||||
.float_32_value => |float_val| .{ .tag = .float_f32, .data = @bitCast(u32, float_val) },
|
||||
// .type_value => |ty| .{ .tag = .type, .data = @enumToInt(ty) },
|
||||
.bytes => unreachable, // TODO
|
||||
// .one_pointer => |val| .{ .tag = .one_pointer, .data = @enumToInt(val) },
|
||||
inline else => |data| .{ .tag = key.tag(), .data = try ip.addExtra(gpa, data) }, // TODO sad stage1 noises :(
|
||||
const tag: Tag = key.tag();
|
||||
const data: u32 = switch (key) {
|
||||
.simple => |simple| @enumToInt(simple),
|
||||
|
||||
.int_type => |int_ty| int_ty.bits,
|
||||
.optional_type => |optional_ty| @enumToInt(optional_ty.payload_type),
|
||||
.anyframe_type => |anyframe_ty| @enumToInt(anyframe_ty.child),
|
||||
|
||||
.int_u64_value => |int_val| if (tag == .int_u32) @intCast(u32, int_val) else try ip.addExtra(gpa, int_val),
|
||||
.int_i64_value => |int_val| if (tag == .int_i32) @bitCast(u32, @intCast(u32, int_val)) else try ip.addExtra(gpa, int_val),
|
||||
.int_big_value => |big_int_val| try ip.addExtra(gpa, big_int_val.limbs),
|
||||
.float_16_value => |float_val| @bitCast(u16, float_val),
|
||||
.float_32_value => |float_val| @bitCast(u32, float_val),
|
||||
inline else => |data| try ip.addExtra(gpa, data), // TODO sad stage1 noises :(
|
||||
};
|
||||
try ip.items.append(gpa, item);
|
||||
|
||||
try ip.items.append(gpa, .{
|
||||
.tag = tag,
|
||||
.data = data,
|
||||
});
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
}
|
||||
|
||||
@ -1142,6 +1008,135 @@ fn extraData(ip: InternPool, comptime T: type, index: usize) T {
|
||||
return std.mem.bytesToValue(T, bytes);
|
||||
}
|
||||
|
||||
const KeyAdapter = struct {
|
||||
ip: *const InternPool,
|
||||
|
||||
pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool {
|
||||
_ = b_void;
|
||||
|
||||
return deepEql(a, ctx.ip.indexToKey(@intToEnum(Index, b_map_index)));
|
||||
}
|
||||
|
||||
pub fn hash(ctx: @This(), a: Key) u32 {
|
||||
_ = ctx;
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
deepHash(&hasher, a);
|
||||
return @truncate(u32, hasher.final());
|
||||
}
|
||||
};
|
||||
|
||||
fn deepEql(a: anytype, b: @TypeOf(a)) bool {
|
||||
const T = @TypeOf(a);
|
||||
|
||||
switch (@typeInfo(T)) {
|
||||
.Struct => |info| {
|
||||
if (info.layout == .Packed) {
|
||||
return std.mem.eql(u8, std.mem.asBytes(&a), std.mem.asBytes(&b));
|
||||
}
|
||||
inline for (info.fields) |field_info| {
|
||||
if (!deepEql(@field(a, field_info.name), @field(b, field_info.name))) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
.Union => |info| {
|
||||
const UnionTag = info.tag_type.?;
|
||||
|
||||
const tag_a = std.meta.activeTag(a);
|
||||
const tag_b = std.meta.activeTag(b);
|
||||
if (tag_a != tag_b) return false;
|
||||
|
||||
inline for (info.fields) |field_info| {
|
||||
if (@field(UnionTag, field_info.name) == tag_a) {
|
||||
return deepEql(@field(a, field_info.name), @field(b, field_info.name));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
.Pointer => |info| {
|
||||
if (info.size != .Slice) {
|
||||
@compileError("cannot compare non slice pointer type " ++ @typeName(T));
|
||||
}
|
||||
|
||||
if (@typeInfo(info.child) == .Int) {
|
||||
return std.mem.eql(info.child, a, b);
|
||||
}
|
||||
if (a.len != b.len) return false;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < a.len) : (i += 1) {
|
||||
if (!deepEql(a[i], b[i])) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
.Enum, .Int => return a == b,
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn deepHash(hasher: anytype, key: anytype) void {
|
||||
const Inner = @TypeOf(key);
|
||||
|
||||
switch (@typeInfo(Inner)) {
|
||||
.Int => {
|
||||
if (comptime std.meta.trait.hasUniqueRepresentation(Inner)) {
|
||||
hasher.update(std.mem.asBytes(&key));
|
||||
} else {
|
||||
const byte_size = comptime std.math.divCeil(comptime_int, @bitSizeOf(Inner), 8) catch unreachable;
|
||||
hasher.update(std.mem.asBytes(&key)[0..byte_size]);
|
||||
}
|
||||
},
|
||||
|
||||
.Bool => deepHash(hasher, @boolToInt(key)),
|
||||
.Enum => deepHash(hasher, @enumToInt(key)),
|
||||
.Float => |info| deepHash(hasher, switch (info.bits) {
|
||||
16 => @bitCast(u16, key),
|
||||
32 => @bitCast(u32, key),
|
||||
64 => @bitCast(u64, key),
|
||||
80 => @bitCast(u80, key),
|
||||
128 => @bitCast(u128, key),
|
||||
else => unreachable,
|
||||
}),
|
||||
|
||||
.Pointer => |info| {
|
||||
if (info.size != .Slice) {
|
||||
@compileError("");
|
||||
}
|
||||
|
||||
if (comptime std.meta.trait.hasUniqueRepresentation(info.child)) {
|
||||
hasher.update(std.mem.sliceAsBytes(key));
|
||||
} else {
|
||||
for (key) |item| {
|
||||
deepHash(hasher, item);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
.Struct => |info| {
|
||||
if (info.layout == .Packed) {
|
||||
hasher.update(std.mem.asBytes(&key));
|
||||
} else {
|
||||
inline for (info.fields) |field| {
|
||||
deepHash(hasher, @field(key, field.name));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
.Union => |info| {
|
||||
const TagType = info.tag_type.?;
|
||||
|
||||
const tag = std.meta.activeTag(key);
|
||||
deepHash(hasher, tag);
|
||||
inline for (info.fields) |field| {
|
||||
if (@field(TagType, field.name) == tag) {
|
||||
deepHash(hasher, @field(key, field.name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// UTILITY
|
||||
// ---------------------------------------------
|
||||
@ -2601,8 +2596,8 @@ test "anyframe type" {
|
||||
const i32_type = try ip.get(gpa, .{ .int_type = .{ .signedness = .signed, .bits = 32 } });
|
||||
const bool_type = try ip.get(gpa, .{ .simple = .bool });
|
||||
|
||||
const @"anyframe->i32" = try ip.get(gpa, Key{ .anyframe_t_type = .{ .child = i32_type } });
|
||||
const @"anyframe->bool" = try ip.get(gpa, Key{ .anyframe_t_type = .{ .child = bool_type } });
|
||||
const @"anyframe->i32" = try ip.get(gpa, Key{ .anyframe_type = .{ .child = i32_type } });
|
||||
const @"anyframe->bool" = try ip.get(gpa, Key{ .anyframe_type = .{ .child = bool_type } });
|
||||
|
||||
try testExpectFmtType(&ip, @"anyframe->i32", "anyframe->i32");
|
||||
try testExpectFmtType(&ip, @"anyframe->bool", "anyframe->bool");
|
||||
|
Loading…
Reference in New Issue
Block a user