//------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #pragma once namespace Js { template struct SameValueComparerCommon { static bool Equals(Key, Key) { static_assert(false, "Can only use SameValueComparer with Var as the key type"); } static hash_t GetHashCode(Key) { static_assert(false, "Can only use SameValueComparer with Var as the key type"); } }; template using SameValueComparer = SameValueComparerCommon; template using SameValueZeroComparer = SameValueComparerCommon; template struct SameValueComparerCommon { static bool Equals(Var x, Var y) { if (zero) { return JavascriptConversion::SameValueZero(x, y); } else { return JavascriptConversion::SameValue(x, y); } } static hash_t HashDouble(double d) { if (JavascriptNumber::IsNan(d)) { return 0; } if (zero) { // SameValueZero treats -0 and +0 the same, so normalize to get same hash code if (JavascriptNumber::IsNegZero(d)) { d = 0.0; } } __int64 v = *(__int64*)&d; return (uint)v ^ (uint)(v >> 32); } static hash_t GetHashCode(Var i) { switch (JavascriptOperators::GetTypeId(i)) { case TypeIds_Integer: // int32 can be fully represented in a double, so hash it as a double // to ensure that tagged ints hash to the same value as JavascriptNumbers. return HashDouble((double)TaggedInt::ToInt32(i)); case TypeIds_Int64Number: case TypeIds_UInt64Number: { __int64 v = JavascriptInt64Number::FromVar(i)->GetValue(); double d = (double) v; if (v != (__int64) d) { // this int64 is too large to represent in a double // and thus will never be equal to a double so hash it // as an int64 return (uint)v ^ (uint)(v >> 32); } // otherwise hash it as a double return HashDouble(d); } case TypeIds_Number: { double d = JavascriptNumber::GetValue(i); return HashDouble(d); } case TypeIds_String: { JavascriptString* v = JavascriptString::UnsafeFromVar(i); return JsUtil::CharacterBuffer::StaticGetHashCode(v->GetString(), v->GetLength()); } default: return RecyclerPointerComparer::GetHashCode(i); } } }; }