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;
Des questions ? Des problèmes ? Besoin de plus d'informations ? Contactez-nous, nous pouvons vous aider !
Visitez notre page d'AideEnregistrez votre projet et nous vous aiderons à démarrer sans aucune obligation !
Partir du bon pied avec Wwise