0030720: Coding - fix HashCode() function problems that are not resolved with 30550
authortiv <tiv@opencascade.com>
Tue, 24 Sep 2019 13:42:21 +0000 (16:42 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 25 Sep 2019 12:58:08 +0000 (15:58 +0300)
Undefined behavior caused by left shift operations in TopLoc_Location::HashCode() function is fixed.
HashCode() function overload for Standard_Size type is made available only if Standard_Size and "unsigned int" are different types (it is usually true for 64-bit platforms). The overload for "unsigned int" is made simple non-templated function (so it behaves the same on 32-bit and 64-bit platforms).
HashCode() function overload for Standard_Utf32Char type is made available only if Standard_Utf32Char and "unsigned int" are different types (it is needed for some old compilers).

src/Standard/Standard_Integer.hxx
src/Standard/Standard_Size.hxx
src/TopLoc/TopLoc_Location.cxx

index 29a792b..9858ce7 100755 (executable)
@@ -130,18 +130,12 @@ inline Standard_Boolean IsEqual (const Standard_Integer theOne,
 }
 
 //! Computes a hash value for the given unsigned integer, in range [1, theUpperBound]
-//! @tparam TheUnsignedInteger the type of the given value (it is "unsigned int",
-//! and must not be the same as Standard_Size, because the overload of the HashCode function
-//! for Standard_Size type is already presented in Standard_Size.hxx)
 //! @param theValue the unsigned integer which hash code is to be computed
+//! @param theUpperBound the upper bound of the range a computing hash code must be within
 //! @return a hash value computed for the given unsigned integer, in range [1, theUpperBound]
-template <typename TheUnsignedInteger>
-typename opencascade::std::enable_if<!opencascade::std::is_same<Standard_Size, unsigned int>::value
-                                       && opencascade::std::is_same<TheUnsignedInteger, unsigned int>::value,
-                                     Standard_Integer>::type
-HashCode (const TheUnsignedInteger theValue, const Standard_Integer theUpperBound)
+inline Standard_Integer HashCode (const unsigned int theValue, const Standard_Integer theUpperBound)
 {
-  return HashCode (static_cast<Standard_Integer> (theValue), theUpperBound);
+  return ::HashCode (static_cast<Standard_Integer> (theValue), theUpperBound);
 }
 
 //! Computes a hash code for the given value of the "long long int" type, in range [1, theUpperBound]
@@ -155,14 +149,20 @@ inline Standard_Integer HashCode (const long long int theValue, const Standard_I
 
 #if (defined(_LP64) || defined(__LP64__) || defined(_WIN64)) || defined(__APPLE__)
 
-//! Computes a hash code for the given value of the Standard_Utf32Char type, in range [1, theUpperBound]
+//! Computes a hash code for the given value of the Standard_Utf32Char type, in the range [1, theUpperBound]
+//! @tparam TheUtf32Char the type of the given value (it is Standard_Utf32Char,
+//! and must not be the same as "unsigned int", because the overload of the HashCode function
+//! for "unsigned int" type is already presented in Standard_Integer.hxx)
 //! @param theValue the value of the Standard_Utf32Char type which hash code is to be computed
 //! @param theUpperBound the upper bound of the range a computing hash code must be within
-//! @return a computed hash code, in range [1, theUpperBound]
-inline Standard_Integer HashCode (const Standard_Utf32Char theValue,
-                                  const Standard_Integer   theUpperBound)
+//! @return a computed hash code, in the range [1, theUpperBound]
+template <typename TheUtf32Char>
+typename opencascade::std::enable_if<!opencascade::std::is_same<Standard_Utf32Char, unsigned int>::value
+                                       && opencascade::std::is_same<TheUtf32Char, Standard_Utf32Char>::value,
+                                     Standard_Integer>::type
+HashCode (const TheUtf32Char theValue, const Standard_Integer theUpperBound)
 {
-  return IntegerHashCode(theValue, IntegerLast(), theUpperBound);
+  return IntegerHashCode (theValue, IntegerLast(), theUpperBound);
 }
 
 // ------------------------------------------------------------------
index 2c23819..e8d8e8d 100644 (file)
 // msv 26.05.2009: add HashCode and IsEqual functions
 
 //! Computes a hash code for the given value of the Standard_Size type, in the range [1, theUpperBound]
+//! @tparam TheSize the type of the given value (it is Standard_Size,
+//! and must not be the same as "unsigned int", because the overload of the HashCode function
+//! for "unsigned int" type is already presented in Standard_Integer.hxx)
 //! @param theValue the value of the Standard_Size type which hash code is to be computed
 //! @param theUpperBound the upper bound of the range a computing hash code must be within
 //! @return a computed hash code, in the range [1, theUpperBound]
-inline Standard_Integer HashCode (const Standard_Size theValue, const Standard_Integer theUpperBound)
+template <typename TheSize>
+typename opencascade::std::enable_if<!opencascade::std::is_same<Standard_Size, unsigned int>::value
+                                       && opencascade::std::is_same<TheSize, Standard_Size>::value,
+                                     Standard_Integer>::type
+HashCode (const TheSize theValue, const Standard_Integer theUpperBound)
 {
   Standard_Size aKey = ~theValue + (theValue << 18);
   aKey ^= (aKey >> 31);
index 4033b4c..0ba8e7f 100644 (file)
@@ -192,9 +192,10 @@ Standard_Integer TopLoc_Location::HashCode (const Standard_Integer theUpperBound
   while (items.More())
   {
     depth += 3;
-    unsigned int i = ::HashCode (items.Value().myDatum, theUpperBound);
-    unsigned int j = ((i + items.Value().myPower) << depth);
-    j              = j >> (32 - depth) | j << depth;
+    unsigned int           i             = ::HashCode (items.Value().myDatum, theUpperBound);
+    const Standard_Integer aClampedDepth = depth % 32;
+    unsigned int           j             = ((i + items.Value().myPower) << aClampedDepth);
+    j                                    = j >> (32 - aClampedDepth) | j << aClampedDepth;
     h ^= j;
     items.Next ();
   }