11/*
2- * Copyright 2019-2025 Diligent Graphics LLC
2+ * Copyright 2019-2026 Diligent Graphics LLC
33 * Copyright 2015-2019 Egor Yusov
44 *
55 * Licensed under the Apache License, Version 2.0 (the "License");
@@ -233,6 +233,9 @@ struct HashMapStringKey
233233 HashMapStringKey (const Char* _Str, bool bMakeCopy = false ) :
234234 Str{_Str}
235235 {
236+ #ifdef DILIGENT_DEBUG
237+ m_DbgStr = _Str != nullptr ? _Str : " " ;
238+ #endif
236239 VERIFY (Str, " String pointer must not be null" );
237240
238241 Ownership_Hash = CStringHash<Char>{}.operator ()(Str) & HashMask;
@@ -250,6 +253,9 @@ struct HashMapStringKey
250253 explicit HashMapStringKey (const String& Str, bool bMakeCopy = true ) :
251254 HashMapStringKey{Str.c_str (), bMakeCopy}
252255 {
256+ #ifdef DILIGENT_DEBUG
257+ m_DbgStr = Str;
258+ #endif
253259 }
254260
255261 HashMapStringKey (HashMapStringKey&& Key) noexcept :
@@ -260,6 +266,10 @@ struct HashMapStringKey
260266 {
261267 Key.Str = nullptr ;
262268 Key.Ownership_Hash = 0 ;
269+ #ifdef DILIGENT_DEBUG
270+ m_DbgStr = std::move (Key.m_DbgStr );
271+ Key.m_DbgStr .clear ();
272+ #endif
263273 }
264274
265275 HashMapStringKey& operator =(HashMapStringKey&& rhs) noexcept
@@ -275,6 +285,11 @@ struct HashMapStringKey
275285 rhs.Str = nullptr ;
276286 rhs.Ownership_Hash = 0 ;
277287
288+ #ifdef DILIGENT_DEBUG
289+ m_DbgStr = std::move (rhs.m_DbgStr );
290+ rhs.m_DbgStr .clear ();
291+ #endif
292+
278293 return *this ;
279294 }
280295
@@ -292,22 +307,20 @@ struct HashMapStringKey
292307
293308 HashMapStringKey Clone () const
294309 {
310+ DbgVerifyString ();
295311 return HashMapStringKey{GetStr (), (Ownership_Hash & StrOwnershipMask) != 0 };
296312 }
297313
298314 bool operator ==(const HashMapStringKey& RHS) const noexcept
299315 {
316+ DbgVerifyString ();
317+ RHS.DbgVerifyString ();
318+
300319 if (Str == RHS.Str )
301320 return true ;
302321
303- if (Str == nullptr )
304- {
305- VERIFY_EXPR (RHS.Str != nullptr );
306- return false ;
307- }
308- else if (RHS.Str == nullptr )
322+ if (Str == nullptr || RHS.Str == nullptr )
309323 {
310- VERIFY_EXPR (Str != nullptr );
311324 return false ;
312325 }
313326
@@ -324,8 +337,9 @@ struct HashMapStringKey
324337#if LOG_HASH_CONFLICTS
325338 if (!IsEqual && Hash == RHSHash)
326339 {
327- LOG_WARNING_MESSAGE (" Unequal strings \" " , Str, " \" and \" " , RHS.Str ,
328- " \" have the same hash. You may want to use a better hash function. "
340+ LOG_WARNING_MESSAGE (" Different strings \" " , Str, " \" and \" " , RHS.Str ,
341+ " \" have the same hash. This can happen occasionally; if frequent, "
342+ " consider a stronger hash or a different key strategy. "
329343 " You may disable this warning by defining LOG_HASH_CONFLICTS to 0" );
330344 }
331345#endif
@@ -344,11 +358,13 @@ struct HashMapStringKey
344358
345359 size_t GetHash () const noexcept
346360 {
361+ DbgVerifyString ();
347362 return Ownership_Hash & HashMask;
348363 }
349364
350365 const Char* GetStr () const noexcept
351366 {
367+ DbgVerifyString ();
352368 return Str;
353369 }
354370
@@ -367,6 +383,22 @@ struct HashMapStringKey
367383
368384 Str = nullptr ;
369385 Ownership_Hash = 0 ;
386+
387+ #ifdef DILIGENT_DEBUG
388+ m_DbgStr.clear ();
389+ #endif
390+ }
391+
392+ private:
393+ void DbgVerifyString () const
394+ {
395+ VERIFY (m_DbgStr == (Str != nullptr ? Str : " " ),
396+ " Debug copy does not match the current key string. "
397+ " Expected=\" " ,
398+ m_DbgStr,
399+ " \" Actual=\" " , (Str != nullptr ? Str : " <null>" ),
400+ " \" . This usually means the key was constructed without copying/owning the string and now points to "
401+ " temporary, freed, or mutated storage." );
370402 }
371403
372404protected:
@@ -377,6 +409,11 @@ struct HashMapStringKey
377409 const Char* Str = nullptr ;
378410 // We will use top bit of the hash to indicate if we own the pointer
379411 size_t Ownership_Hash = 0 ;
412+
413+ private:
414+ #ifdef DILIGENT_DEBUG
415+ std::string m_DbgStr;
416+ #endif
380417};
381418
382419
0 commit comments