00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
00078
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
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
00260
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
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
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
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
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)
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
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;