Diligent Engine API Reference
HashUtils.h
1 /* Copyright 2015-2018 Egor Yusov
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
12  *
13  * In no event and under no legal theory, whether in tort (including negligence),
14  * contract, or otherwise, unless required by applicable law (such as deliberate
15  * and grossly negligent acts) or agreed to in writing, shall any Contributor be
16  * liable for any damages, including any direct, indirect, special, incidental,
17  * or consequential damages of any character arising as a result of this License or
18  * out of the use or inability to use the software (including but not limited to damages
19  * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
20  * all other commercial damages or losses), even if such Contributor has been advised
21  * of the possibility of such damages.
22  */
23 
24 #pragma once
25 
26 #include <functional>
27 #include <memory>
28 
29 #include "Errors.h"
30 
31 #define LOG_HASH_CONFLICTS 1
32 
33 namespace Diligent
34 {
35  // http://www.boost.org/doc/libs/1_35_0/doc/html/hash/combine.html
36  template<typename T>
37  void HashCombine(std::size_t &Seed, const T& Val)
38  {
39  Seed ^= std::hash<T>()(Val) + 0x9e3779b9 + (Seed << 6) + (Seed >> 2);
40  }
41 
42  template<typename FirstArgType, typename... RestArgsType>
43  void HashCombine( std::size_t &Seed, const FirstArgType& FirstArg, const RestArgsType&... RestArgs )
44  {
45  HashCombine( Seed, FirstArg );
46  HashCombine( Seed, RestArgs... ); // recursive call using pack expansion syntax
47  }
48 
49  template<typename... ArgsType>
50  std::size_t ComputeHash( const ArgsType&... Args )
51  {
52  std::size_t Seed = 0;
53  HashCombine( Seed, Args... );
54  return Seed;
55  }
56 
57  template<typename CharType>
58  struct CStringHash
59  {
60  size_t operator()( const CharType *str ) const
61  {
62  // http://www.cse.yorku.ca/~oz/hash.html
63  std::size_t Seed = 0;
64  while( size_t Ch = *(str++) )
65  Seed = Seed * 65599 + Ch;
66  return Seed;
67  }
68  };
69 
70  template<typename CharType>
71  struct CStringCompare
72  {
73  bool operator()( const CharType *str1, const CharType *str2 )const
74  {
75  UNSUPPORTED( "Template specialization is not implemented" );
76  return false;
77  }
78  };
79 
80  template<>
81  struct CStringCompare<Char>
82  {
83  bool operator()( const Char *str1, const Char *str2 )const
84  {
85  return strcmp( str1, str2 ) == 0;
86  }
87  };
88 
94  {
95  public:
96  // This constructor can perform implicit const Char* -> HashMapStringKey
97  // conversion without copying the string
98  HashMapStringKey(const Char* Str, bool bMakeCopy = false) :
99  StrPtr(nullptr),
100  Hash(0)
101  {
102  VERIFY( Str, "String pointer cannot be null" );
103  if( bMakeCopy )
104  {
105  MakeCopy( Str );
106  }
107  else
108  {
109  StrPtr = Str;
110  }
111  }
112 
113  explicit // Make this constructor explicit to avoid unintentional string copies
114  HashMapStringKey(const String &Str) :
115  StrPtr( nullptr ),
116  Hash(0)
117  {
118  MakeCopy( Str.c_str() );
119  }
120 
122  StringBuff( std::move(Key.StringBuff) ),
123  StrPtr( std::move(Key.StrPtr) ),
124  Hash(0)
125  {
126  Key.StrPtr = nullptr;
127  Key.Hash = 0;
128  }
129 
130  // Disable copy constuctor and assignments. The struct is designed
131  // to be initialized at creation time only
132  HashMapStringKey( const HashMapStringKey& ) = delete;
133  HashMapStringKey& operator = ( const HashMapStringKey& ) = delete;
134  HashMapStringKey& operator = ( HashMapStringKey&& ) = delete;
135 
136  // Comparison operator
137  bool operator == (const HashMapStringKey& RHS)const
138  {
139  if( StrPtr == RHS.StrPtr )
140  return true;
141 
142  // Hash member might not have been initialized
143  if( (Hash != 0 && RHS.Hash !=0 && Hash != RHS.Hash) || StrPtr == nullptr || RHS.StrPtr == nullptr )
144  return false;
145 
146  bool IsEqual = strcmp( StrPtr, RHS.StrPtr ) == 0;
147 
148 #if LOG_HASH_CONFLICTS
149  if( Hash != 0 && RHS.Hash !=0 && Hash == RHS.Hash && !IsEqual )
150  {
151  LOG_WARNING_MESSAGE("Unequal strings \"", StrPtr, "\" and \"", RHS.StrPtr, "\" hashed to the same bucket. "
152  "You may want to use better hash function. You may disable this warning by defining LOG_HASH_CONFLICTS to 0");
153  }
154 #endif
155  return IsEqual;
156  }
157 
158  size_t GetHash()const
159  {
160  if( Hash == 0 )
161  Hash = CStringHash<Char>()(StrPtr);
162 
163  return Hash;
164  }
165 
166  const Char* GetStr()const{ return StrPtr; }
167 
168  private:
169  void MakeCopy( const Char* Str )
170  {
171  auto LenWithZeroTerm = strlen( Str ) + 1;
172  StringBuff.reset( new char[ LenWithZeroTerm ] );
173  memcpy( StringBuff.get(), Str, LenWithZeroTerm );
174  StrPtr = StringBuff.get();
175  }
176 
177  // !!! WARNING !!!
178  // We can't use String to store the buffer, because String default
179  // constructor always allocates memory even when the string is empty,
180  // nor can we use vector for the same reason
181  std::unique_ptr< Char[] > StringBuff; // Must be declared first
182  const Char* StrPtr;// Must be declared after StringBuff
183  mutable size_t Hash;
184  };
185 }
186 
187 namespace std
188 {
189  template<>
190  struct hash<Diligent::HashMapStringKey>
191  {
192  size_t operator()( const Diligent::HashMapStringKey &Key ) const
193  {
194  return Key.GetHash();
195  }
196  };
197 }
Namespace for the OpenGL implementation of the graphics engine.
Definition: BufferD3D11Impl.h:34
Definition: AdvancedMath.h:316
This helper structure is intended to facilitate using strings as a hash table key. It provides constructors that can make a copy of the source string or just keep pointer to it, which enables searching in the hash using raw const Char* pointers.
Definition: HashUtils.h:93