Diligent Engine  v.2.4.g
HashUtils.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2021 Diligent Graphics LLC
3  * Copyright 2015-2019 Egor Yusov
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * In no event and under no legal theory, whether in tort (including negligence),
18  * contract, or otherwise, unless required by applicable law (such as deliberate
19  * and grossly negligent acts) or agreed to in writing, shall any Contributor be
20  * liable for any damages, including any direct, indirect, special, incidental,
21  * or consequential damages of any character arising as a result of this License or
22  * out of the use or inability to use the software (including but not limited to damages
23  * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
24  * all other commercial damages or losses), even if such Contributor has been advised
25  * of the possibility of such damages.
26  */
27 
28 #pragma once
29 
30 #include <functional>
31 #include <memory>
32 #include <cstring>
33 
34 #include "../../Primitives/interface/Errors.hpp"
35 #include "../../Platforms/Basic/interface/DebugUtilities.hpp"
36 
37 #define LOG_HASH_CONFLICTS 1
38 
39 namespace Diligent
40 {
41 
42 // http://www.boost.org/doc/libs/1_35_0/doc/html/hash/combine.html
43 template <typename T>
44 void HashCombine(std::size_t& Seed, const T& Val)
45 {
46  Seed ^= std::hash<T>{}(Val) + 0x9e3779b9 + (Seed << 6) + (Seed >> 2);
47 }
48 
49 template <typename FirstArgType, typename... RestArgsType>
50 void HashCombine(std::size_t& Seed, const FirstArgType& FirstArg, const RestArgsType&... RestArgs)
51 {
52  HashCombine(Seed, FirstArg);
53  HashCombine(Seed, RestArgs...); // recursive call using pack expansion syntax
54 }
55 
56 template <typename... ArgsType>
57 std::size_t ComputeHash(const ArgsType&... Args)
58 {
59  std::size_t Seed = 0;
60  HashCombine(Seed, Args...);
61  return Seed;
62 }
63 
64 template <typename CharType>
66 {
67  size_t operator()(const CharType* str) const
68  {
69  // http://www.cse.yorku.ca/~oz/hash.html
70  std::size_t Seed = 0;
71  while (size_t Ch = *(str++))
72  Seed = Seed * 65599 + Ch;
73  return Seed;
74  }
75 };
76 
77 template <typename CharType>
79 {
80  bool operator()(const CharType* str1, const CharType* str2) const
81  {
82  UNSUPPORTED("Template specialization is not implemented");
83  return false;
84  }
85 };
86 
87 template <>
89 {
90  bool operator()(const Char* str1, const Char* str2) const
91  {
92  return strcmp(str1, str2) == 0;
93  }
94 };
95 
101 {
102 public:
103  // This constructor can perform implicit const Char* -> HashMapStringKey
104  // conversion without copying the string.
105  HashMapStringKey(const Char* _Str, bool bMakeCopy = false) :
106  Str{_Str}
107  {
108  VERIFY(Str, "String pointer must not be null");
109 
110  Ownership_Hash = CStringHash<Char>{}.operator()(Str) & HashMask;
111  if (bMakeCopy)
112  {
113  auto LenWithZeroTerm = strlen(Str) + 1;
114  auto* StrCopy = new char[LenWithZeroTerm];
115  memcpy(StrCopy, Str, LenWithZeroTerm);
116  Str = StrCopy;
118  }
119  }
120 
121  // Make this constructor explicit to avoid unintentional string copies
122  explicit HashMapStringKey(const String& Str) :
123  HashMapStringKey{Str.c_str(), true}
124  {
125  }
126 
128  // clang-format off
129  Str {Key.Str},
130  Ownership_Hash{Key.Ownership_Hash}
131  // clang-format on
132  {
133  Key.Str = nullptr;
134  Key.Ownership_Hash = 0;
135  }
136 
138  {
139  if (Str != nullptr && (Ownership_Hash & StrOwnershipMask) != 0)
140  delete[] Str;
141  }
142 
143  // Disable copy constuctor and assignments. The struct is designed
144  // to be initialized at creation time only.
145  // clang-format off
146  HashMapStringKey (const HashMapStringKey&) = delete;
147  HashMapStringKey& operator=(const HashMapStringKey&) = delete;
149  // clang-format on
150 
151  bool operator==(const HashMapStringKey& RHS) const
152  {
153  if (Str == RHS.Str)
154  return true;
155 
156  if (Str == nullptr)
157  {
158  VERIFY_EXPR(RHS.Str != nullptr);
159  return false;
160  }
161  else if (RHS.Str == nullptr)
162  {
163  VERIFY_EXPR(Str != nullptr);
164  return false;
165  }
166 
167  auto Hash = GetHash();
168  auto RHSHash = RHS.GetHash();
169  if (Hash != RHSHash)
170  {
171  VERIFY_EXPR(strcmp(Str, RHS.Str) != 0);
172  return false;
173  }
174 
175  bool IsEqual = strcmp(Str, RHS.Str) == 0;
176 
177 #if LOG_HASH_CONFLICTS
178  if (!IsEqual && Hash == RHSHash)
179  {
180  LOG_WARNING_MESSAGE("Unequal strings \"", Str, "\" and \"", RHS.Str,
181  "\" have the same hash. You may want to use a better hash function. "
182  "You may disable this warning by defining LOG_HASH_CONFLICTS to 0");
183  }
184 #endif
185  return IsEqual;
186  }
187 
188  bool operator!=(const HashMapStringKey& RHS) const
189  {
190  return !(*this == RHS);
191  }
192 
193  size_t GetHash() const
194  {
195  return Ownership_Hash & HashMask;
196  }
197 
198  const Char* GetStr() const
199  {
200  return Str;
201  }
202 
203  struct Hasher
204  {
205  size_t operator()(const HashMapStringKey& Key) const
206  {
207  return Key.GetHash();
208  }
209  };
210 
211 protected:
212  static constexpr size_t StrOwnershipBit = sizeof(size_t) * 8 - 1;
213  static constexpr size_t StrOwnershipMask = size_t{1} << StrOwnershipBit;
214  static constexpr size_t HashMask = ~StrOwnershipMask;
215 
216  const Char* Str = nullptr;
217  // We will use top bit of the hash to indicate if we own the pointer
218  size_t Ownership_Hash = 0;
219 };
220 
221 } // namespace Diligent
Diligent::HashMapStringKey::operator=
HashMapStringKey & operator=(const HashMapStringKey &)=delete
Diligent::Char
char Char
Definition: BasicTypes.h:64
Diligent::CStringHash
Definition: HashUtils.hpp:65
Diligent::HashMapStringKey::Str
const Char * Str
Definition: HashUtils.hpp:216
Diligent::HashMapStringKey::Hasher::operator()
size_t operator()(const HashMapStringKey &Key) const
Definition: HashUtils.hpp:205
Diligent::CStringCompare::operator()
bool operator()(const CharType *str1, const CharType *str2) const
Definition: HashUtils.hpp:80
Diligent::HashMapStringKey::HashMapStringKey
HashMapStringKey(HashMapStringKey &&Key) noexcept
Definition: HashUtils.hpp:127
Diligent::HashMapStringKey::operator!=
bool operator!=(const HashMapStringKey &RHS) const
Definition: HashUtils.hpp:188
UNSUPPORTED
#define UNSUPPORTED(...)
Definition: DebugUtilities.hpp:78
Diligent::HashMapStringKey::operator==
bool operator==(const HashMapStringKey &RHS) const
Definition: HashUtils.hpp:151
Diligent::CStringHash::operator()
size_t operator()(const CharType *str) const
Definition: HashUtils.hpp:67
Diligent::HashMapStringKey::GetStr
const Char * GetStr() const
Definition: HashUtils.hpp:198
Diligent::HashMapStringKey::~HashMapStringKey
~HashMapStringKey()
Definition: HashUtils.hpp:137
Diligent::CStringCompare
Definition: HashUtils.hpp:78
Diligent::ComputeHash
std::size_t ComputeHash(const ArgsType &... Args)
Definition: HashUtils.hpp:57
Diligent::HashMapStringKey::HashMapStringKey
HashMapStringKey(const String &Str)
Definition: HashUtils.hpp:122
LOG_WARNING_MESSAGE
#define LOG_WARNING_MESSAGE(...)
Definition: Errors.hpp:123
Diligent::HashMapStringKey
This helper structure is intended to facilitate using strings as a hash table key....
Definition: HashUtils.hpp:100
Diligent::String
std::basic_string< Char > String
String variable.
Definition: BasicTypes.h:66
VERIFY_EXPR
#define VERIFY_EXPR(...)
Definition: DebugUtilities.hpp:79
VERIFY
#define VERIFY(...)
Definition: DebugUtilities.hpp:76
Diligent::HashMapStringKey::StrOwnershipMask
static constexpr size_t StrOwnershipMask
Definition: HashUtils.hpp:213
Diligent::HashMapStringKey::Ownership_Hash
size_t Ownership_Hash
Definition: HashUtils.hpp:218
Diligent::HashMapStringKey::HashMapStringKey
HashMapStringKey(const Char *_Str, bool bMakeCopy=false)
Definition: HashUtils.hpp:105
Diligent::HashMapStringKey::HashMask
static constexpr size_t HashMask
Definition: HashUtils.hpp:214
Diligent::HashMapStringKey::Hasher
Definition: HashUtils.hpp:203
Diligent::HashCombine
void HashCombine(std::size_t &Seed, const T &Val)
Definition: HashUtils.hpp:44
Diligent::HashMapStringKey::StrOwnershipBit
static constexpr size_t StrOwnershipBit
Definition: HashUtils.hpp:212
Diligent::CStringCompare< Char >::operator()
bool operator()(const Char *str1, const Char *str2) const
Definition: HashUtils.hpp:90
Diligent::HashMapStringKey::GetHash
size_t GetHash() const
Definition: HashUtils.hpp:193
Diligent
The library uses Direct3D-style math:
Definition: AdvancedMath.hpp:37