diff --git a/runtime/complex.go b/runtime/complex.go index f8b12001..743600fa 100644 --- a/runtime/complex.go +++ b/runtime/complex.go @@ -72,6 +72,7 @@ func initComplexType(dict map[string]*Object) { ComplexType.slots.Eq = &binaryOpSlot{complexEq} ComplexType.slots.GE = &binaryOpSlot{complexCompareNotSupported} ComplexType.slots.GT = &binaryOpSlot{complexCompareNotSupported} + ComplexType.slots.Hash = &unaryOpSlot{complexHash} ComplexType.slots.LE = &binaryOpSlot{complexCompareNotSupported} ComplexType.slots.LT = &binaryOpSlot{complexCompareNotSupported} ComplexType.slots.NE = &binaryOpSlot{complexNE} @@ -130,3 +131,12 @@ func complexCoerce(o *Object) (complex128, bool) { } return complex(floatO, 0.0), true } + +func complexHash(f *Frame, o *Object) (*Object, *BaseException) { + v := toComplexUnsafe(o).Value() + hashCombined := hashFloat(real(v)) + 1000003*hashFloat(imag(v)) + if hashCombined == -1 { + hashCombined = -2 + } + return NewInt(hashCombined).ToObject(), nil +} diff --git a/runtime/complex_test.go b/runtime/complex_test.go index cf58eaa3..24a934c9 100644 --- a/runtime/complex_test.go +++ b/runtime/complex_test.go @@ -93,3 +93,18 @@ func TestComplexRepr(t *testing.T) { } } } + +func TestComplexHash(t *testing.T) { + cases := []invokeTestCase{ + {args: wrapArgs(complex(0.0, 0.0)), want: NewInt(0).ToObject()}, + {args: wrapArgs(complex(0.0, 1.0)), want: NewInt(1000003).ToObject()}, + {args: wrapArgs(complex(1.0, 0.0)), want: NewInt(1).ToObject()}, + {args: wrapArgs(complex(3.1, -4.2)), want: NewInt(-1556830019620134).ToObject()}, + {args: wrapArgs(complex(3.1, 4.2)), want: NewInt(1557030815934348).ToObject()}, + } + for _, cas := range cases { + if err := runInvokeTestCase(wrapFuncForTest(complexHash), &cas); err != "" { + t.Error(err) + } + } +}