Browse Source

Add StringHash reverse support.

Eugene Kozlov 7 years ago
parent
commit
d0ce35d194

+ 1 - 1
CMake/Modules/FindUrho3D.cmake

@@ -53,7 +53,7 @@
 #  URHO3D_STATIC_RUNTIME
 #
 
-set (AUTO_DISCOVER_VARS URHO3D_OPENGL URHO3D_D3D11 URHO3D_SSE URHO3D_DATABASE_ODBC URHO3D_DATABASE_SQLITE URHO3D_LUAJIT URHO3D_TESTING URHO3D_STATIC_RUNTIME)
+set (AUTO_DISCOVER_VARS URHO3D_OPENGL URHO3D_D3D11 URHO3D_SSE URHO3D_HASH_DEBUG URHO3D_DATABASE_ODBC URHO3D_DATABASE_SQLITE URHO3D_LUAJIT URHO3D_TESTING URHO3D_STATIC_RUNTIME)
 set (PATH_SUFFIX Urho3D)
 if (CMAKE_PROJECT_NAME STREQUAL Urho3D AND TARGET Urho3D)
     # A special case where library location is already known to be in the build tree of Urho3D project

+ 1 - 0
CMake/Modules/UrhoCommon.cmake

@@ -185,6 +185,7 @@ if (CMAKE_PROJECT_NAME STREQUAL Urho3D)
         # It is not possible to turn SSE off on 64-bit MSVC and it appears it is also not able to do so safely on 64-bit GCC
         cmake_dependent_option (URHO3D_SSE "Enable SIMD instruction set (32-bit Web and Intel platforms only, including Android on Intel Atom); default to true on Intel and false on Web platform; the effective SSE level could be higher, see also URHO3D_DEPLOYMENT_TARGET and CMAKE_OSX_DEPLOYMENT_TARGET build options" "${URHO3D_DEFAULT_SIMD}" "NOT URHO3D_64BIT" TRUE)
     endif ()
+    option (URHO3D_HASH_DEBUG "Store extra data to enable StringHash reversing and hash collision checking" FALSE)
     cmake_dependent_option (URHO3D_3DNOW "Enable 3DNow! instruction set (Linux platform only); should only be used for older CPU with (legacy) 3DNow! support" "${HAVE_3DNOW}" "X86 AND CMAKE_SYSTEM_NAME STREQUAL Linux AND NOT URHO3D_SSE" FALSE)
     cmake_dependent_option (URHO3D_MMX "Enable MMX instruction set (32-bit Linux platform only); the MMX is effectively enabled when 3DNow! or SSE is enabled; should only be used for older CPU with MMX support" "${HAVE_MMX}" "X86 AND CMAKE_SYSTEM_NAME STREQUAL Linux AND NOT URHO3D_64BIT AND NOT URHO3D_SSE AND NOT URHO3D_3DNOW" FALSE)
     # For completeness sake - this option is intentionally not documented as we do not officially support PowerPC (yet)

+ 1 - 0
CMake/Modules/exportheader.cmake.in

@@ -27,6 +27,7 @@
 #cmakedefine URHO3D_OPENGL
 #cmakedefine URHO3D_D3D11
 #cmakedefine URHO3D_SSE
+#cmakedefine URHO3D_HASH_DEBUG
 #cmakedefine URHO3D_DATABASE_ODBC
 #cmakedefine URHO3D_DATABASE_SQLITE
 #cmakedefine URHO3D_LUAJIT

+ 6 - 0
Source/Urho3D/Container/Str.h

@@ -36,6 +36,12 @@ static const int MATRIX_CONVERSION_BUFFER_LENGTH = 256;
 
 class WString;
 
+class StringHash;
+template <class T, class U> class HashMap;
+
+/// Map of strings.
+using StringMap = HashMap<StringHash, String>;
+
 /// %String class.
 class URHO3D_API String
 {

+ 88 - 0
Source/Urho3D/Math/StringHash.cpp

@@ -24,6 +24,9 @@
 
 #include "../Math/MathDefs.h"
 #include "../Math/StringHash.h"
+#include "../Container/HashMap.h"
+#include "../Core/Mutex.h"
+#include "../IO/Log.h"
 
 #include <cstdio>
 
@@ -32,16 +35,87 @@
 namespace Urho3D
 {
 
+#ifdef URHO3D_HASH_DEBUG
+
+// Expose map to let Visual Studio debugger access it if Urho3D is linked statically.
+StringMap* hashReverseMap = nullptr;
+
+// Hide static global variables in functions to ensure initialization order.
+// @{
+static Mutex& GetHashReverseMapMutex()
+{
+    static Mutex mutex;
+    return mutex;
+}
+
+static StringMap& GetHashReverseMap()
+{
+    static StringMap map;
+    hashReverseMap = &map;
+    return map;
+}
+// @}
+
+static void AddStringHash(const StringHash& hash, const char* string)
+{
+    Mutex& guard = GetHashReverseMapMutex();
+    guard.Acquire();
+
+    StringMap& map = GetHashReverseMap();
+    auto iter = map.Find(hash);
+    if (iter == map.End())
+    {
+        map.Populate(hash, string);
+    }
+    else if (iter->second_.Compare(string, false) != 0)
+    {
+        URHO3D_LOGWARNINGF("String hash collision detected! Both \"%s\" and \"%s\" have hash #%s",
+            string, iter->second_.CString(), hash.ToString().CString());
+    }
+
+    guard.Release();
+}
+
+static String ReverseStringHash(const StringHash& hash)
+{
+    Mutex& guard = GetHashReverseMapMutex();
+    guard.Acquire();
+
+    const StringMap& map = GetHashReverseMap();
+    auto iter = map.Find(hash);
+    String result = iter == map.End() ? String::EMPTY : iter->second_;
+
+    guard.Release();
+    return result;
+}
+
+#else
+
+static void AddStringHash(const StringHash& /*hash*/, const char* /*string*/)
+{
+    // Do nothing
+}
+
+static String ReverseStringHash(const StringHash& /*hash*/)
+{
+    // Do nothing
+    return String::EMPTY;
+}
+
+#endif
+
 const StringHash StringHash::ZERO;
 
 StringHash::StringHash(const char* str) noexcept :
     value_(Calculate(str))
 {
+    AddStringHash(*this, str);
 }
 
 StringHash::StringHash(const String& str) noexcept :
     value_(Calculate(str.CString()))
 {
+    AddStringHash(*this, str.CString());
 }
 
 unsigned StringHash::Calculate(const char* str, unsigned hash)
@@ -60,6 +134,15 @@ unsigned StringHash::Calculate(const char* str, unsigned hash)
     return hash;
 }
 
+const StringMap* StringHash::GetHashReverseMap()
+{
+#ifdef URHO3D_HASH_DEBUG
+    return &Urho3D::GetHashReverseMap();
+#else
+    return nullptr;
+#endif
+}
+
 String StringHash::ToString() const
 {
     char tempBuffer[CONVERSION_BUFFER_LENGTH];
@@ -67,4 +150,9 @@ String StringHash::ToString() const
     return String(tempBuffer);
 }
 
+String StringHash::Reverse() const
+{
+    return ReverseStringHash(*this);
+}
+
 }

+ 6 - 0
Source/Urho3D/Math/StringHash.h

@@ -90,12 +90,18 @@ public:
     /// Return as string.
     String ToString() const;
 
+    /// Return string which has specific hash value. Return first string if many (in order of calculation). Use for debug purposes only. Return empty string if URHO3D_HASH_DEBUG is off.
+    String Reverse() const;
+
     /// Return hash value for HashSet & HashMap.
     unsigned ToHash() const { return value_; }
 
     /// Calculate hash value case-insensitively from a C string.
     static unsigned Calculate(const char* str, unsigned hash = 0);
 
+    /// Get map of strings for each unique StringHash. Unsafe to use if new unique StringHash-es are created in other threads. Use for debug purposes only. Return nullptr if URHO3D_HASH_DEBUG is off.
+    static const StringMap* GetHashReverseMap();
+
     /// Zero hash.
     static const StringHash ZERO;