Version

menu_open

include/AK/Tools/Common/AkString.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002 The content of this file includes portions of the AUDIOKINETIC Wwise Technology
00003 released in source code form as part of the SDK installer package.
00004 
00005 Commercial License Usage
00006 
00007 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
00008 may use this file in accordance with the end user license agreement provided
00009 with the software or, alternatively, in accordance with the terms contained in a
00010 written agreement between you and Audiokinetic Inc.
00011 
00012 Apache License Usage
00013 
00014 Alternatively, this file may be used under the Apache License, Version 2.0 (the
00015 "Apache License"); you may not use this file except in compliance with the
00016 Apache License. You may obtain a copy of the Apache License at
00017 http://www.apache.org/licenses/LICENSE-2.0.
00018 
00019 Unless required by applicable law or agreed to in writing, software distributed
00020 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
00021 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
00022 the specific language governing permissions and limitations under the License.
00023 
00024 Version: <VERSION>  Build: <BUILDNUMBER>
00025 Copyright (c) <COPYRIGHTYEAR> Audiokinetic Inc.
00026 *******************************************************************************/
00027 #pragma once
00028 
00029 #include <AK/Tools/Common/AkFNVHash.h>
00030 #include <AK/Tools/Common/AkHashList.h>
00031 
00032 template<typename TAlloc, typename T_CHAR>
00033 class AkStringData : public TAlloc
00034 {
00035 public:
00036     AkStringData() : pStr(NULL), bOwner(false) {}
00037     AkStringData(const T_CHAR* in_pStr) : pStr(in_pStr), bOwner(false) {}
00038     ~AkStringData() { Term(); }
00039 
00040     void Term()
00041     {
00042         if (pStr && bOwner)
00043         {
00044             TAlloc::Free((void*)pStr);
00045             bOwner = false;
00046         }
00047         pStr = NULL;
00048     }
00049 
00050 protected:
00051     const T_CHAR* pStr;
00052     bool bOwner;
00053 };
00054 
00055 template<typename TAlloc, typename T_CHAR>
00056 class AkStringImpl : public AkStringData<TAlloc, T_CHAR>
00057 {};
00058 
00059 template<typename TAlloc, typename T_CHAR>
00060 class AkString: public AkStringImpl<TAlloc, T_CHAR>
00061 {
00062 private:
00063     typedef AkStringData<TAlloc, T_CHAR> tData;
00064     typedef AkStringImpl<TAlloc, T_CHAR> tImpl;
00065 
00066 public:
00067     AkString() : AkStringImpl<TAlloc, T_CHAR>() {}
00068 
00069     template<typename T_CHAR2>
00070     AkString(const T_CHAR2* in_pStr) { tImpl::Set(in_pStr); }
00071 
00072     AkString(const AkString<TAlloc, T_CHAR>& in_other) { tImpl::Set(in_other.Get()); }
00073 
00074     template<typename TAlloc2, typename T_CHAR2>
00075     AkString(const AkString<TAlloc2, T_CHAR2>& in_other) { tImpl::Set(in_other.Get()); }
00076 
00077     // The default assignment behavior is to not create a local copy, unless it is necessary (due to incompatible string types).
00078     // Call AllocCopy() if you want to ensure there is a local copy owned by this AkString.  
00079     AKRESULT AllocCopy()
00080     {
00081         if (tData::pStr && !tData::bOwner)
00082         {
00083             const T_CHAR* pRefStr = tData::pStr;
00084             AkUInt32 uLen = tImpl::Length();
00085             if (uLen > 0)
00086             {
00087                 tData::pStr = (T_CHAR*)TAlloc::Alloc((uLen + 1) * sizeof(T_CHAR));
00088                 if (tData::pStr == NULL)
00089                     return AK_InsufficientMemory;
00090 
00091                 AKPLATFORM::AkMemCpy((void*)tData::pStr, (void*)pRefStr, ((uLen + 1) * sizeof(T_CHAR)));
00092                 tData::bOwner = true;
00093             }
00094             else
00095             {
00096                 tData::pStr = NULL;
00097             }
00098         }
00099         return AK_Success;
00100     }
00101 
00102     // Transfer memory ownership from in_from to this AkString.
00103     void Transfer(AkString<TAlloc, T_CHAR>& in_from)
00104     {
00105         tData::Term();
00106 
00107         tData::pStr = in_from.tData::pStr;
00108         tData::bOwner = true;
00109         
00110         in_from.tData::pStr = NULL;
00111         in_from.tData::bOwner = false;
00112     }
00113 
00114     const T_CHAR* Get() const
00115     {
00116         return tData::pStr;
00117     }
00118 
00119     AkString& operator=(const AkString<TAlloc, T_CHAR>& in_rhs)
00120     {
00121         tImpl::Set(in_rhs.Get());
00122         return *this;
00123     }
00124 
00125     template<typename TAlloc2, typename T_CHAR2>
00126     AkString& operator=(const AkString<TAlloc2, T_CHAR2>& in_rhs)
00127     {
00128         tImpl::Set(in_rhs.Get());
00129         return *this;
00130     }
00131 
00132     template<typename T_CHAR2>
00133     AkString& operator=(const T_CHAR2* in_pStr)
00134     {
00135         tImpl::Set(in_pStr);
00136         return *this;
00137     }
00138 };
00139 
00140 #ifdef AK_SUPPORT_WCHAR 
00141 template<typename TAlloc>
00142 class AkStringImpl <TAlloc, wchar_t> : public AkStringData<TAlloc, wchar_t>
00143 {
00144 private:
00145     typedef AkStringData<TAlloc, wchar_t> tData;
00146 
00147 public:
00148     AkStringImpl() : AkStringData<TAlloc, wchar_t>() {}
00149 
00150 protected:
00151     AKRESULT Set(const char* in_pStr)
00152     {
00153         tData::Term();
00154 
00155         if (in_pStr != NULL)
00156         {
00157             size_t uLen = strlen(in_pStr);
00158             if (uLen > 0)
00159             {
00160                 tData::pStr = (wchar_t*)TAlloc::Alloc((uLen + 1) * sizeof(wchar_t));
00161                 if (tData::pStr == NULL)
00162                     return AK_InsufficientMemory;
00163 
00164                 AKPLATFORM::AkCharToWideChar(in_pStr, (AkUInt32)(uLen + 1), const_cast<wchar_t*>(tData::pStr));
00165                 tData::bOwner = true;
00166             }
00167             else
00168             {
00169                 tData::pStr = NULL;
00170             }
00171         }
00172 
00173         return AK_Success;
00174     }
00175 
00176     AKRESULT Set(const wchar_t* in_pStr)
00177     {
00178         tData::Term();
00179         tData::pStr = in_pStr;
00180         return AK_Success;
00181     }
00182 
00183 public:
00184     AkUInt32 Length() const
00185     {
00186         return (AkUInt32)wcslen(tData::pStr);
00187     }
00188 };
00189 #endif
00190 
00191 template<typename TAlloc>
00192 class AkStringImpl <TAlloc, char> : public AkStringData<TAlloc, char>
00193 {
00194 private:
00195     typedef AkStringData<TAlloc, char> tData;
00196 
00197 public:
00198     AkStringImpl() : AkStringData<TAlloc, char>() {}
00199 
00200 protected:
00201     AKRESULT Set(const wchar_t* in_pStr)
00202     {
00203         tData::Term();
00204 
00205         if (in_pStr != NULL)
00206         {
00207             size_t uLen = wcslen(in_pStr);
00208             if (uLen > 0)
00209             {
00210                 tData::pStr = (char*)TAlloc::Alloc((uLen + 1) * sizeof(char));
00211                 if (tData::pStr == NULL)
00212                     return AK_InsufficientMemory;
00213 
00214                 AKPLATFORM::AkWideCharToChar(in_pStr, (AkUInt32)(uLen + 1), const_cast<char*>(tData::pStr));
00215                 tData::bOwner = true;
00216             }
00217             else
00218             {
00219                 tData::pStr = NULL;
00220             }
00221         }
00222 
00223         return AK_Success;
00224     }
00225 
00226     AKRESULT Set(const char* in_pStr)
00227     {
00228         tData::Term();
00229         tData::pStr = in_pStr;
00230         return AK_Success;
00231     }
00232 
00233 public:
00234     AkUInt32 Length() const
00235     {
00236         return (AkUInt32)strlen(tData::pStr);
00237     }
00238 };
00239 
00240 struct AkNonThreaded
00241 {
00242     AkForceInline void Lock() {}
00243     AkForceInline void Unlock() {}
00244 };
00245 
00246 template<typename TAlloc, typename T_CHAR>
00247 static AkForceInline AkUInt32 AkHash(const AkString<TAlloc, T_CHAR>& in_str)
00248 {
00249     AkUInt32 uLen = in_str.Length();
00250     if (uLen > 0)
00251     {
00252         AK::FNVHash32 hash;
00253         return hash.Compute(in_str.Get(), uLen * sizeof(T_CHAR));
00254     }
00255     return 0;
00256 }
00257 
00258 //
00259 // 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,
00260 //  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.
00261 //
00262 template<typename TAlloc, typename T_CHAR, typename tLock = AkNonThreaded>
00263 class AkDbString : public TAlloc
00264 {
00265 public: 
00266     typedef AkDbString<TAlloc, T_CHAR, tLock> tThis;
00267     typedef AkString<TAlloc, T_CHAR> tString;
00268 
00269     struct Entry
00270     {
00271         Entry() : refCount(0) {}
00272 
00273         tString str;
00274         AkInt32 refCount;
00275     };
00276 
00277     typedef AkHashList<AkUInt32, Entry, TAlloc> tStringTable;
00278 
00279     struct Instance : public TAlloc
00280     {
00281         tStringTable table;
00282         tLock lock;
00283     };
00284 
00285 public:
00286 
00287     // Must be called to initialize the database.  
00288     static AKRESULT InitDB()
00289     {
00290         if (pInstance == NULL)
00291         {
00292             pInstance = (Instance*)pInstance->TAlloc::Alloc(sizeof(Instance));
00293             AkPlacementNew(pInstance) Instance();
00294             return AK_Success;
00295         }
00296         else
00297             return AK_Fail;
00298     }
00299 
00300     // Term the DB.
00301     static void TermDB()
00302     {
00303         if (pInstance != NULL)
00304         {
00305             pInstance->~Instance();
00306             pInstance->TAlloc::Free(pInstance);
00307             pInstance = NULL;
00308         }
00309     }
00310 
00311     static void UnlockDB() { pInstance->lock.Unlock();}
00312     static void LockDB() { pInstance->lock.Lock(); }
00313 
00314 private:
00315 
00316     static Instance* pInstance;
00317 
00318 public:
00319     AkDbString() : m_uHash(0)
00320     {}
00321 
00322     AkDbString(const tThis& in_fromDbStr) : m_uHash(0) { Aquire(in_fromDbStr.m_uHash); }
00323 
00324     // Construct from AkString
00325     template<typename TAlloc2, typename T_CHAR2>
00326     AkDbString(const AkString<TAlloc2, T_CHAR2>& in_fromStr) : m_uHash(0) { Aquire(in_fromStr); }
00327 
00328     tThis& operator=(const tThis& in_rhs)
00329     {
00330         Aquire(in_rhs.m_uHash);
00331         return *this;
00332     }
00333 
00334     // Assign from AkString
00335     template<typename TAlloc2, typename T_CHAR2>
00336     tThis& operator=(const AkString<TAlloc2, T_CHAR2>& in_rhs)
00337     {
00338         Aquire(in_rhs);
00339         return *this;
00340     }
00341 
00342     ~AkDbString()
00343     {
00344         Release();
00345     }
00346 
00347     const T_CHAR* Get()
00348     {
00349         if (m_uHash != 0)
00350         {
00351             Entry* pEntry = pInstance->table.Exists(m_uHash);
00352             AKASSERT(pEntry != NULL);
00353             return pEntry->str.Get();
00354         }
00355         return NULL;
00356     }
00357 
00358 protected:
00359     
00360     template<typename TAlloc2, typename T_CHAR2>
00361     AKRESULT Aquire(const AkString<TAlloc2, T_CHAR2>& in_str)
00362     {
00363         AKRESULT res = AK_Success;
00364 
00365         Release();
00366 
00367         if (in_str.Get() != NULL)
00368         {
00369             m_uHash = AkHash(in_str);
00370 
00371             LockDB();
00372             {
00373                 Entry* pEntry = pInstance->table.Set(m_uHash);
00374                 if (pEntry != NULL)
00375                 {
00376                     pEntry->refCount++;
00377 
00378                     if (pEntry->str.Get() == NULL)
00379                     {
00380                         pEntry->str = in_str;
00381                         pEntry->str.AllocCopy();
00382 
00383                         if (pEntry->str.Get() == NULL) // Allocation failure
00384                         {
00385                             pInstance->table.Unset(m_uHash);
00386                             m_uHash = 0;
00387                             res = AK_Fail;
00388                         }
00389                     }
00390                 }
00391                 else
00392                 {
00393                     m_uHash = 0;
00394                     res = AK_Fail;
00395                 }
00396             }
00397             UnlockDB();
00398         }
00399 
00400         return res;
00401     }
00402 
00403     // in_uHash must have come from another AkDbString, and therefore already exist in the DB.
00404     AKRESULT Aquire(AkUInt32 in_uHash)
00405     {
00406         AKRESULT res = AK_Success;
00407 
00408         Release();
00409 
00410         if (in_uHash != 0)
00411         {
00412             m_uHash = in_uHash;
00413             LockDB();
00414             {
00415                 Entry* pEntry = pInstance->table.Exists(m_uHash);
00416                 AKASSERT(pEntry != NULL);
00417 
00418                 pEntry->refCount++;
00419                 AKASSERT(pEntry->str.Get() != NULL);
00420             }
00421             UnlockDB();
00422         }
00423 
00424         return res;
00425     }
00426 
00427     void Release()
00428     {
00429         if (m_uHash != 0)
00430         {
00431             LockDB();
00432             {
00433                 tStringTable& table = pInstance->table;
00434                 typename tStringTable::IteratorEx it = table.FindEx(m_uHash);
00435                 Entry& entry = (*it).item;
00436                 AKASSERT(it != table.End() && entry.refCount > 0);
00437 
00438                 entry.refCount--;
00439                 if (entry.refCount == 0)
00440                 {
00441                     table.Erase(it);
00442                 }
00443             }
00444             UnlockDB();
00445 
00446             m_uHash = 0;
00447         }
00448     }
00449 
00450     AkUInt32 m_uHash;
00451 
00452 };
00453 
00454 template<typename TAlloc, typename T_CHAR, typename tLock>
00455 typename AkDbString<TAlloc, T_CHAR, tLock>::Instance* AkDbString<TAlloc, T_CHAR, tLock>::pInstance = NULL;

Cette page a-t-elle été utile ?

Besoin d'aide ?

Des questions ? Des problèmes ? Besoin de plus d'informations ? Contactez-nous, nous pouvons vous aider !

Visitez notre page d'Aide

Décrivez-nous de votre projet. Nous sommes là pour vous aider.

Enregistrez votre projet et nous vous aiderons à démarrer sans aucune obligation !

Partir du bon pied avec Wwise