Bug 1546853: Implement mozilla::Variant::addTagToHash. r=froydnj
authorJim Blandy <jimb@mozilla.com>
Thu, 25 Apr 2019 14:03:40 +0000
changeset 471326 6dea6fe4571e9d219b49a5e4cfbfefd87b7299f3
parent 471325 72ae3513844cdb10886cd351ad7bf7ea5d512248
child 471348 f4002576fa1684fb028432840e6b39ae6a94ca5a
push id84040
push userjblandy@mozilla.com
push dateThu, 25 Apr 2019 16:16:39 +0000
treeherderautoland@6dea6fe4571e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1546853
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1546853: Implement mozilla::Variant::addTagToHash. r=froydnj Define the Variant::addTagToHash method, which perturbs a hash value according to the variant's current alternative's tag. This makes it easier to avoid collisions in variants in which different alternatives might hash similarly. Tests included. Differential Revision: https://phabricator.services.mozilla.com/D28768
mfbt/Variant.h
mfbt/tests/TestVariant.cpp
--- a/mfbt/Variant.h
+++ b/mfbt/Variant.h
@@ -6,16 +6,17 @@
 
 /* A template class for tagged unions. */
 
 #include <new>
 #include <stdint.h>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/FunctionTypeTraits.h"
+#include "mozilla/HashFunctions.h"
 #include "mozilla/OperatorNewExtensions.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/TypeTraits.h"
 #include <utility>
 
 #ifndef mozilla_Variant_h
 #  define mozilla_Variant_h
 
@@ -754,16 +755,25 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_
                        typename FunctionTypeTraits<M1>::ReturnType>::value,
                 IsSame<typename FunctionTypeTraits<M0>::ReturnType,
                        typename FunctionTypeTraits<Ms>::ReturnType>::value...>::
             value,
         "all matchers must have the same return type");
     return Impl::matchN(*this, std::forward<M0>(aM0), std::forward<M1>(aM1),
                         std::forward<Ms>(aMs)...);
   }
+
+  /**
+   * Incorporate the current variant's tag into hashValue.
+   * Note that this does not hash the actual contents; you must take
+   * care of that yourself, perhaps by using a match.
+   */
+  mozilla::HashNumber addTagToHash(mozilla::HashNumber hashValue) {
+    return mozilla::AddToHash(hashValue, tag);
+  }
 };
 
 /*
  * AsVariant() is used to construct a Variant<T,...> value containing the
  * provided T value using type inference. It can be used to construct Variant
  * values in expressions or return them from functions without specifying the
  * entire Variant type.
  *
--- a/mfbt/tests/TestVariant.cpp
+++ b/mfbt/tests/TestVariant.cpp
@@ -468,26 +468,58 @@ static void testMatchingLambdas() {
 
 static void testRvalueMatcher() {
   printf("testRvalueMatcher\n");
   using V = Variant<uint8_t, uint32_t, uint64_t>;
   V v(uint8_t(1));
   MOZ_RELEASE_ASSERT(v.match(Describer()) == Describer::little);
 }
 
+static void testAddTagToHash() {
+  printf("testAddToHash\n");
+  using V = Variant<uint8_t, uint16_t, uint32_t, uint64_t>;
+
+  // We don't know what our hash function is, and these are certainly not all
+  // true under all hash functions. But they are probably true under almost any
+  // decent hash function, and our aim is simply to establish that the tag
+  // *does* influence the hash value.
+  {
+    mozilla::HashNumber h8 = V(uint8_t(1)).addTagToHash(0);
+    mozilla::HashNumber h16 = V(uint16_t(1)).addTagToHash(0);
+    mozilla::HashNumber h32 = V(uint32_t(1)).addTagToHash(0);
+    mozilla::HashNumber h64 = V(uint64_t(1)).addTagToHash(0);
+
+    MOZ_RELEASE_ASSERT(h8 != h16 && h8 != h32 && h8 != h64);
+    MOZ_RELEASE_ASSERT(h16 != h32 && h16 != h64);
+    MOZ_RELEASE_ASSERT(h32 != h64);
+  }
+
+  {
+    mozilla::HashNumber h8 = V(uint8_t(1)).addTagToHash(0x124356);
+    mozilla::HashNumber h16 = V(uint16_t(1)).addTagToHash(0x124356);
+    mozilla::HashNumber h32 = V(uint32_t(1)).addTagToHash(0x124356);
+    mozilla::HashNumber h64 = V(uint64_t(1)).addTagToHash(0x124356);
+
+    MOZ_RELEASE_ASSERT(h8 != h16 && h8 != h32 && h8 != h64);
+    MOZ_RELEASE_ASSERT(h16 != h32 && h16 != h64);
+    MOZ_RELEASE_ASSERT(h32 != h64);
+  }
+}
+
 int main() {
   testDetails();
   testSimple();
   testDuplicate();
   testConstructionWithVariantType();
   testConstructionWithVariantIndex();
   testCopy();
   testMove();
   testDestructor();
   testEquality();
   testMatching();
   testMatchingLambda();
   testMatchingLambdas();
   testRvalueMatcher();
+  testAddTagToHash();
 
   printf("TestVariant OK!\n");
   return 0;
 }