Version

menu_open
Wwise SDK 2019.1.11
AkString.h
1 /*******************************************************************************
2 The content of this file includes portions of the AUDIOKINETIC Wwise Technology
3 released in source code form as part of the SDK installer package.
4 
5 Commercial License Usage
6 
7 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
8 may use this file in accordance with the end user license agreement provided
9 with the software or, alternatively, in accordance with the terms contained in a
10 written agreement between you and Audiokinetic Inc.
11 
12 Apache License Usage
13 
14 Alternatively, this file may be used under the Apache License, Version 2.0 (the
15 "Apache License"); you may not use this file except in compliance with the
16 Apache License. You may obtain a copy of the Apache License at
17 http://www.apache.org/licenses/LICENSE-2.0.
18 
19 Unless required by applicable law or agreed to in writing, software distributed
20 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
21 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
22 the specific language governing permissions and limitations under the License.
23 
24 Version: <VERSION> Build: <BUILDNUMBER>
25 Copyright (c) <COPYRIGHTYEAR> Audiokinetic Inc.
26 *******************************************************************************/
27 #pragma once
28 
29 #include <AK/Tools/Common/AkFNVHash.h>
30 #include <AK/Tools/Common/AkHashList.h>
31 
32 template<typename TAlloc, typename T_CHAR>
33 class AkStringData : public TAlloc
34 {
35 public:
36  AkStringData() : pStr(NULL), bOwner(false) {}
37  AkStringData(const T_CHAR* in_pStr) : pStr(in_pStr), bOwner(false) {}
39 
40  void Term()
41  {
42  if (pStr && bOwner)
43  {
44  TAlloc::Free((void*)pStr);
45  bOwner = false;
46  }
47  pStr = NULL;
48  }
49 
50 protected:
51  const T_CHAR* pStr;
52  bool bOwner;
53 };
54 
55 template<typename TAlloc, typename T_CHAR>
56 class AkStringImpl : public AkStringData<TAlloc, T_CHAR>
57 {};
58 
59 template<typename TAlloc, typename T_CHAR>
60 class AkString: public AkStringImpl<TAlloc, T_CHAR>
61 {
62 private:
65 
66 public:
67  AkString() : AkStringImpl<TAlloc, T_CHAR>() {}
68 
69  template<typename T_CHAR2>
70  AkString(const T_CHAR2* in_pStr) { tImpl::Set(in_pStr); }
71 
72  AkString(const AkString<TAlloc, T_CHAR>& in_other) { tImpl::Set(in_other.Get()); }
73 
74  template<typename TAlloc2, typename T_CHAR2>
75  AkString(const AkString<TAlloc2, T_CHAR2>& in_other) { tImpl::Set(in_other.Get()); }
76 
77  // The default assignment behavior is to not create a local copy, unless it is necessary (due to incompatible string types).
78  // Call AllocCopy() if you want to ensure there is a local copy owned by this AkString.
79  AKRESULT AllocCopy()
80  {
81  if (tData::pStr && !tData::bOwner)
82  {
83  const T_CHAR* pRefStr = tData::pStr;
84  AkUInt32 uLen = tImpl::Length();
85  if (uLen > 0)
86  {
87  tData::pStr = (T_CHAR*)TAlloc::Alloc((uLen + 1) * sizeof(T_CHAR));
88  if (tData::pStr == NULL)
89  return AK_InsufficientMemory;
90 
91  AKPLATFORM::AkMemCpy((void*)tData::pStr, (void*)pRefStr, ((uLen + 1) * sizeof(T_CHAR)));
92  tData::bOwner = true;
93  }
94  else
95  {
96  tData::pStr = NULL;
97  }
98  }
99  return AK_Success;
100  }
101 
102  // Transfer memory ownership from in_from to this AkString.
104  {
105  tData::Term();
106 
107  tData::pStr = in_from.tData::pStr;
108  tData::bOwner = true;
109 
110  in_from.tData::pStr = NULL;
111  in_from.tData::bOwner = false;
112  }
113 
114  const T_CHAR* Get() const
115  {
116  return tData::pStr;
117  }
118 
120  {
121  tImpl::Set(in_rhs.Get());
122  return *this;
123  }
124 
125  template<typename TAlloc2, typename T_CHAR2>
127  {
128  tImpl::Set(in_rhs.Get());
129  return *this;
130  }
131 
132  template<typename T_CHAR2>
133  AkString& operator=(const T_CHAR2* in_pStr)
134  {
135  tImpl::Set(in_pStr);
136  return *this;
137  }
138 };
139 
140 #ifdef AK_SUPPORT_WCHAR
141 template<typename TAlloc>
142 class AkStringImpl <TAlloc, wchar_t> : public AkStringData<TAlloc, wchar_t>
143 {
144 private:
145  typedef AkStringData<TAlloc, wchar_t> tData;
146 
147 public:
148  AkStringImpl() : AkStringData<TAlloc, wchar_t>() {}
149 
150 protected:
151  AKRESULT Set(const char* in_pStr)
152  {
153  tData::Term();
154 
155  if (in_pStr != NULL)
156  {
157  size_t uLen = strlen(in_pStr);
158  if (uLen > 0)
159  {
160  tData::pStr = (wchar_t*)TAlloc::Alloc((uLen + 1) * sizeof(wchar_t));
161  if (tData::pStr == NULL)
162  return AK_InsufficientMemory;
163 
164  AKPLATFORM::AkCharToWideChar(in_pStr, (AkUInt32)(uLen + 1), const_cast<wchar_t*>(tData::pStr));
165  tData::bOwner = true;
166  }
167  else
168  {
169  tData::pStr = NULL;
170  }
171  }
172 
173  return AK_Success;
174  }
175 
176  AKRESULT Set(const wchar_t* in_pStr)
177  {
178  tData::Term();
179  tData::pStr = in_pStr;
180  return AK_Success;
181  }
182 
183 public:
184  AkUInt32 Length() const
185  {
186  return (AkUInt32)wcslen(tData::pStr);
187  }
188 };
189 #endif
190 
191 template<typename TAlloc>
192 class AkStringImpl <TAlloc, char> : public AkStringData<TAlloc, char>
193 {
194 private:
196 
197 public:
198  AkStringImpl() : AkStringData<TAlloc, char>() {}
199 
200 protected:
201  AKRESULT Set(const wchar_t* in_pStr)
202  {
203  tData::Term();
204 
205  if (in_pStr != NULL)
206  {
207  size_t uLen = wcslen(in_pStr);
208  if (uLen > 0)
209  {
210  tData::pStr = (char*)TAlloc::Alloc((uLen + 1) * sizeof(char));
211  if (tData::pStr == NULL)
212  return AK_InsufficientMemory;
213 
214  AKPLATFORM::AkWideCharToChar(in_pStr, (AkUInt32)(uLen + 1), const_cast<char*>(tData::pStr));
215  tData::bOwner = true;
216  }
217  else
218  {
219  tData::pStr = NULL;
220  }
221  }
222 
223  return AK_Success;
224  }
225 
226  AKRESULT Set(const char* in_pStr)
227  {
228  tData::Term();
229  tData::pStr = in_pStr;
230  return AK_Success;
231  }
232 
233 public:
234  AkUInt32 Length() const
235  {
236  return (AkUInt32)strlen(tData::pStr);
237  }
238 };
239 
241 {
242  AkForceInline void Lock() {}
243  AkForceInline void Unlock() {}
244 };
245 
246 template<typename TAlloc, typename T_CHAR>
247 static AkForceInline AkUInt32 AkHash(const AkString<TAlloc, T_CHAR>& in_str)
248 {
249  AkUInt32 uLen = in_str.Length();
250  if (uLen > 0)
251  {
252  AK::FNVHash32 hash;
253  return hash.Compute(in_str.Get(), uLen * sizeof(T_CHAR));
254  }
255  return 0;
256 }
257 
258 //
259 // 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,
260 // 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.
261 //
262 template<typename TAlloc, typename T_CHAR, typename tLock = AkNonThreaded>
263 class AkDbString : public TAlloc
264 {
265 public:
268 
269  struct Entry
270  {
271  Entry() : refCount(0) {}
272 
274  AkInt32 refCount;
275  };
276 
278 
279  struct Instance : public TAlloc
280  {
282  tLock lock;
283  };
284 
285 public:
286 
287  // Must be called to initialize the database.
288  static AKRESULT InitDB()
289  {
290  if (pInstance == NULL)
291  {
292  pInstance = (Instance*)pInstance->TAlloc::Alloc(sizeof(Instance));
293  AkPlacementNew(pInstance) Instance();
294  return AK_Success;
295  }
296  else
297  return AK_Fail;
298  }
299 
300  // Term the DB.
301  static void TermDB()
302  {
303  if (pInstance != NULL)
304  {
305  pInstance->~Instance();
306  pInstance->TAlloc::Free(pInstance);
307  pInstance = NULL;
308  }
309  }
310 
311  static void UnlockDB() { pInstance->lock.Unlock();}
312  static void LockDB() { pInstance->lock.Lock(); }
313 
314 private:
315 
316  static Instance* pInstance;
317 
318 public:
320  {}
321 
322  AkDbString(const tThis& in_fromDbStr) : m_uHash(0) { Aquire(in_fromDbStr.m_uHash); }
323 
324  // Construct from AkString
325  template<typename TAlloc2, typename T_CHAR2>
326  AkDbString(const AkString<TAlloc2, T_CHAR2>& in_fromStr) : m_uHash(0) { Aquire(in_fromStr); }
327 
328  tThis& operator=(const tThis& in_rhs)
329  {
330  Aquire(in_rhs.m_uHash);
331  return *this;
332  }
333 
334  // Assign from AkString
335  template<typename TAlloc2, typename T_CHAR2>
337  {
338  Aquire(in_rhs);
339  return *this;
340  }
341 
342  // Assign from char string
343  template<typename T_CHAR2>
344  tThis& operator=(const T_CHAR2* in_rhs)
345  {
346  const AkString<TAlloc, T_CHAR2>& convert = in_rhs;
347  Aquire(convert);
348  return *this;
349  }
350 
352  {
353  Release();
354  }
355 
356  const T_CHAR* Get() const
357  {
358  if (m_uHash != 0)
359  {
360  Entry* pEntry = pInstance->table.Exists(m_uHash);
361  AKASSERT(pEntry != NULL);
362  return pEntry->str.Get();
363  }
364  return NULL;
365  }
366 
367 protected:
368 
369  template<typename TAlloc2, typename T_CHAR2>
370  AKRESULT Aquire(const AkString<TAlloc2, T_CHAR2>& in_str)
371  {
372  AKRESULT res = AK_Success;
373 
374  Release();
375 
376  if (in_str.Get() != NULL)
377  {
378  m_uHash = AkHash(in_str);
379 
380  LockDB();
381  {
382  Entry* pEntry = pInstance->table.Set(m_uHash);
383  if (pEntry != NULL)
384  {
385  pEntry->refCount++;
386 
387  if (pEntry->str.Get() == NULL)
388  {
389  pEntry->str = in_str;
390  pEntry->str.AllocCopy();
391 
392  if (pEntry->str.Get() == NULL) // Allocation failure
393  {
394  pInstance->table.Unset(m_uHash);
395  m_uHash = 0;
396  res = AK_Fail;
397  }
398  }
399  }
400  else
401  {
402  m_uHash = 0;
403  res = AK_Fail;
404  }
405  }
406  UnlockDB();
407  }
408 
409  return res;
410  }
411 
412  // in_uHash must have come from another AkDbString, and therefore already exist in the DB.
413  AKRESULT Aquire(AkUInt32 in_uHash)
414  {
415  AKRESULT res = AK_Success;
416 
417  Release();
418 
419  if (in_uHash != 0)
420  {
421  m_uHash = in_uHash;
422  LockDB();
423  {
424  Entry* pEntry = pInstance->table.Exists(m_uHash);
425  AKASSERT(pEntry != NULL);
426 
427  pEntry->refCount++;
428  AKASSERT(pEntry->str.Get() != NULL);
429  }
430  UnlockDB();
431  }
432 
433  return res;
434  }
435 
436  void Release()
437  {
438  if (m_uHash != 0)
439  {
440  LockDB();
441  {
442  tStringTable& table = pInstance->table;
443  typename tStringTable::IteratorEx it = table.FindEx(m_uHash);
444  AKASSERT(it != table.End());//<- Check that DbString was properly constructed.
445  Entry& entry = (*it).item;
446  AKASSERT(entry.refCount > 0);
447 
448  entry.refCount--;
449  if (entry.refCount == 0)
450  {
451  table.Erase(it);
452  }
453  }
454  UnlockDB();
455 
456  m_uHash = 0;
457  }
458  }
459 
460  AkUInt32 m_uHash;
461 
462 };
463 
464 template<typename TAlloc, typename T_CHAR, typename tLock>
~AkStringData()
Definition: AkString.h:38
Definition: AkString.h:270
HashParams::HashType Compute(const void *in_pData, unsigned int in_dataSize)
Definition: AkFNVHash.h:102
AkString & operator=(const AkString< TAlloc, T_CHAR > &in_rhs)
Definition: AkString.h:119
tThis & operator=(const AkString< TAlloc2, T_CHAR2 > &in_rhs)
Definition: AkString.h:336
Iterator End()
Definition: AkHashList.h:161
tString str
Definition: AkString.h:273
AKRESULT Set(const char *in_pStr)
Definition: AkString.h:226
const T_CHAR * Get() const
Definition: AkString.h:356
void Transfer(AkString< TAlloc, T_CHAR > &in_from)
Definition: AkString.h:103
AkStringData(const T_CHAR *in_pStr)
Definition: AkString.h:37
AkInt32 refCount
Definition: AkString.h:274
tStringTable table
Definition: AkString.h:281
AkDbString()
Definition: AkString.h:319
AkString(const T_CHAR2 *in_pStr)
Definition: AkString.h:70
AKRESULT Aquire(const AkString< TAlloc2, T_CHAR2 > &in_str)
Definition: AkString.h:370
AkString< TAlloc, T_CHAR > tString
Definition: AkString.h:267
AkHashList< AkUInt32, Entry, TAlloc > tStringTable
Definition: AkString.h:277
AkString & operator=(const T_CHAR2 *in_pStr)
Definition: AkString.h:133
IteratorEx Erase(const IteratorEx &in_rIter)
Definition: AkHashList.h:324
AkUInt32 Length() const
Definition: AkString.h:234
AkUInt32 m_uHash
Definition: AkString.h:460
AkStringData()
Definition: AkString.h:36
Definition: AkString.h:61
AkForceInline void AkMemCpy(void *pDest, const void *pSrc, AkUInt32 uSize)
Platform Independent Helper.
Definition: AkPlatformFuncs.h:330
AkForceInline void Unlock()
Definition: AkString.h:243
static void UnlockDB()
Definition: AkString.h:311
AkDbString< TAlloc, T_CHAR, tLock > tThis
Definition: AkString.h:266
const T_CHAR * Get() const
Definition: AkString.h:114
AkString(const AkString< TAlloc, T_CHAR > &in_other)
Definition: AkString.h:72
void Release()
Definition: AkString.h:436
~AkDbString()
Definition: AkString.h:351
static void TermDB()
Definition: AkString.h:301
static void LockDB()
Definition: AkString.h:312
AkForceInline void Lock()
Definition: AkString.h:242
AKRESULT Aquire(AkUInt32 in_uHash)
Definition: AkString.h:413
AKRESULT Set(const wchar_t *in_pStr)
Definition: AkString.h:201
IteratorEx FindEx(T_KEY in_Key)
Definition: AkHashList.h:168
AkString & operator=(const AkString< TAlloc2, T_CHAR2 > &in_rhs)
Definition: AkString.h:126
AkForceInline AkInt32 AkCharToWideChar(const char *in_pszAnsiString, AkUInt32 in_uiOutBufferSize, void *io_pvUnicodeStringBuffer)
String conversion helper.
Definition: AkPlatformFuncs.h:389
AKRESULT AllocCopy()
Definition: AkString.h:79
tThis & operator=(const tThis &in_rhs)
Definition: AkString.h:328
Entry()
Definition: AkString.h:271
AkForceInline AkInt32 AkWideCharToChar(const wchar_t *in_pszUnicodeString, AkUInt32 in_uiOutBufferSize, char *io_pszAnsiString)
String conversion helper.
Definition: AkPlatformFuncs.h:372
bool bOwner
Definition: AkString.h:52
void Term()
Definition: AkString.h:40
AkDbString(const AkString< TAlloc2, T_CHAR2 > &in_fromStr)
Definition: AkString.h:326
AkDbString(const tThis &in_fromDbStr)
Definition: AkString.h:322
AkString()
Definition: AkString.h:67
static AKRESULT InitDB()
Definition: AkString.h:288
AkString(const AkString< TAlloc2, T_CHAR2 > &in_other)
Definition: AkString.h:75
tThis & operator=(const T_CHAR2 *in_rhs)
Definition: AkString.h:344
const T_CHAR * pStr
Definition: AkString.h:51

Was this page helpful?

Need Support?

Questions? Problems? Need more info? Contact us, and we can help!

Visit our Support page

Tell us about your project. We're here to help.

Register your project and we'll help you get started with no strings attached!

Get started with Wwise