From: tiv Date: Tue, 24 Sep 2019 13:42:21 +0000 (+0300) Subject: 0030720: Coding - fix HashCode() function problems that are not resolved with 30550 X-Git-Tag: V7_4_0~10 X-Git-Url: http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff_plain;h=467e864adf5f2f27cc1b6b6e88b8a2cf7ce86783 0030720: Coding - fix HashCode() function problems that are not resolved with 30550 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). --- diff --git a/src/Standard/Standard_Integer.hxx b/src/Standard/Standard_Integer.hxx index 29a792b354..9858ce7f41 100755 --- a/src/Standard/Standard_Integer.hxx +++ b/src/Standard/Standard_Integer.hxx @@ -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 opencascade::std::enable_if::value - && opencascade::std::is_same::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 (theValue), theUpperBound); + return ::HashCode (static_cast (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 opencascade::std::enable_if::value + && opencascade::std::is_same::value, + Standard_Integer>::type +HashCode (const TheUtf32Char theValue, const Standard_Integer theUpperBound) { - return IntegerHashCode(theValue, IntegerLast(), theUpperBound); + return IntegerHashCode (theValue, IntegerLast(), theUpperBound); } // ------------------------------------------------------------------ diff --git a/src/Standard/Standard_Size.hxx b/src/Standard/Standard_Size.hxx index 2c23819876..e8d8e8d4ef 100644 --- a/src/Standard/Standard_Size.hxx +++ b/src/Standard/Standard_Size.hxx @@ -21,10 +21,17 @@ // 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 opencascade::std::enable_if::value + && opencascade::std::is_same::value, + Standard_Integer>::type +HashCode (const TheSize theValue, const Standard_Integer theUpperBound) { Standard_Size aKey = ~theValue + (theValue << 18); aKey ^= (aKey >> 31); diff --git a/src/TopLoc/TopLoc_Location.cxx b/src/TopLoc/TopLoc_Location.cxx index 4033b4c3e9..0ba8e7ffff 100644 --- a/src/TopLoc/TopLoc_Location.cxx +++ b/src/TopLoc/TopLoc_Location.cxx @@ -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 (); }