123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- /*******************************************************************************
- The content of this file includes portions of the AUDIOKINETIC Wwise Technology
- released in source code form as part of the SDK installer package.
- Commercial License Usage
- Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
- may use this file in accordance with the end user license agreement provided
- with the software or, alternatively, in accordance with the terms contained in a
- written agreement between you and Audiokinetic Inc.
- Apache License Usage
- Alternatively, this file may be used under the Apache License, Version 2.0 (the
- "Apache License"); you may not use this file except in compliance with the
- Apache License. You may obtain a copy of the Apache License at
- http://www.apache.org/licenses/LICENSE-2.0.
- Unless required by applicable law or agreed to in writing, software distributed
- under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
- OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
- the specific language governing permissions and limitations under the License.
- Copyright (c) 2023 Audiokinetic Inc.
- *******************************************************************************/
- #pragma once
- #include <AK/Tools/Common/AkFNVHash.h>
- #include <AK/Tools/Common/AkHashList.h>
- template<typename TAlloc, typename T_CHAR>
- class AkStringData : public TAlloc
- {
- public:
- AkStringData() : pStr(NULL), bOwner(false) {}
- AkStringData(const T_CHAR* in_pStr) : pStr(in_pStr), bOwner(false) {}
- ~AkStringData() { Term(); }
- void Term()
- {
- if (pStr && bOwner)
- {
- TAlloc::Free((void*)pStr);
- bOwner = false;
- }
- pStr = nullptr;
- }
- void ClearReference()
- {
- if (!bOwner)
- pStr = nullptr;
- }
- protected:
- const T_CHAR* pStr;
- bool bOwner;
- };
- template<typename TAlloc, typename T_CHAR>
- class AkStringImpl : public AkStringData<TAlloc, T_CHAR>
- {};
- template<typename TAlloc, typename T_CHAR>
- class AkString: public AkStringImpl<TAlloc, T_CHAR>
- {
- private:
- typedef AkStringData<TAlloc, T_CHAR> tData;
- typedef AkStringImpl<TAlloc, T_CHAR> tImpl;
- public:
- AkString() : AkStringImpl<TAlloc, T_CHAR>() {}
- template<typename T_CHAR2>
- AkString(const T_CHAR2* in_pStr) { tImpl::Set(in_pStr); }
- AkString(const AkString<TAlloc, T_CHAR>& in_other) { tImpl::Set(in_other.Get()); TAlloc::operator=(in_other); }
- template<typename TAlloc2, typename T_CHAR2>
- AkString(const AkString<TAlloc2, T_CHAR2>& in_other) { tImpl::Set(in_other.Get()); TAlloc::operator=(in_other); } // if this does not compile it means that both allocation policies are not compatible.
- // The default assignment behavior is to not create a local copy, unless it is necessary (due to incompatible string types).
- // Call AllocCopy() if you want to ensure there is a local copy owned by this AkString.
- AKRESULT AllocCopy()
- {
- if (tData::pStr && !tData::bOwner)
- {
- const T_CHAR* pRefStr = tData::pStr;
- AkUInt32 uLen = tImpl::Length();
- if (uLen > 0)
- {
- tData::pStr = (T_CHAR*)TAlloc::Alloc((uLen + 1) * sizeof(T_CHAR));
- if (tData::pStr == NULL)
- return AK_InsufficientMemory;
- AKPLATFORM::AkMemCpy((void*)tData::pStr, (void*)pRefStr, ((uLen + 1) * sizeof(T_CHAR)));
- tData::bOwner = true;
- }
- else
- {
- tData::pStr = NULL;
- }
- }
- return AK_Success;
- }
- // Transfer memory ownership from in_from to this AkString.
- void Transfer(AkString<TAlloc, T_CHAR>& in_from)
- {
- tData::Term();
- TAlloc::TransferMem((void*&) tData::pStr, in_from, (void*)in_from.tData::pStr);
- in_from.tData::pStr = nullptr;
-
- tData::bOwner = in_from.tData::bOwner;
- in_from.tData::bOwner = false;
- }
- const T_CHAR* Get() const
- {
- return tData::pStr;
- }
- AkString& operator=(const AkString<TAlloc, T_CHAR>& in_rhs)
- {
- tImpl::Set(in_rhs.Get());
- TAlloc::operator=(in_rhs);
- return *this;
- }
- template<typename TAlloc2, typename T_CHAR2>
- AkString& operator=(const AkString<TAlloc2, T_CHAR2>& in_rhs)
- {
- tImpl::Set(in_rhs.Get());
- TAlloc::operator=(in_rhs); // if this does not compile it means that both allocation policies are not compatible.
- return *this;
- }
- template<typename T_CHAR2>
- AkString& operator=(const T_CHAR2* in_pStr)
- {
- tImpl::Set(in_pStr);
- return *this;
- }
- };
- #ifdef AK_SUPPORT_WCHAR
- template<typename TAlloc>
- class AkStringImpl <TAlloc, wchar_t> : public AkStringData<TAlloc, wchar_t>
- {
- private:
- typedef AkStringData<TAlloc, wchar_t> tData;
- public:
- AkStringImpl() : AkStringData<TAlloc, wchar_t>() {}
- protected:
- AKRESULT Set(const char* in_pStr)
- {
- tData::Term();
- if (in_pStr != NULL)
- {
- size_t uLen = strlen(in_pStr);
- if (uLen > 0)
- {
- tData::pStr = (wchar_t*)TAlloc::Alloc((uLen + 1) * sizeof(wchar_t));
- if (tData::pStr == NULL)
- return AK_InsufficientMemory;
- AKPLATFORM::AkCharToWideChar(in_pStr, (AkUInt32)(uLen + 1), const_cast<wchar_t*>(tData::pStr));
- tData::bOwner = true;
- }
- else
- {
- tData::pStr = NULL;
- }
- }
- return AK_Success;
- }
- AKRESULT Set(const wchar_t* in_pStr)
- {
- tData::Term();
- tData::pStr = in_pStr;
- return AK_Success;
- }
- public:
- AkUInt32 Length() const
- {
- if (tData::pStr == nullptr)
- return 0;
- return (AkUInt32)wcslen(tData::pStr);
- }
- };
- #endif
- template<typename TAlloc>
- class AkStringImpl <TAlloc, char> : public AkStringData<TAlloc, char>
- {
- private:
- typedef AkStringData<TAlloc, char> tData;
- public:
- AkStringImpl() : AkStringData<TAlloc, char>() {}
- protected:
- AKRESULT Set(const wchar_t* in_pStr)
- {
- tData::Term();
- if (in_pStr != NULL)
- {
- size_t uLen = wcslen(in_pStr);
- if (uLen > 0)
- {
- tData::pStr = (char*)TAlloc::Alloc((uLen + 1) * sizeof(char));
- if (tData::pStr == NULL)
- return AK_InsufficientMemory;
- AKPLATFORM::AkWideCharToChar(in_pStr, (AkUInt32)(uLen + 1), const_cast<char*>(tData::pStr));
- tData::bOwner = true;
- }
- else
- {
- tData::pStr = NULL;
- }
- }
- return AK_Success;
- }
- AKRESULT Set(const char* in_pStr)
- {
- tData::Term();
- tData::pStr = in_pStr;
- return AK_Success;
- }
- public:
- AkUInt32 Length() const
- {
- if (tData::pStr == nullptr)
- return 0;
- return (AkUInt32)strlen(tData::pStr);
- }
- };
- struct AkNonThreaded
- {
- AkForceInline void Lock() {}
- AkForceInline void Unlock() {}
- };
- template<typename TAlloc, typename T_CHAR>
- static AkForceInline AkUInt32 AkHash(const AkString<TAlloc, T_CHAR>& in_str)
- {
- AkUInt32 uLen = in_str.Length();
- if (uLen > 0)
- {
- AK::FNVHash32 hash;
- return hash.Compute(in_str.Get(), uLen * sizeof(T_CHAR));
- }
- return 0;
- }
- //
- // AkDbString - A string reference class that stores a hash to a string in a database. If an identical string is found, the reference count in the database is incremented,
- // so that we do not store duplicate strings. Database can be made multi thread safe by passing in CAkLock for tLock, or AkNonThreaded if concurrent access is not needed.
- //
- template<typename TAlloc, typename T_CHAR, typename tLock = AkNonThreaded>
- class AkDbString : public TAlloc
- {
- public:
- typedef AkDbString<TAlloc, T_CHAR, tLock> tThis;
- typedef AkString<TAlloc, T_CHAR> tString;
- struct Entry
- {
- Entry() : refCount(0) {}
- tString str;
- AkInt32 refCount;
- };
- typedef AkHashList<AkUInt32, Entry, TAlloc> tStringTable;
- struct Instance : public TAlloc
- {
- tStringTable table;
- tLock lock;
- };
- public:
- // Must be called to initialize the database.
- static AKRESULT InitDB()
- {
- if (pInstance == NULL)
- {
- pInstance = (Instance*)pInstance->TAlloc::Alloc(sizeof(Instance));
- AkPlacementNew(pInstance) Instance();
- return AK_Success;
- }
- else
- return AK_Fail;
- }
- // Term the DB.
- static void TermDB()
- {
- if (pInstance != NULL)
- {
- pInstance->~Instance();
- pInstance->TAlloc::Free(pInstance);
- pInstance = NULL;
- }
- }
- static void UnlockDB() { pInstance->lock.Unlock();}
- static void LockDB() { pInstance->lock.Lock(); }
- private:
- static Instance* pInstance;
- public:
- AkDbString() : m_uHash(0)
- {}
- AkDbString(const tThis& in_fromDbStr) : m_uHash(0) { Aquire(in_fromDbStr.m_uHash); }
- // Construct from AkString
- template<typename TAlloc2, typename T_CHAR2>
- AkDbString(const AkString<TAlloc2, T_CHAR2>& in_fromStr) : m_uHash(0) { Aquire(in_fromStr); }
- tThis& operator=(const tThis& in_rhs)
- {
- Aquire(in_rhs.m_uHash);
- return *this;
- }
- // Assign from AkString
- template<typename TAlloc2, typename T_CHAR2>
- tThis& operator=(const AkString<TAlloc2, T_CHAR2>& in_rhs)
- {
- Aquire(in_rhs);
- return *this;
- }
- // Assign from char string
- template<typename T_CHAR2>
- tThis& operator=(const T_CHAR2* in_rhs)
- {
- const AkString<TAlloc, T_CHAR2>& convert = in_rhs;
- Aquire(convert);
- return *this;
- }
- ~AkDbString()
- {
- Release();
- }
- const T_CHAR* Get() const
- {
- if (m_uHash != 0)
- {
- Entry* pEntry = pInstance->table.Exists(m_uHash);
- AKASSERT(pEntry != NULL);
- return pEntry->str.Get();
- }
- return NULL;
- }
- protected:
-
- template<typename TAlloc2, typename T_CHAR2>
- AKRESULT Aquire(const AkString<TAlloc2, T_CHAR2>& in_str)
- {
- AKRESULT res = AK_Success;
- Release();
- if (in_str.Get() != NULL)
- {
- m_uHash = AkHash(in_str);
- LockDB();
- {
- Entry* pEntry = pInstance->table.Set(m_uHash);
- if (pEntry != NULL)
- {
- pEntry->refCount++;
- if (pEntry->str.Get() == NULL)
- {
- pEntry->str = in_str;
- pEntry->str.AllocCopy();
- if (pEntry->str.Get() == NULL) // Allocation failure
- {
- pInstance->table.Unset(m_uHash);
- m_uHash = 0;
- res = AK_Fail;
- }
- }
- }
- else
- {
- m_uHash = 0;
- res = AK_Fail;
- }
- }
- UnlockDB();
- }
- return res;
- }
- // in_uHash must have come from another AkDbString, and therefore already exist in the DB.
- AKRESULT Aquire(AkUInt32 in_uHash)
- {
- AKRESULT res = AK_Success;
- Release();
- if (in_uHash != 0)
- {
- m_uHash = in_uHash;
- LockDB();
- {
- Entry* pEntry = pInstance->table.Exists(m_uHash);
- AKASSERT(pEntry != NULL);
- pEntry->refCount++;
- AKASSERT(pEntry->str.Get() != NULL);
- }
- UnlockDB();
- }
- return res;
- }
- void Release()
- {
- if (m_uHash != 0)
- {
- LockDB();
- {
- tStringTable& table = pInstance->table;
- typename tStringTable::IteratorEx it = table.FindEx(m_uHash);
- AKASSERT(it != table.End());//<- Check that DbString was properly constructed.
- Entry& entry = (*it).item;
- AKASSERT(entry.refCount > 0);
- entry.refCount--;
- if (entry.refCount == 0)
- {
- table.Erase(it);
- }
- }
- UnlockDB();
- m_uHash = 0;
- }
- }
- AkUInt32 m_uHash;
- };
- template<typename TAlloc, typename T_CHAR, typename tLock>
- typename AkDbString<TAlloc, T_CHAR, tLock>::Instance* AkDbString<TAlloc, T_CHAR, tLock>::pInstance = NULL;
|