feature. See also
. The project being documented here (as the example) is the Zig library itself.
Interner.Key
pub const Key = union(enum)
File
Code
pub const Key = union(enum) {
int_ty: u16,
float_ty: u16,
complex_ty: u16,
ptr_ty,
noreturn_ty,
void_ty,
func_ty,
array_ty: struct {
len: u64,
child: Ref,
},
vector_ty: struct {
len: u32,
child: Ref,
},
record_ty: []const Ref,
null,
int: union(enum) {
u64: u64,
i64: i64,
big_int: BigIntConst,
pub fn toBigInt(repr: @This(), space: *Tag.Int.BigIntSpace) BigIntConst {
return switch (repr) {
.big_int => |x| x,
inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(),
};
}
},
float: Float,
complex: Complex,
bytes: []const u8,
pointer: Pointer,
pub const Float = union(enum) {
f16: f16,
f32: f32,
f64: f64,
f80: f80,
f128: f128,
};
pub const Complex = union(enum) {
cf16: [2]f16,
cf32: [2]f32,
cf64: [2]f64,
cf80: [2]f80,
cf128: [2]f128,
};
pub const Pointer = struct {
node: u32,
offset: Ref,
};
pub fn hash(key: Key) u32 {
var hasher = Hash.init(0);
const tag = std.meta.activeTag(key);
std.hash.autoHash(&hasher, tag);
switch (key) {
.bytes => |bytes| {
hasher.update(bytes);
},
.record_ty => |elems| for (elems) |elem| {
std.hash.autoHash(&hasher, elem);
},
.float => |repr| switch (repr) {
inline else => |data| std.hash.autoHash(
&hasher,
@as(@Int(.unsigned, @bitSizeOf(@TypeOf(data))), @bitCast(data)),
),
},
.complex => |repr| switch (repr) {
inline else => |data| std.hash.autoHash(
&hasher,
@as(@Int(.unsigned, @bitSizeOf(@TypeOf(data))), @bitCast(data)),
),
},
.int => |repr| {
var space: Tag.Int.BigIntSpace = undefined;
const big = repr.toBigInt(&space);
std.hash.autoHash(&hasher, big.positive);
for (big.limbs) |limb| std.hash.autoHash(&hasher, limb);
},
inline else => |info| {
std.hash.autoHash(&hasher, info);
},
}
return @truncate(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;
switch (a) {
.record_ty => |a_elems| {
const b_elems = b.record_ty;
if (a_elems.len != b_elems.len) return false;
for (a_elems, b_elems) |a_elem, b_elem| {
if (a_elem != b_elem) return false;
}
return true;
},
.bytes => |a_bytes| {
const b_bytes = b.bytes;
return std.mem.eql(u8, a_bytes, b_bytes);
},
.int => |a_repr| {
var a_space: Tag.Int.BigIntSpace = undefined;
const a_big = a_repr.toBigInt(&a_space);
var b_space: Tag.Int.BigIntSpace = undefined;
const b_big = b.int.toBigInt(&b_space);
return a_big.eql(b_big);
},
inline else => |a_info, tag| {
const b_info = @field(b, @tagName(tag));
return std.meta.eql(a_info, b_info);
},
}
}
fn toRef(key: Key) ?Ref {
switch (key) {
.int_ty => |bits| switch (bits) {
1 => return .i1,
8 => return .i8,
16 => return .i16,
32 => return .i32,
64 => return .i64,
128 => return .i128,
else => {},
},
.float_ty => |bits| switch (bits) {
16 => return .f16,
32 => return .f32,
64 => return .f64,
80 => return .f80,
128 => return .f128,
else => unreachable,
},
.complex_ty => |bits| switch (bits) {
16 => return .cf16,
32 => return .cf32,
64 => return .cf64,
80 => return .cf80,
128 => return .cf128,
else => unreachable,
},
.ptr_ty => return .ptr,
.func_ty => return .func,
.noreturn_ty => return .noreturn,
.void_ty => return .void,
.int => |repr| {
var space: Tag.Int.BigIntSpace = undefined;
const big = repr.toBigInt(&space);
if (big.eqlZero()) return .zero;
const big_one = BigIntConst{ .limbs = &.{1}, .positive = true };
if (big.eql(big_one)) return .one;
},
.float => |repr| switch (repr) {
inline else => |data| {
if (std.math.isPositiveZero(data)) return .zero;
if (data == 1) return .one;
},
},
.null => return .null,
else => {},
}
return null;
}
pub fn toBigInt(key: Key, space: *Tag.Int.BigIntSpace) BigIntConst {
return key.int.toBigInt(space);
}
}