SameValueComparer.h 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Js
  7. {
  8. template <typename Key, bool zero>
  9. struct SameValueComparerCommon
  10. {
  11. static bool Equals(Key, Key) { static_assert(false, "Can only use SameValueComparer with Var as the key type"); }
  12. static hash_t GetHashCode(Key) { static_assert(false, "Can only use SameValueComparer with Var as the key type"); }
  13. };
  14. template <typename Key> using SameValueComparer = SameValueComparerCommon<Key, false>;
  15. template <typename Key> using SameValueZeroComparer = SameValueComparerCommon<Key, true>;
  16. template <bool zero>
  17. struct SameValueComparerCommon<Var, zero>
  18. {
  19. static bool Equals(Var x, Var y)
  20. {
  21. if (zero)
  22. {
  23. return JavascriptConversion::SameValueZero(x, y);
  24. }
  25. else
  26. {
  27. return JavascriptConversion::SameValue(x, y);
  28. }
  29. }
  30. static hash_t HashDouble(double d)
  31. {
  32. if (JavascriptNumber::IsNan(d))
  33. {
  34. return 0;
  35. }
  36. if (zero)
  37. {
  38. // SameValueZero treats -0 and +0 the same, so normalize to get same hash code
  39. if (JavascriptNumber::IsNegZero(d))
  40. {
  41. d = 0.0;
  42. }
  43. }
  44. __int64 v = *(__int64*)&d;
  45. return (uint)v ^ (uint)(v >> 32);
  46. }
  47. static hash_t GetHashCode(Var i)
  48. {
  49. switch (JavascriptOperators::GetTypeId(i))
  50. {
  51. case TypeIds_Integer:
  52. // int32 can be fully represented in a double, so hash it as a double
  53. // to ensure that tagged ints hash to the same value as JavascriptNumbers.
  54. return HashDouble((double)TaggedInt::ToInt32(i));
  55. case TypeIds_Int64Number:
  56. case TypeIds_UInt64Number:
  57. {
  58. __int64 v = JavascriptInt64Number::FromVar(i)->GetValue();
  59. double d = (double) v;
  60. if (v != (__int64) d)
  61. {
  62. // this int64 is too large to represent in a double
  63. // and thus will never be equal to a double so hash it
  64. // as an int64
  65. return (uint)v ^ (uint)(v >> 32);
  66. }
  67. // otherwise hash it as a double
  68. return HashDouble(d);
  69. }
  70. case TypeIds_Number:
  71. {
  72. double d = JavascriptNumber::GetValue(i);
  73. return HashDouble(d);
  74. }
  75. case TypeIds_String:
  76. {
  77. JavascriptString* v = JavascriptString::UnsafeFromVar(i);
  78. return JsUtil::CharacterBuffer<WCHAR>::StaticGetHashCode(v->GetString(), v->GetLength());
  79. }
  80. default:
  81. return RecyclerPointerComparer<Var>::GetHashCode(i);
  82. }
  83. }
  84. };
  85. }