Commit 7e2774367e

Vexu <git@vexu.eu>
2020-10-12 11:53:44
stage2: implement Value.hash
1 parent 27d233c
Changed files (1)
src/value.zig
@@ -1242,8 +1242,139 @@ pub const Value = extern union {
         return compare(a, .eq, b);
     }
 
-    pub fn hash(a: Value) u64 {
-        @panic("TODO Value.hash");
+    pub fn hash(self: Value) u64 {
+        var hasher = std.hash.Wyhash.init(0);
+        std.hash.autoHash(&hasher, self.tag());
+
+        switch (self.tag()) {
+            .u8_type,
+            .i8_type,
+            .u16_type,
+            .i16_type,
+            .u32_type,
+            .i32_type,
+            .u64_type,
+            .i64_type,
+            .usize_type,
+            .isize_type,
+            .c_short_type,
+            .c_ushort_type,
+            .c_int_type,
+            .c_uint_type,
+            .c_long_type,
+            .c_ulong_type,
+            .c_longlong_type,
+            .c_ulonglong_type,
+            .c_longdouble_type,
+            .f16_type,
+            .f32_type,
+            .f64_type,
+            .f128_type,
+            .c_void_type,
+            .bool_type,
+            .void_type,
+            .type_type,
+            .anyerror_type,
+            .comptime_int_type,
+            .comptime_float_type,
+            .noreturn_type,
+            .null_type,
+            .undefined_type,
+            .fn_noreturn_no_args_type,
+            .fn_void_no_args_type,
+            .fn_naked_noreturn_no_args_type,
+            .fn_ccc_void_no_args_type,
+            .single_const_pointer_to_comptime_int_type,
+            .const_slice_u8_type,
+            .enum_literal_type,
+            .anyframe_type,
+            .ty,
+            => {
+                // Directly return Type.hash, toType can only fail for .int_type and .error_set.
+                var allocator = std.heap.FixedBufferAllocator.init(&[_]u8{});
+                return (self.toType(&allocator.allocator) catch unreachable).hash();
+            },
+            .error_set => {
+                // Payload.decl should be same for all instances of the type.
+                const payload = @fieldParentPtr(Payload.ErrorSet, "base", self.ptr_otherwise);
+                std.hash.autoHash(&hasher, payload.decl);
+            },
+            .int_type => {
+                const payload = self.cast(Payload.IntType).?;
+                if (payload.signed) {
+                    var new = Type.Payload.IntSigned{ .bits = payload.bits };
+                    return Type.initPayload(&new.base).hash();
+                } else {
+                    var new = Type.Payload.IntUnsigned{ .bits = payload.bits };
+                    return Type.initPayload(&new.base).hash();
+                }
+            },
+
+            .undef,
+            .zero,
+            .one,
+            .void_value,
+            .unreachable_value,
+            .empty_struct_value,
+            .empty_array,
+            .null_value,
+            .bool_true,
+            .bool_false,
+            => {},
+
+            .float_16, .float_32, .float_64, .float_128 => {},
+            .enum_literal, .bytes => {
+                const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise);
+                hasher.update(payload.data);
+            },
+            .int_u64 => {
+                const payload = @fieldParentPtr(Payload.Int_u64, "base", self.ptr_otherwise);
+                std.hash.autoHash(&hasher, payload.int);
+            },
+            .int_i64 => {
+                const payload = @fieldParentPtr(Payload.Int_i64, "base", self.ptr_otherwise);
+                std.hash.autoHash(&hasher, payload.int);
+            },
+            .repeated => {
+                const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
+                std.hash.autoHash(&hasher, payload.val.hash());
+            },
+            .ref_val => {
+                const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
+                std.hash.autoHash(&hasher, payload.val.hash());
+            },
+            .int_big_positive, .int_big_negative => {
+                var space: BigIntSpace = undefined;
+                const big = self.toBigInt(&space);
+                std.hash.autoHash(&hasher, big.positive);
+                for (big.limbs) |limb| {
+                    std.hash.autoHash(&hasher, limb);
+                }
+            },
+            .elem_ptr => {
+                const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
+                std.hash.autoHash(&hasher, payload.array_ptr.hash());
+                std.hash.autoHash(&hasher, payload.index);
+            },
+            .decl_ref => {
+                const payload = @fieldParentPtr(Payload.DeclRef, "base", self.ptr_otherwise);
+                std.hash.autoHash(&hasher, payload.decl);
+            },
+            .function => {
+                const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
+                std.hash.autoHash(&hasher, payload.func);
+            },
+            .variable => {
+                const payload = @fieldParentPtr(Payload.Variable, "base", self.ptr_otherwise);
+                std.hash.autoHash(&hasher, payload.variable);
+            },
+            .@"error" => {
+                const payload = @fieldParentPtr(Payload.Error, "base", self.ptr_otherwise);
+                hasher.update(payload.name);
+                std.hash.autoHash(&hasher, payload.value);
+            },
+        }
+        return hasher.final();
     }
 
     /// Asserts the value is a pointer and dereferences it.