1919#include < map>
2020#include < mutex>
2121#include < string>
22- #include < string_view>
2322#include < unordered_map>
2423#include < unordered_set>
2524#include < utility>
@@ -29,59 +28,79 @@ extern CGameSA* pGame;
2928
3029namespace TextureIndex
3130{
31+ inline std::size_t ComputeLength (const char * value) noexcept
32+ {
33+ if (!value)
34+ return 0 ;
35+
36+ std::size_t result = 0 ;
37+ while (result < RW_TEXTURE_NAME_LENGTH && value[result] != ' \0 ' )
38+ ++result;
39+ return result;
40+ }
41+
3242 struct Name
3343 {
3444 std::array<char , RW_TEXTURE_NAME_LENGTH + 1 > data{};
3545 std::size_t length = 0 ;
3646
37- void Assign (std::string_view value ) noexcept
47+ void Assign (const char * value, std::size_t valueLength ) noexcept
3848 {
39- const std::size_t copyLength = std::min<std::size_t >(value. size () , RW_TEXTURE_NAME_LENGTH);
40- if (copyLength > 0 )
41- std::memmove (data.data (), value. data () , copyLength);
49+ const std::size_t copyLength = std::min<std::size_t >(valueLength , RW_TEXTURE_NAME_LENGTH);
50+ if (copyLength > 0 && value )
51+ std::memmove (data.data (), value, copyLength);
4252 if (copyLength < data.size ())
4353 std::fill (data.begin () + copyLength, data.end (), ' \0 ' );
4454 length = copyLength;
4555 }
4656
47- [[nodiscard]] std::string_view View () const noexcept { return std::string_view (data.data (), length); }
57+ void Assign (const char * value) noexcept
58+ {
59+ Assign (value, ComputeLength (value));
60+ }
4861
49- [[nodiscard]] const char * CStr () const noexcept { return data.data (); }
62+ void Assign (const std::string& value) noexcept
63+ {
64+ Assign (value.c_str (), value.size ());
65+ }
66+
67+ const char * CStr () const noexcept { return data.data (); }
5068
51- [[nodiscard]] bool Empty () const noexcept { return length == 0 ; }
69+ std::size_t Length () const noexcept { return length; }
70+
71+ bool Empty () const noexcept { return length == 0 ; }
5272 };
5373
54- [[nodiscard]] inline char ToLowerAscii (char ch) noexcept
74+ inline char ToLowerAscii (char ch) noexcept
5575 {
5676 return static_cast <char >(std::tolower (static_cast <unsigned char >(ch)));
5777 }
5878
59- [[nodiscard]] inline std::string_view ToView (const Name& value) noexcept
60- {
61- return value.View ();
62- }
63- [[nodiscard]] inline std::string_view ToView (const std::string& value) noexcept
79+ inline bool IsEqualCanonical (const char * lhs, std::size_t lhsLength, const char * rhs, std::size_t rhsLength) noexcept
6480 {
65- return value;
66- }
67- [[nodiscard]] inline std::string_view ToView (std::string_view value) noexcept
68- {
69- return value;
70- }
71- [[nodiscard]] inline std::string_view ToView ( const char * value) noexcept
72- {
73- return value ? std::string_view (value) : std::string_view () ;
81+ if (lhsLength != rhsLength)
82+ return false ;
83+
84+ for (std:: size_t idx = 0 ; idx < lhsLength; ++idx)
85+ {
86+ if ( ToLowerAscii (lhs[idx]) != ToLowerAscii (rhs[idx]))
87+ return false ;
88+ }
89+ return true ;
7490 }
7591
76- [[nodiscard]] inline std::size_t HashCanonical (std::string_view view ) noexcept
92+ inline std::size_t HashCanonical (const char * data, std::size_t length ) noexcept
7793 {
7894 constexpr std::size_t kFnvOffset = 2166136261u ;
7995 constexpr std::size_t kFnvPrime = 16777619u ;
8096
8197 std::size_t hash = kFnvOffset ;
82- for (char ch : view)
98+ if (!data)
99+ return hash;
100+
101+ for (std::size_t idx = 0 ; idx < length; ++idx)
83102 {
84- hash ^= static_cast <unsigned char >(ToLowerAscii (ch ));
103+ hash ^= static_cast <unsigned char >(ToLowerAscii (data[idx] ));
85104 hash *= kFnvPrime ;
86105 }
87106 return hash;
@@ -91,32 +110,49 @@ namespace TextureIndex
91110 {
92111 using is_transparent = void ;
93112
94- template <typename T>
95- std::size_t operator ()(const T& value) const noexcept
113+ std::size_t operator ()(const Name& value) const noexcept
114+ {
115+ return HashCanonical (value.CStr (), value.Length ());
116+ }
117+
118+ std::size_t operator ()(const char * value) const noexcept
119+ {
120+ return HashCanonical (value, ComputeLength (value));
121+ }
122+
123+ std::size_t operator ()(const std::string& value) const noexcept
96124 {
97- return HashCanonical (ToView ( value));
125+ return HashCanonical (value. c_str (), value. size ( ));
98126 }
99127 };
100128
101129 struct Equal
102130 {
103131 using is_transparent = void ;
104132
105- template <typename LHS, typename RHS>
106- bool operator ()(const LHS& lhs, const RHS& rhs) const noexcept
133+ bool operator ()(const Name& lhs, const Name& rhs) const noexcept
107134 {
108- const std::string_view lhsView = ToView (lhs );
109- const std::string_view rhsView = ToView (rhs);
135+ return IsEqualCanonical (lhs. CStr (), lhs. Length (), rhs. CStr (), rhs. Length () );
136+ }
110137
111- if (lhsView.size () != rhsView.size ())
112- return false ;
138+ bool operator ()(const Name& lhs, const char * rhs) const noexcept
139+ {
140+ return IsEqualCanonical (lhs.CStr (), lhs.Length (), rhs, ComputeLength (rhs));
141+ }
113142
114- for (std::size_t idx = 0 ; idx < lhsView.size (); ++idx)
115- {
116- if (ToLowerAscii (lhsView[idx]) != ToLowerAscii (rhsView[idx]))
117- return false ;
118- }
119- return true ;
143+ bool operator ()(const char * lhs, const Name& rhs) const noexcept
144+ {
145+ return IsEqualCanonical (lhs, ComputeLength (lhs), rhs.CStr (), rhs.Length ());
146+ }
147+
148+ bool operator ()(const std::string& lhs, const Name& rhs) const noexcept
149+ {
150+ return IsEqualCanonical (lhs.c_str (), lhs.size (), rhs.CStr (), rhs.Length ());
151+ }
152+
153+ bool operator ()(const Name& lhs, const std::string& rhs) const noexcept
154+ {
155+ return IsEqualCanonical (lhs.CStr (), lhs.Length (), rhs.c_str (), rhs.size ());
120156 }
121157 };
122158} // namespace TextureIndex
@@ -296,9 +332,9 @@ namespace
296332 perTxdInfo.usTxdId = txdId;
297333 perTxdInfo.bTexturesAreCopies = (replacementTextures.usedInTxdIdLookup .size () > 1 );
298334
299- auto [indexInsertIt, indexInserted] = replacementTextures.perTxdIndexLookup .emplace (txdId, newIndex);
300- if (!indexInserted )
301- indexInsertIt ->second = newIndex;
335+ auto indexInsertResult = replacementTextures.perTxdIndexLookup .emplace (txdId, newIndex);
336+ if (!indexInsertResult. second )
337+ indexInsertResult. first ->second = newIndex;
302338
303339 isNewEntry = true ;
304340 return &perTxdInfo;
@@ -316,8 +352,10 @@ namespace
316352 dassert (replacementTextures.usedInTxdIdLookup .find (txdId) != replacementTextures.usedInTxdIdLookup .end ());
317353
318354 dassert (replacementTextures.perTxdIndexLookup .size () == replacementTextures.perTxdList .size ());
319- for (const auto & [txdId, index] : replacementTextures.perTxdIndexLookup )
355+ for (const auto & pair : replacementTextures.perTxdIndexLookup )
320356 {
357+ const ushort txdId = pair.first ;
358+ const std::size_t index = pair.second ;
321359 dassert (index < replacementTextures.perTxdList .size ());
322360 dassert (replacementTextures.perTxdList [index].usTxdId == txdId);
323361 }
@@ -340,17 +378,17 @@ namespace
340378 }
341379 }
342380
343- [[nodiscard]] inline bool IsValidTexDictionary (const RwTexDictionary* const pTxd)
381+ inline bool IsValidTexDictionary (const RwTexDictionary* const pTxd)
344382 {
345383 return pTxd && SharedUtil::IsReadablePointer (pTxd, sizeof (*pTxd));
346384 }
347385
348- [[nodiscard]] inline bool IsValidTexturePtr (const RwTexture* const pTexture)
386+ inline bool IsValidTexturePtr (const RwTexture* const pTexture)
349387 {
350388 return pTexture && SharedUtil::IsReadablePointer (pTexture, sizeof (*pTexture));
351389 }
352390
353- [[nodiscard]] size_t GetTextureNameLength (const RwTexture* const pTexture)
391+ size_t GetTextureNameLength (const RwTexture* const pTexture)
354392 {
355393 if (!pTexture)
356394 return 0 ;
@@ -361,28 +399,22 @@ namespace
361399 return length;
362400 }
363401
364- [[nodiscard]] std::string_view GetTextureNameView (const RwTexture* const pTexture)
365- {
366- if (!pTexture)
367- return {};
368-
369- const size_t length = GetTextureNameLength (pTexture);
370- return std::string_view (pTexture->name , length);
371- }
372-
373402 TextureIndex::Name ExtractTextureName (const RwTexture* pTexture)
374403 {
375404 TextureIndex::Name name;
376- name.Assign (GetTextureNameView (pTexture));
405+ if (pTexture)
406+ name.Assign (pTexture->name , GetTextureNameLength (pTexture));
377407 return name;
378408 }
379409
380- RwTexture* LookupOriginalTexture (CModelTexturesInfo& info, std::string_view name)
410+ RwTexture* LookupOriginalTexture (CModelTexturesInfo& info, const char * name)
381411 {
382- if (name. empty () )
412+ if (! name || name[ 0 ] == ' \0 ' )
383413 return nullptr ;
384414
385- auto it = info.originalTextureIndex .find (name);
415+ TextureIndex::Name lookupKey;
416+ lookupKey.Assign (name);
417+ auto it = info.originalTextureIndex .find (lookupKey);
386418 if (it == info.originalTextureIndex .end ())
387419 return nullptr ;
388420
@@ -413,12 +445,12 @@ namespace
413445 RebuildOriginalLookup (info);
414446 }
415447
416- RwTexture* ResolveOriginalTexture (CModelTexturesInfo& info, RwTexDictionary* pTxd, RwTexture* pCandidate, std::string_view replacementName)
448+ RwTexture* ResolveOriginalTexture (CModelTexturesInfo& info, RwTexDictionary* pTxd, RwTexture* pCandidate, const char * replacementName)
417449 {
418450 if (IsValidTexturePtr (pCandidate))
419451 return pCandidate;
420452
421- if (replacementName. empty () )
453+ if (! replacementName || replacementName[ 0 ] == ' \0 ' )
422454 return nullptr ;
423455
424456 const bool canReload = IsValidTexDictionary (pTxd);
@@ -435,14 +467,17 @@ namespace
435467 return IsValidTexturePtr (record.texture ) ? record.texture : nullptr ;
436468 };
437469
438- auto mapIt = info.originalTextureIndex .find (replacementName);
470+ TextureIndex::Name replacementKey;
471+ replacementKey.Assign (replacementName);
472+
473+ auto mapIt = info.originalTextureIndex .find (replacementKey);
439474 if (mapIt != info.originalTextureIndex .end ())
440475 {
441476 if (RwTexture* resolved = tryResolve (mapIt->second ))
442477 return resolved;
443478
444479 RebuildOriginalLookup (info);
445- mapIt = info.originalTextureIndex .find (replacementName );
480+ mapIt = info.originalTextureIndex .find (replacementKey );
446481 if (mapIt != info.originalTextureIndex .end ())
447482 {
448483 if (RwTexture* resolved = tryResolve (mapIt->second ))
@@ -501,7 +536,9 @@ namespace
501536 if (!IsValidTexturePtr (pReplacementTexture) || !IsValidTexturePtr (pOriginalTexture))
502537 continue ;
503538
504- swapMap.insert_or_assign (pOriginalTexture, pReplacementTexture);
539+ auto insertResult = swapMap.insert (std::make_pair (pOriginalTexture, pReplacementTexture));
540+ if (!insertResult.second )
541+ insertResult.first ->second = pReplacementTexture;
505542 }
506543
507544 return !swapMap.empty ();
@@ -518,11 +555,13 @@ namespace
518555 if (!IsValidTexturePtr (pOldTexture))
519556 continue ;
520557
521- RwTexture* pOriginalTexture = (idx < perTxdInfo.replacedOriginals .size ()) ? perTxdInfo.replacedOriginals [idx] : nullptr ;
522- const std::string_view replacementName = GetTextureNameView ( pOldTexture) ;
523- RwTexture* pResolvedOriginal = ResolveOriginalTexture (info, pTxd, pOriginalTexture, replacementName);
558+ RwTexture* pOriginalTexture = (idx < perTxdInfo.replacedOriginals .size ()) ? perTxdInfo.replacedOriginals [idx] : nullptr ;
559+ const char * replacementName = pOldTexture ? pOldTexture-> name : nullptr ;
560+ RwTexture* pResolvedOriginal = ResolveOriginalTexture (info, pTxd, pOriginalTexture, replacementName);
524561
525- swapMap.insert_or_assign (pOldTexture, pResolvedOriginal);
562+ auto insertResult = swapMap.insert (std::make_pair (pOldTexture, pResolvedOriginal));
563+ if (!insertResult.second )
564+ insertResult.first ->second = pResolvedOriginal;
526565
527566 if (pResolvedOriginal && !CRenderWareSA::RwTexDictionaryContainsTexture (pTxd, pResolvedOriginal))
528567 {
@@ -669,8 +708,8 @@ ModelTexturesInfoGuard AcquireModelTexturesInfo(ushort usModelId)
669708 }
670709 }
671710
672- auto [insertIt, inserted] = ms_ModelTexturesInfoMap.emplace (usTxdId, CModelTexturesInfo ());
673- guard.info = &insertIt ->second ;
711+ auto insertResult = ms_ModelTexturesInfoMap.emplace (usTxdId, CModelTexturesInfo ());
712+ guard.info = &insertResult. first ->second ;
674713
675714 guard.info ->usTxdId = usTxdId;
676715 guard.info ->pTxd = pTxd;
@@ -845,10 +884,10 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
845884 dassert (bHasValidTxd);
846885 for (RwTexture* pNewTexture : pPerTxdInfo->usingTextures )
847886 {
848- const std::string_view replacementName = GetTextureNameView ( pNewTexture) ;
887+ const char * replacementName = pNewTexture ? pNewTexture-> name : nullptr ;
849888
850889 RwTexture* pExistingTexture = LookupOriginalTexture (*pInfo, replacementName);
851- if (!pExistingTexture && bHasValidTxd && ! replacementName. empty () )
890+ if (!pExistingTexture && bHasValidTxd && replacementName && replacementName[ 0 ] != ' \0 ' )
852891 pExistingTexture = RwTexDictionaryFindNamedTexture (pInfo->pTxd , pNewTexture->name );
853892
854893 if (pExistingTexture && bHasValidTxd)
0 commit comments