Bug 1533636 - Define HashStringUntilZero and HashStringKnownLength template functions for code that wishes to invoke the HashString algorithm on non-pointer iterator types. r=froydnj
authorJeff Walden <jwalden@mit.edu>
Tue, 05 Mar 2019 10:11:32 -0800
changeset 463475 0ad3e7b4f75e90c05ab0ee975dd17a9b7d43ce5d
parent 463474 0e054a2c650a484e6a547d5fa4a6cde490445b53
child 463476 8ffeb0cdf0e58989498414a1f9b7c22495f7f998
push id35685
push useropoprus@mozilla.com
push dateTue, 12 Mar 2019 04:48:38 +0000
treeherdermozilla-central@b9d87882a365 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1533636
milestone67.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 1533636 - Define HashStringUntilZero and HashStringKnownLength template functions for code that wishes to invoke the HashString algorithm on non-pointer iterator types. r=froydnj Differential Revision: https://phabricator.services.mozilla.com/D22652
mfbt/HashFunctions.h
--- a/mfbt/HashFunctions.h
+++ b/mfbt/HashFunctions.h
@@ -50,16 +50,17 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Char16.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Types.h"
 #include "mozilla/WrappingOperations.h"
 
 #include <stdint.h>
+#include <type_traits>
 
 namespace mozilla {
 
 using HashNumber = uint32_t;
 static const uint32_t kHashNumberBits = 32;
 
 /**
  * The golden ratio as a 32-bit fixed-point value.
@@ -221,83 +222,102 @@ MOZ_MUST_USE HashNumber AddToHash(HashNu
  * much better than calling AddToHash(x, y), because AddToHash(x, y) assumes
  * that x has already been hashed.
  */
 template <typename... Args>
 MOZ_MUST_USE inline HashNumber HashGeneric(Args... aArgs) {
   return AddToHash(0, aArgs...);
 }
 
-namespace detail {
-
-template <typename T>
-constexpr HashNumber HashUntilZero(const T* aStr) {
+/**
+ * Hash successive |*aIter| until |!*aIter|, i.e. til null-termination.
+ *
+ * This function is *not* named HashString like the non-template overloads
+ * below.  Some users define HashString overloads and pass inexactly-matching
+ * values to them -- but an inexactly-matching value would match this overload
+ * instead!  We follow the general rule and don't mix and match template and
+ * regular overloads to avoid this.
+ *
+ * If you have the string's length, call HashStringKnownLength: it may be
+ * marginally faster.
+ */
+template <typename Iterator>
+MOZ_MUST_USE constexpr HashNumber HashStringUntilZero(Iterator aIter) {
   HashNumber hash = 0;
-  for (; T c = *aStr; aStr++) {
+  for (; auto c = *aIter; ++aIter) {
     hash = AddToHash(hash, c);
   }
   return hash;
 }
 
-template <typename T>
-HashNumber HashKnownLength(const T* aStr, size_t aLength) {
+/**
+ * Hash successive |aIter[i]| up to |i == aLength|.
+ */
+template <typename Iterator>
+MOZ_MUST_USE constexpr HashNumber HashStringKnownLength(Iterator aIter,
+                                                        size_t aLength) {
   HashNumber hash = 0;
   for (size_t i = 0; i < aLength; i++) {
-    hash = AddToHash(hash, aStr[i]);
+    hash = AddToHash(hash, aIter[i]);
   }
   return hash;
 }
 
-} /* namespace detail */
-
 /**
  * The HashString overloads below do just what you'd expect.
  *
- * If you have the string's length, you might as well call the overload which
- * includes the length.  It may be marginally faster.
+ * These functions are non-template functions so that users can 1) overload them
+ * with their own types 2) in a way that allows implicit conversions to happen.
  */
 MOZ_MUST_USE inline HashNumber HashString(const char* aStr) {
-  return detail::HashUntilZero(reinterpret_cast<const unsigned char*>(aStr));
+  // Use the |const unsigned char*| version of the above so that all ordinary
+  // character data hashes identically.
+  return HashStringUntilZero(reinterpret_cast<const unsigned char*>(aStr));
 }
 
 MOZ_MUST_USE inline HashNumber HashString(const char* aStr, size_t aLength) {
-  return detail::HashKnownLength(reinterpret_cast<const unsigned char*>(aStr),
-                                 aLength);
+  // Delegate to the |const unsigned char*| version of the above to share
+  // template instantiations.
+  return HashStringKnownLength(reinterpret_cast<const unsigned char*>(aStr),
+                               aLength);
 }
 
 MOZ_MUST_USE
 inline HashNumber HashString(const unsigned char* aStr, size_t aLength) {
-  return detail::HashKnownLength(aStr, aLength);
+  return HashStringKnownLength(aStr, aLength);
 }
 
 // You may need to use the
 // MOZ_{PUSH,POP}_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING macros if you use
 // this function. See the comment on those macros' definitions for more detail.
 MOZ_MUST_USE constexpr HashNumber HashString(const char16_t* aStr) {
-  return detail::HashUntilZero(aStr);
+  return HashStringUntilZero(aStr);
 }
 
 MOZ_MUST_USE inline HashNumber HashString(const char16_t* aStr,
                                           size_t aLength) {
-  return detail::HashKnownLength(aStr, aLength);
+  return HashStringKnownLength(aStr, aLength);
 }
 
-/*
- * On Windows, wchar_t is not the same as char16_t, even though it's
- * the same width!
+/**
+ * HashString overloads for |wchar_t| on platforms where it isn't |char16_t|.
  */
-#ifdef WIN32
-MOZ_MUST_USE inline HashNumber HashString(const wchar_t* aStr) {
-  return detail::HashUntilZero(aStr);
+template <typename WCharT, typename = typename std::enable_if<
+                               std::is_same<WCharT, wchar_t>::value &&
+                               !std::is_same<wchar_t, char16_t>::value>::type>
+MOZ_MUST_USE inline HashNumber HashString(const WCharT* aStr) {
+  return HashStringUntilZero(aStr);
 }
 
-MOZ_MUST_USE inline HashNumber HashString(const wchar_t* aStr, size_t aLength) {
-  return detail::HashKnownLength(aStr, aLength);
+template <typename WCharT, typename = typename std::enable_if<
+                               std::is_same<WCharT, wchar_t>::value &&
+                               !std::is_same<wchar_t, char16_t>::value>::type>
+MOZ_MUST_USE inline HashNumber HashString(const WCharT* aStr, size_t aLength) {
+  return HashStringKnownLength(aStr, aLength);
 }
-#endif
 
 /**
  * Hash some number of bytes.
  *
  * This hash walks word-by-word, rather than byte-by-byte, so you won't get the
  * same result out of HashBytes as you would out of HashString.
  */
 MOZ_MUST_USE extern MFBT_API HashNumber HashBytes(const void* bytes,