|
@@ -2,7 +2,7 @@
|
|
|
# User Nicholas Nethercote <nnethercote@mozilla.com>
|
|
|
# Date 1520465234 -39600
|
|
|
# Node ID 545fb6e48c79d2704b5e5506a667b72d97a3d949
|
|
|
-# Parent 83dffebb15369683ef0426c43d68c593f5d2b618
|
|
|
+# Parent 098988e8fe62d9266542e24e618c1cd3b2d94660
|
|
|
Bug 1443706 - Introduce ConstExprHashString(const char16_t*). r=jwalden
|
|
|
|
|
|
This is a `constexpr` alternative to HashString(const char16_t*). We can't make
|
|
@@ -25,7 +25,7 @@ MozReview-Commit-ID: 7r3PnrQXb29
|
|
|
diff --git a/mfbt/HashFunctions.h b/mfbt/HashFunctions.h
|
|
|
--- a/mfbt/HashFunctions.h
|
|
|
+++ b/mfbt/HashFunctions.h
|
|
|
-@@ -60,17 +60,24 @@ namespace mozilla {
|
|
|
+@@ -60,17 +60,22 @@ namespace mozilla {
|
|
|
|
|
|
/**
|
|
|
* The golden ratio as a 32-bit fixed-point value.
|
|
@@ -34,24 +34,22 @@ diff --git a/mfbt/HashFunctions.h b/mfbt/HashFunctions.h
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
|
--inline uint32_t
|
|
|
+-inline uint32_t AddU32ToHash(uint32_t aHash, uint32_t aValue) {
|
|
|
+MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
|
|
|
-+constexpr uint32_t
|
|
|
-+RotateLeft5(uint32_t aValue)
|
|
|
-+{
|
|
|
++constexpr uint32_t RotateLeft5(uint32_t aValue) {
|
|
|
+ return (aValue << 5) | (aValue >> 27);
|
|
|
+}
|
|
|
+
|
|
|
-+constexpr uint32_t
|
|
|
- AddU32ToHash(uint32_t aHash, uint32_t aValue)
|
|
|
- {
|
|
|
++constexpr uint32_t AddU32ToHash(uint32_t aHash, uint32_t aValue) {
|
|
|
/*
|
|
|
* This is the meat of all our hash routines. This hash function is not
|
|
|
* particularly sophisticated, but it seems to work well for our mostly
|
|
|
* plain-text inputs. Implementation notes follow.
|
|
|
*
|
|
|
* Our use of the golden ratio here is arbitrary; we could pick almost any
|
|
|
-@@ -84,17 +91,17 @@ AddU32ToHash(uint32_t aHash, uint32_t aV
|
|
|
+ * number which:
|
|
|
+ *
|
|
|
+@@ -82,17 +87,17 @@ inline uint32_t AddU32ToHash(uint32_t aH
|
|
|
*
|
|
|
* The rotation length of 5 is also arbitrary, although an odd number is again
|
|
|
* preferable so our hash explores the whole universe of possible rotations.
|
|
@@ -70,7 +68,7 @@ diff --git a/mfbt/HashFunctions.h b/mfbt/HashFunctions.h
|
|
|
* (Number-theoretic aside: Because any odd number |m| is relatively prime to
|
|
|
* our modulus (2**32), the list
|
|
|
*
|
|
|
-@@ -105,24 +112,24 @@ AddU32ToHash(uint32_t aHash, uint32_t aV
|
|
|
+@@ -103,24 +108,24 @@ inline uint32_t AddU32ToHash(uint32_t aH
|
|
|
*
|
|
|
* It's also nice if |m| has large-ish order mod 2**32 -- that is, if the
|
|
|
* smallest k such that m**k == 1 (mod 2**32) is large -- so we can safely
|
|
@@ -86,38 +84,38 @@ diff --git a/mfbt/HashFunctions.h b/mfbt/HashFunctions.h
|
|
|
/**
|
|
|
* AddUintptrToHash takes sizeof(uintptr_t) as a template parameter.
|
|
|
*/
|
|
|
- template<size_t PtrSize>
|
|
|
--inline uint32_t
|
|
|
-+constexpr uint32_t
|
|
|
- AddUintptrToHash(uint32_t aHash, uintptr_t aValue)
|
|
|
- {
|
|
|
+ template <size_t PtrSize>
|
|
|
+-inline uint32_t AddUintptrToHash(uint32_t aHash, uintptr_t aValue) {
|
|
|
++constexpr uint32_t AddUintptrToHash(uint32_t aHash, uintptr_t aValue) {
|
|
|
return AddU32ToHash(aHash, static_cast<uint32_t>(aValue));
|
|
|
}
|
|
|
|
|
|
- template<>
|
|
|
- inline uint32_t
|
|
|
- AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue)
|
|
|
-@@ -168,17 +175,17 @@ AddToHash(uint32_t aHash, A* aA)
|
|
|
- return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, uintptr_t(aA));
|
|
|
- }
|
|
|
-
|
|
|
- // We use AddUintptrToHash() for hashing all integral types. 8-byte integral types
|
|
|
- // are treated the same as 64-bit pointers, and smaller integral types are first
|
|
|
- // implicitly converted to 32 bits and then passed to AddUintptrToHash() to be hashed.
|
|
|
- template<typename T,
|
|
|
- typename U = typename mozilla::EnableIf<mozilla::IsIntegral<T>::value>::Type>
|
|
|
--MOZ_MUST_USE inline uint32_t
|
|
|
-+MOZ_MUST_USE constexpr uint32_t
|
|
|
- AddToHash(uint32_t aHash, T aA)
|
|
|
- {
|
|
|
- return detail::AddUintptrToHash<sizeof(T)>(aHash, aA);
|
|
|
+ template <>
|
|
|
+ inline uint32_t AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue) {
|
|
|
+ uint32_t v1 = static_cast<uint32_t>(aValue);
|
|
|
+ uint32_t v2 = static_cast<uint32_t>(static_cast<uint64_t>(aValue) >> 32);
|
|
|
+ return AddU32ToHash(AddU32ToHash(aHash, v1), v2);
|
|
|
+@@ -132,17 +137,17 @@ inline uint32_t AddUintptrToHash<8>(uint
|
|
|
+ * AddToHash takes a hash and some values and returns a new hash based on the
|
|
|
+ * inputs.
|
|
|
+ *
|
|
|
+ * Currently, we support hashing uint32_t's, values which we can implicitly
|
|
|
+ * convert to uint32_t, data pointers, and function pointers.
|
|
|
+ */
|
|
|
+ template <typename T, bool TypeIsNotIntegral = !mozilla::IsIntegral<T>::value,
|
|
|
+ typename U = typename mozilla::EnableIf<TypeIsNotIntegral>::Type>
|
|
|
+-MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, T aA) {
|
|
|
++MOZ_MUST_USE constexpr uint32_t AddToHash(uint32_t aHash, T aA) {
|
|
|
+ /*
|
|
|
+ * Try to convert |A| to uint32_t implicitly. If this works, great. If not,
|
|
|
+ * we'll error out.
|
|
|
+ */
|
|
|
+ return detail::AddU32ToHash(aHash, aA);
|
|
|
}
|
|
|
|
|
|
- template<typename A, typename... Args>
|
|
|
- MOZ_MUST_USE uint32_t
|
|
|
- AddToHash(uint32_t aHash, A aArg, Args... aArgs)
|
|
|
-@@ -208,16 +215,29 @@ HashUntilZero(const T* aStr)
|
|
|
- {
|
|
|
+ template <typename A>
|
|
|
+@@ -190,16 +195,27 @@ template <typename T>
|
|
|
+ uint32_t HashUntilZero(const T* aStr) {
|
|
|
uint32_t hash = 0;
|
|
|
for (T c; (c = *aStr); aStr++) {
|
|
|
hash = AddToHash(hash, c);
|
|
@@ -129,29 +127,27 @@ diff --git a/mfbt/HashFunctions.h b/mfbt/HashFunctions.h
|
|
|
+// only be used for compile-time computation because it uses recursion.
|
|
|
+// XXX: once support for GCC 4.9 is dropped, this function should be removed
|
|
|
+// and HashUntilZero(const T*) should be made `constexpr`.
|
|
|
-+template<typename T>
|
|
|
-+constexpr uint32_t
|
|
|
-+ConstExprHashUntilZero(const T* aStr, uint32_t aHash)
|
|
|
-+{
|
|
|
++template <typename T>
|
|
|
++constexpr uint32_t ConstExprHashUntilZero(const T* aStr, uint32_t aHash) {
|
|
|
+ return !*aStr
|
|
|
+ ? aHash
|
|
|
+ : ConstExprHashUntilZero(aStr + 1, AddToHash(aHash, *aStr));
|
|
|
+}
|
|
|
+
|
|
|
- template<typename T>
|
|
|
- uint32_t
|
|
|
- HashKnownLength(const T* aStr, size_t aLength)
|
|
|
- {
|
|
|
+ template <typename T>
|
|
|
+ uint32_t HashKnownLength(const T* aStr, size_t aLength) {
|
|
|
uint32_t hash = 0;
|
|
|
for (size_t i = 0; i < aLength; i++) {
|
|
|
hash = AddToHash(hash, aStr[i]);
|
|
|
}
|
|
|
-@@ -252,16 +272,31 @@ HashString(const unsigned char* aStr, si
|
|
|
+ return hash;
|
|
|
+ }
|
|
|
+@@ -225,16 +241,29 @@ MOZ_MUST_USE
|
|
|
+ inline uint32_t HashString(const unsigned char* aStr, size_t aLength) {
|
|
|
+ return detail::HashKnownLength(aStr, aLength);
|
|
|
}
|
|
|
|
|
|
- MOZ_MUST_USE inline uint32_t
|
|
|
- HashString(const char16_t* aStr)
|
|
|
- {
|
|
|
+ MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr) {
|
|
|
return detail::HashUntilZero(aStr);
|
|
|
}
|
|
|
|
|
@@ -164,24 +160,22 @@ diff --git a/mfbt/HashFunctions.h b/mfbt/HashFunctions.h
|
|
|
+//
|
|
|
+// XXX: once support for GCC 4.9 is dropped, this function should be removed
|
|
|
+// and HashString(const char16_t*) should be made `constexpr`.
|
|
|
-+MOZ_MUST_USE constexpr uint32_t
|
|
|
-+ConstExprHashString(const char16_t* aStr)
|
|
|
-+{
|
|
|
++MOZ_MUST_USE constexpr uint32_t ConstExprHashString(const char16_t* aStr) {
|
|
|
+ return detail::ConstExprHashUntilZero(aStr, 0);
|
|
|
+}
|
|
|
+
|
|
|
- MOZ_MUST_USE inline uint32_t
|
|
|
- HashString(const char16_t* aStr, size_t aLength)
|
|
|
- {
|
|
|
+ MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr, size_t aLength) {
|
|
|
return detail::HashKnownLength(aStr, aLength);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* On Windows, wchar_t is not the same as char16_t, even though it's
|
|
|
+ * the same width!
|
|
|
+ */
|
|
|
diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
--- a/mfbt/WrappingOperations.h
|
|
|
+++ b/mfbt/WrappingOperations.h
|
|
|
-@@ -89,55 +89,42 @@ struct WrapToSignedHelper
|
|
|
+@@ -88,51 +88,38 @@ struct WrapToSignedHelper {
|
|
|
/**
|
|
|
* Convert an unsigned value to signed, if necessary wrapping around.
|
|
|
*
|
|
@@ -189,11 +183,10 @@ diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
* these days -- but this function makes explicit that such conversion is
|
|
|
* happening.
|
|
|
*/
|
|
|
- template<typename UnsignedType>
|
|
|
+ template <typename UnsignedType>
|
|
|
-inline constexpr typename detail::WrapToSignedHelper<UnsignedType>::SignedType
|
|
|
+constexpr typename detail::WrapToSignedHelper<UnsignedType>::SignedType
|
|
|
- WrapToSigned(UnsignedType aValue)
|
|
|
- {
|
|
|
+ WrapToSigned(UnsignedType aValue) {
|
|
|
return detail::WrapToSignedHelper<UnsignedType>::compute(aValue);
|
|
|
}
|
|
|
|
|
@@ -212,27 +205,23 @@ diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
-
|
|
|
namespace detail {
|
|
|
|
|
|
- template<typename T>
|
|
|
--inline constexpr T
|
|
|
-+constexpr T
|
|
|
- ToResult(typename MakeUnsigned<T>::Type aUnsigned)
|
|
|
- {
|
|
|
+ template <typename T>
|
|
|
+-inline constexpr T ToResult(typename MakeUnsigned<T>::Type aUnsigned) {
|
|
|
++constexpr T ToResult(typename MakeUnsigned<T>::Type aUnsigned) {
|
|
|
// We could *always* return WrapToSigned and rely on unsigned conversion to
|
|
|
// undo the wrapping when |T| is unsigned, but this seems clearer.
|
|
|
return IsSigned<T>::value ? WrapToSigned(aUnsigned) : aUnsigned;
|
|
|
}
|
|
|
|
|
|
- template<typename T>
|
|
|
- struct WrappingAddHelper
|
|
|
- {
|
|
|
+ template <typename T>
|
|
|
+ struct WrappingAddHelper {
|
|
|
private:
|
|
|
using UnsignedT = typename MakeUnsigned<T>::Type;
|
|
|
|
|
|
public:
|
|
|
MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
|
|
|
-- static T compute(T aX, T aY)
|
|
|
-+ static constexpr T compute(T aX, T aY)
|
|
|
- {
|
|
|
+- static T compute(T aX, T aY) {
|
|
|
++ static constexpr T compute(T aX, T aY) {
|
|
|
return ToResult<T>(static_cast<UnsignedT>(aX) + static_cast<UnsignedT>(aY));
|
|
|
}
|
|
|
};
|
|
@@ -240,7 +229,8 @@ diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
} // namespace detail
|
|
|
|
|
|
/**
|
|
|
-@@ -160,33 +147,33 @@ public:
|
|
|
+ * Add two integers of the same type and return the result converted to that
|
|
|
+@@ -154,30 +141,30 @@ public:
|
|
|
* WrappingAdd(int32_t(-42), int32_t(-17)) is -59 ((8589934533 mod 2**32) - 2**32).
|
|
|
*
|
|
|
* There's no equivalent to this operation in C++, as C++ signed addition that
|
|
@@ -248,27 +238,23 @@ diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
* behave with most compilers, unless an optimization or similar -- quite
|
|
|
* permissibly -- triggers different behavior.
|
|
|
*/
|
|
|
- template<typename T>
|
|
|
--inline T
|
|
|
-+constexpr T
|
|
|
- WrappingAdd(T aX, T aY)
|
|
|
- {
|
|
|
+ template <typename T>
|
|
|
+-inline T WrappingAdd(T aX, T aY) {
|
|
|
++constexpr T WrappingAdd(T aX, T aY) {
|
|
|
return detail::WrappingAddHelper<T>::compute(aX, aY);
|
|
|
}
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
|
- template<typename T>
|
|
|
- struct WrappingSubtractHelper
|
|
|
- {
|
|
|
+ template <typename T>
|
|
|
+ struct WrappingSubtractHelper {
|
|
|
private:
|
|
|
using UnsignedT = typename MakeUnsigned<T>::Type;
|
|
|
|
|
|
public:
|
|
|
MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
|
|
|
-- static T compute(T aX, T aY)
|
|
|
-+ static constexpr T compute(T aX, T aY)
|
|
|
- {
|
|
|
+- static T compute(T aX, T aY) {
|
|
|
++ static constexpr T compute(T aX, T aY) {
|
|
|
return ToResult<T>(static_cast<UnsignedT>(aX) - static_cast<UnsignedT>(aY));
|
|
|
}
|
|
|
};
|
|
@@ -276,7 +262,8 @@ diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
} // namespace detail
|
|
|
|
|
|
/**
|
|
|
-@@ -210,33 +197,33 @@ public:
|
|
|
+ * Subtract two integers of the same type and return the result converted to
|
|
|
+@@ -200,30 +187,30 @@ public:
|
|
|
* WrappingSubtract(int32_t(-17), int32_t(-42)) is 25 (25 mod 2**32).
|
|
|
*
|
|
|
* There's no equivalent to this operation in C++, as C++ signed subtraction
|
|
@@ -284,27 +271,23 @@ diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
* to behave with most compilers, unless an optimization or similar -- quite
|
|
|
* permissibly -- triggers different behavior.
|
|
|
*/
|
|
|
- template<typename T>
|
|
|
--inline T
|
|
|
-+constexpr T
|
|
|
- WrappingSubtract(T aX, T aY)
|
|
|
- {
|
|
|
+ template <typename T>
|
|
|
+-inline T WrappingSubtract(T aX, T aY) {
|
|
|
++constexpr T WrappingSubtract(T aX, T aY) {
|
|
|
return detail::WrappingSubtractHelper<T>::compute(aX, aY);
|
|
|
}
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
|
- template<typename T>
|
|
|
- struct WrappingMultiplyHelper
|
|
|
- {
|
|
|
- private:
|
|
|
+ template <typename T>
|
|
|
+ struct WrappingMultiplyHelper {
|
|
|
+ private:
|
|
|
using UnsignedT = typename MakeUnsigned<T>::Type;
|
|
|
|
|
|
- public:
|
|
|
+ public:
|
|
|
MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
|
|
|
-- static T compute(T aX, T aY)
|
|
|
-+ static constexpr T compute(T aX, T aY)
|
|
|
- {
|
|
|
+- static T compute(T aX, T aY) {
|
|
|
++ static constexpr T compute(T aX, T aY) {
|
|
|
// Begin with |1U| to ensure the overall operation chain is never promoted
|
|
|
// to signed integer operations that might have *signed* integer overflow.
|
|
|
return ToResult<T>(static_cast<UnsignedT>(1U *
|
|
@@ -312,7 +295,8 @@ diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
static_cast<UnsignedT>(aY)));
|
|
|
}
|
|
|
};
|
|
|
-@@ -272,17 +259,41 @@ public:
|
|
|
+
|
|
|
+@@ -259,15 +246,39 @@ struct WrappingMultiplyHelper {
|
|
|
* WrappingMultiply(int8_t(16), int8_t(255)) is -16 ((4080 mod 2**8) - 2**8).
|
|
|
*
|
|
|
* There's no equivalent to this operation in C++, as C++ signed
|
|
@@ -320,11 +304,9 @@ diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
* multiplication *tends* to behave with most compilers, unless an optimization
|
|
|
* or similar -- quite permissibly -- triggers different behavior.
|
|
|
*/
|
|
|
- template<typename T>
|
|
|
--inline T
|
|
|
-+constexpr T
|
|
|
- WrappingMultiply(T aX, T aY)
|
|
|
- {
|
|
|
+ template <typename T>
|
|
|
+-inline T WrappingMultiply(T aX, T aY) {
|
|
|
++constexpr T WrappingMultiply(T aX, T aY) {
|
|
|
return detail::WrappingMultiplyHelper<T>::compute(aX, aY);
|
|
|
}
|
|
|
|
|
@@ -355,4 +337,3 @@ diff --git a/mfbt/WrappingOperations.h b/mfbt/WrappingOperations.h
|
|
|
} /* namespace mozilla */
|
|
|
|
|
|
#endif /* mozilla_WrappingOperations_h */
|
|
|
-
|