Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1488 lines
46 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #ifndef UTLSTRING_H
  7. #define UTLSTRING_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "tier1/utlmemory.h"
  12. #include "tier1/strtools.h"
  13. #include "limits.h"
  14. #ifndef SIZE_MAX
  15. #define SIZE_MAX ((size_t) -1)
  16. #endif
  17. //-----------------------------------------------------------------------------
  18. // Base class, containing simple memory management
  19. //-----------------------------------------------------------------------------
  20. class CUtlBinaryBlock
  21. {
  22. public:
  23. CUtlBinaryBlock( int growSize = 0, int initSize = 0 );
  24. ~CUtlBinaryBlock()
  25. {
  26. #ifdef _DEBUG
  27. m_nActualLength = 0x7BADF00D;
  28. #else
  29. m_nActualLength = 0;
  30. #endif
  31. }
  32. // NOTE: nInitialLength indicates how much of the buffer starts full
  33. CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength );
  34. CUtlBinaryBlock( const void* pMemory, int nSizeInBytes );
  35. CUtlBinaryBlock( const CUtlBinaryBlock& src );
  36. CUtlBinaryBlock &operator=( const CUtlBinaryBlock &src );
  37. #if VALVE_CPP11
  38. CUtlBinaryBlock( CUtlBinaryBlock&& src );
  39. CUtlBinaryBlock &operator=( CUtlBinaryBlock&& src );
  40. #endif
  41. void Get( void *pValue, int nMaxLen ) const;
  42. void Set( const void *pValue, int nLen );
  43. const void *Get( ) const;
  44. void *Get( );
  45. unsigned char& operator[]( int i );
  46. const unsigned char& operator[]( int i ) const;
  47. int Length() const;
  48. void SetLength( int nLength ); // Undefined memory will result
  49. bool IsEmpty() const;
  50. void Clear();
  51. void Purge();
  52. bool IsReadOnly() const;
  53. // Test for equality
  54. bool operator==( const CUtlBinaryBlock &src ) const;
  55. private:
  56. CUtlMemory<unsigned char> m_Memory;
  57. int m_nActualLength;
  58. };
  59. //-----------------------------------------------------------------------------
  60. // class inlines
  61. //-----------------------------------------------------------------------------
  62. #if VALVE_CPP11
  63. inline CUtlBinaryBlock::CUtlBinaryBlock( CUtlBinaryBlock&& src )
  64. : m_Memory( Move(src.m_Memory) )
  65. , m_nActualLength( src.m_nActualLength )
  66. {
  67. src.m_nActualLength = 0;
  68. }
  69. inline CUtlBinaryBlock& CUtlBinaryBlock::operator= ( CUtlBinaryBlock&& src )
  70. {
  71. int length = src.m_nActualLength;
  72. src.m_nActualLength = 0;
  73. m_Memory = Move( src.m_Memory );
  74. m_nActualLength = length;
  75. return *this;
  76. }
  77. #endif
  78. inline const void *CUtlBinaryBlock::Get( ) const
  79. {
  80. return m_Memory.Base();
  81. }
  82. inline void *CUtlBinaryBlock::Get( )
  83. {
  84. return m_Memory.Base();
  85. }
  86. inline int CUtlBinaryBlock::Length() const
  87. {
  88. return m_nActualLength;
  89. }
  90. inline unsigned char& CUtlBinaryBlock::operator[]( int i )
  91. {
  92. return m_Memory[i];
  93. }
  94. inline const unsigned char& CUtlBinaryBlock::operator[]( int i ) const
  95. {
  96. return m_Memory[i];
  97. }
  98. inline bool CUtlBinaryBlock::IsReadOnly() const
  99. {
  100. return m_Memory.IsReadOnly();
  101. }
  102. inline bool CUtlBinaryBlock::IsEmpty() const
  103. {
  104. return Length() == 0;
  105. }
  106. inline void CUtlBinaryBlock::Clear()
  107. {
  108. SetLength( 0 );
  109. }
  110. inline void CUtlBinaryBlock::Purge()
  111. {
  112. SetLength( 0 );
  113. m_Memory.Purge();
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Simple string class.
  117. // NOTE: This is *not* optimal! Use in tools, but not runtime code
  118. //-----------------------------------------------------------------------------
  119. class CUtlString
  120. {
  121. public:
  122. CUtlString(); // = default;
  123. CUtlString( const char *pString ); // initialize from c-style string
  124. // Attaches the string to external memory. Useful for avoiding a copy
  125. CUtlString( void* pMemory, int nSizeInBytes, int nInitialLength );
  126. CUtlString( const void* pMemory, int nSizeInBytes );
  127. // Copy/move constructor/assignment
  128. // Moves are extremely efficient as the underlying memory is not copied, just the pointers.
  129. CUtlString( const CUtlString& string ); // = default;
  130. CUtlString &operator=( const CUtlString &src ); // = default;
  131. #if VALVE_CPP11
  132. CUtlString( CUtlString&& moveFrom ); // = default;
  133. CUtlString &operator=( CUtlString&& moveFrom ); // = default;
  134. #endif
  135. // Also can assign from a regular C-style string
  136. CUtlString &operator=( const char *src );
  137. char *Access() { return Get(); }
  138. const char *Get( ) const;
  139. char *Get();
  140. char* GetForModify();
  141. void Clear() { Set( NULL ); }
  142. // CUtlString can be used anywhere a c-style string would be required
  143. // via this implicit conversion
  144. operator const char*() const;
  145. // for compatibility switching items from UtlSymbol
  146. const char *String() const { return Get(); }
  147. // Returns strlen
  148. int Length() const;
  149. bool IsEmpty() const;
  150. // GS - Added for chromehtml
  151. bool IsValid()
  152. {
  153. return (Length() != 0);
  154. }
  155. // Sets the length (used to serialize into the buffer )
  156. // Note: If nLen != 0, then this adds an extra byte for a null-terminator.
  157. void Set( const char *pValue );
  158. void SetLength( int nLen );
  159. void Purge();
  160. void Swap(CUtlString &src);
  161. // Case Change
  162. void ToUpper();
  163. void ToLower( );
  164. void Append( const char *pchAddition );
  165. void Append(const char *pchAddition, int nMaxChars);
  166. void Append(char chAddition) {
  167. char temp[2] = { chAddition, 0 };
  168. Append(temp);
  169. }
  170. // Strips the trailing slash
  171. void StripTrailingSlash();
  172. char operator[] ( int idx ) const;
  173. char& operator[] ( int idx );
  174. // Test for equality
  175. bool operator==( const CUtlString &src ) const;
  176. bool operator==( const char *src ) const;
  177. bool operator!=( const CUtlString &src ) const { return !operator==( src ); }
  178. bool operator!=( const char *src ) const { return !operator==( src ); }
  179. // If these are not defined, CUtlString as rhs will auto-convert
  180. // to const char* and do logical operations on the raw pointers. Ugh.
  181. inline friend bool operator==( const char *lhs, const CUtlString &rhs ) { return rhs.operator==( lhs ); }
  182. inline friend bool operator!=( const char *lhs, const CUtlString &rhs ) { return rhs.operator!=( lhs ); }
  183. CUtlString &operator+=( const CUtlString &rhs );
  184. CUtlString &operator+=( const char *rhs );
  185. CUtlString &operator+=( char c );
  186. CUtlString &operator+=( int rhs );
  187. CUtlString &operator+=( double rhs );
  188. CUtlString operator+( const char *pOther )const;
  189. CUtlString operator+( int rhs )const;
  190. bool MatchesPattern( const CUtlString &Pattern, int nFlags = 0 ); // case SENSITIVE, use * for wildcard in pattern string
  191. #if ! defined(SWIG)
  192. // Don't let SWIG see the PRINTF_FORMAT_STRING attribute or it will complain.
  193. int Format( PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 2, 3 );
  194. int FormatV( PRINTF_FORMAT_STRING const char *pFormat, va_list marker );
  195. #else
  196. int Format( const char *pFormat, ... );
  197. int FormatV( const char *pFormat, va_list marker );
  198. #endif
  199. void SetDirect( const char *pValue, int nChars );
  200. // Defining AltArgumentType_t hints that associative container classes should
  201. // also implement Find/Insert/Remove functions that take const char* params.
  202. typedef const char *AltArgumentType_t;
  203. // Take a piece out of the string.
  204. // If you only specify nStart, it'll go from nStart to the end.
  205. // You can use negative numbers and it'll wrap around to the start.
  206. CUtlString Slice( int32 nStart=0, int32 nEnd=INT_MAX );
  207. // Grab a substring starting from the left or the right side.
  208. CUtlString Left( int32 nChars );
  209. CUtlString Right( int32 nChars );
  210. CUtlString Remove(char const *pTextToRemove, bool bCaseSensitive) const;
  211. // Replace all instances of one character with another.
  212. CUtlString Replace( char cFrom, char cTo );
  213. /// Replace one string with the other (single pass). Passing a NULL to pchTo is same as calling Remove
  214. CUtlString Replace( char const *pchFrom, const char *pchTo, bool bCaseSensitive = false ) const;
  215. /// helper func for caseless replace
  216. CUtlString ReplaceCaseless( char const *pchFrom, const char *pchTo ) const { return Replace( pchFrom, pchTo, false ); }
  217. void RemoveDotSlashes(char separator = CORRECT_PATH_SEPARATOR);
  218. // Trim whitespace
  219. void TrimLeft( const char *szTargets = "\t\r\n " );
  220. void TrimRight( const char *szTargets = "\t\r\n " );
  221. void Trim( const char *szTargets = "\t\r\n " );
  222. // Calls right through to V_MakeAbsolutePath.
  223. CUtlString AbsPath( const char *pStartingDir=NULL ) const;
  224. CUtlString AbsPath(const char *pStartingDir, bool bLowercaseName) const
  225. {
  226. CUtlString result = AbsPath(pStartingDir);
  227. if (bLowercaseName)
  228. {
  229. result.ToLower();
  230. }
  231. return result;
  232. }
  233. // Gets the filename (everything except the path.. c:\a\b\c\somefile.txt -> somefile.txt).
  234. CUtlString UnqualifiedFilename() const;
  235. // Strips off one directory. Uses V_StripLastDir but strips the last slash also!
  236. CUtlString DirName();
  237. // Get a string with the extension removed (with V_StripExtension).
  238. CUtlString StripExtension() const;
  239. // Get a string with the filename removed (uses V_UnqualifiedFileName and also strips the last slash)
  240. CUtlString StripFilename() const;
  241. // Get a string with the base filename (with V_FileBase).
  242. CUtlString GetBaseFilename() const;
  243. // Get a string with the file extension (with V_FileBase).
  244. CUtlString GetExtension() const;
  245. // Works like V_ComposeFileName.
  246. static CUtlString PathJoin( const char *pStr1, const char *pStr2 );
  247. // These can be used for utlvector sorts.
  248. static int __cdecl SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 );
  249. static int __cdecl SortCaseSensitive( const CUtlString *pString1, const CUtlString *pString2 );
  250. // From Src2
  251. void FixSlashes( char cSeparator = CORRECT_PATH_SEPARATOR )
  252. {
  253. for ( int nLength = Length() - 1; nLength >= 0; nLength-- )
  254. {
  255. char *pname = (char*)&m_Storage[ nLength ];
  256. if ( *pname == INCORRECT_PATH_SEPARATOR || *pname == CORRECT_PATH_SEPARATOR )
  257. {
  258. *pname = cSeparator;
  259. }
  260. }
  261. }
  262. bool IsEqual_CaseSensitive( const char *src ) const
  263. {
  264. if ( !src )
  265. {
  266. return ( Length() == 0 );
  267. }
  268. return ( V_strcmp( Get(), src ) == 0 );
  269. }
  270. bool IsEqual_CaseInsensitive(const char *src) const
  271. {
  272. if (!src)
  273. {
  274. return (Length() == 0);
  275. }
  276. return (V_stricmp(Get(), src) == 0);
  277. }
  278. private:
  279. CUtlBinaryBlock m_Storage;
  280. };
  281. //-----------------------------------------------------------------------------
  282. // Inline methods
  283. //-----------------------------------------------------------------------------
  284. #if VALVE_CPP11
  285. inline CUtlString::CUtlString( CUtlString&& moveFrom )
  286. : m_Storage( Move( moveFrom.m_Storage ) )
  287. {
  288. }
  289. inline CUtlString& CUtlString::operator=( CUtlString&& moveFrom )
  290. {
  291. m_Storage = Move( moveFrom.m_Storage );
  292. return *this;
  293. }
  294. #endif
  295. inline bool CUtlString::IsEmpty() const
  296. {
  297. return Length() == 0;
  298. }
  299. inline int __cdecl CUtlString::SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 )
  300. {
  301. return V_stricmp( pString1->String(), pString2->String() );
  302. }
  303. inline int __cdecl CUtlString::SortCaseSensitive( const CUtlString *pString1, const CUtlString *pString2 )
  304. {
  305. return V_strcmp( pString1->String(), pString2->String() );
  306. }
  307. inline char CUtlString::operator [] ( int index ) const
  308. {
  309. return Get()[index];
  310. }
  311. inline char& CUtlString::operator[] ( int index )
  312. {
  313. return Access()[index];
  314. }
  315. inline CUtlString::operator const char *( ) const
  316. {
  317. return Get();
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Purpose: Implementation of low-level string functionality for character types.
  321. //-----------------------------------------------------------------------------
  322. template < typename T >
  323. class StringFuncs
  324. {
  325. public:
  326. static T *Duplicate( const T *pValue );
  327. static void Copy( T *out_pOut, const T *pIn, int iLength );
  328. static int Compare( const T *pLhs, const T *pRhs );
  329. static int Length( const T *pValue );
  330. static const T *FindChar( const T *pStr, const T cSearch );
  331. static const T *EmptyString();
  332. };
  333. template < >
  334. class StringFuncs<char>
  335. {
  336. public:
  337. static char *Duplicate( const char *pValue ) { return strdup( pValue ); }
  338. static void Copy( char *out_pOut, const char *pIn, int iLength ) { strncpy( out_pOut, pIn, iLength ); }
  339. static int Compare( const char *pLhs, const char *pRhs ) { return strcmp( pLhs, pRhs ); }
  340. static int Length( const char *pValue ) { return (int)strlen( pValue ); }
  341. static const char *FindChar( const char *pStr, const char cSearch ) { return strchr( pStr, cSearch ); }
  342. static const char *EmptyString() { return ""; }
  343. };
  344. template < >
  345. class StringFuncs<wchar_t>
  346. {
  347. public:
  348. static wchar_t *Duplicate( const wchar_t *pValue ) { return wcsdup( pValue ); }
  349. static void Copy( wchar_t *out_pOut, const wchar_t *pIn, int iLength ) { wcsncpy( out_pOut, pIn, iLength ); }
  350. static int Compare( const wchar_t *pLhs, const wchar_t *pRhs ) { return wcscmp( pLhs, pRhs ); }
  351. static int Length( const wchar_t *pValue ) { return (int) wcslen( pValue ); }
  352. static const wchar_t *FindChar( const wchar_t *pStr, const wchar_t cSearch ) { return wcschr( pStr, cSearch ); }
  353. static const wchar_t *EmptyString() { return L""; }
  354. };
  355. //-----------------------------------------------------------------------------
  356. // Dirt-basic auto-release string class. Not intended for manipulation,
  357. // can be stored in a container or forwarded as a functor parameter.
  358. // Note the benefit over CUtlString: sizeof(CUtlConstString) == sizeof(char*).
  359. // Also note: null char* pointers are treated identically to empty strings.
  360. //-----------------------------------------------------------------------------
  361. template < typename T = char >
  362. class CUtlConstStringBase
  363. {
  364. public:
  365. CUtlConstStringBase() : m_pString( NULL ) {}
  366. CUtlConstStringBase( const T *pString ) : m_pString( NULL ) { Set( pString ); }
  367. CUtlConstStringBase( const CUtlConstStringBase& src ) : m_pString( NULL ) { Set( src.m_pString ); }
  368. ~CUtlConstStringBase() { Set( NULL ); }
  369. void Set( const T *pValue );
  370. void Clear() { Set( NULL ); }
  371. const T *Get() const { return m_pString ? m_pString : StringFuncs<T>::EmptyString(); }
  372. operator const T*() const { return m_pString ? m_pString : StringFuncs<T>::EmptyString(); }
  373. bool IsEmpty() const { return m_pString == NULL; } // Note: empty strings are never stored by Set
  374. int Compare( const T *rhs ) const;
  375. // Logical ops
  376. bool operator<( const T *rhs ) const { return Compare( rhs ) < 0; }
  377. bool operator==( const T *rhs ) const { return Compare( rhs ) == 0; }
  378. bool operator!=( const T *rhs ) const { return Compare( rhs ) != 0; }
  379. bool operator<( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) < 0; }
  380. bool operator==( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) == 0; }
  381. bool operator!=( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) != 0; }
  382. // If these are not defined, CUtlConstString as rhs will auto-convert
  383. // to const char* and do logical operations on the raw pointers. Ugh.
  384. inline friend bool operator<( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) > 0; }
  385. inline friend bool operator==( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) == 0; }
  386. inline friend bool operator!=( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) != 0; }
  387. CUtlConstStringBase &operator=( const T *src ) { Set( src ); return *this; }
  388. CUtlConstStringBase &operator=( const CUtlConstStringBase &src ) { Set( src.m_pString ); return *this; }
  389. // Defining AltArgumentType_t is a hint to containers that they should
  390. // implement Find/Insert/Remove functions that take const char* params.
  391. typedef const T *AltArgumentType_t;
  392. protected:
  393. const T *m_pString;
  394. };
  395. template < typename T >
  396. void CUtlConstStringBase<T>::Set( const T *pValue )
  397. {
  398. if ( pValue != m_pString )
  399. {
  400. free( ( void* ) m_pString );
  401. m_pString = pValue && pValue[0] ? StringFuncs<T>::Duplicate( pValue ) : NULL;
  402. }
  403. }
  404. template < typename T >
  405. int CUtlConstStringBase<T>::Compare( const T *rhs ) const
  406. {
  407. if ( m_pString )
  408. {
  409. if ( rhs )
  410. return StringFuncs<T>::Compare( m_pString, rhs );
  411. else
  412. return 1;
  413. }
  414. else
  415. {
  416. if ( rhs )
  417. return -1;
  418. else
  419. return 0;
  420. }
  421. }
  422. inline CUtlString CUtlString::operator+( const char *pOther )const
  423. {
  424. CUtlString s = *this;
  425. s += pOther;
  426. return s;
  427. }
  428. typedef CUtlConstStringBase<char> CUtlConstString;
  429. typedef CUtlConstStringBase<wchar_t> CUtlConstWideString;
  430. //-----------------------------------------------------------------------------
  431. // Purpose: General purpose string class good for when it
  432. // is rarely expected to be empty, and/or will undergo
  433. // many modifications/appends.
  434. //-----------------------------------------------------------------------------
  435. class CUtlStringBuilder
  436. {
  437. public:
  438. CUtlStringBuilder();
  439. CUtlStringBuilder(const char *pchString);
  440. CUtlStringBuilder(CUtlStringBuilder const &string);
  441. explicit CUtlStringBuilder(size_t nPreallocateBytes);
  442. //CUtlStringBuilder( const CUtlStringResult &strMoveSource );
  443. //explicit CUtlStringBuilder( IFillStringFunctor& func );
  444. ~CUtlStringBuilder();
  445. // operator=
  446. CUtlStringBuilder &operator=(const CUtlStringBuilder &src);
  447. CUtlStringBuilder &operator=(const char *pchString);
  448. //CUtlStringBuilder &operator=( const CUtlStringResult &strMoveSource );
  449. // operator==
  450. bool operator==(CUtlStringBuilder const &src) const;
  451. bool operator==(const char *pchString) const;
  452. // operator!=
  453. bool operator!=(CUtlStringBuilder const &src) const;
  454. bool operator!=(const char *pchString) const;
  455. // operator </>, performs case sensitive comparison
  456. bool operator<(const CUtlStringBuilder &val) const;
  457. bool operator<(const char *pchString) const;
  458. bool operator>(const CUtlStringBuilder &val) const;
  459. bool operator>(const char *pchString) const;
  460. // operator+=
  461. CUtlStringBuilder &operator+=(const char *rhs);
  462. // is valid?
  463. bool IsValid() const;
  464. // gets the string
  465. // never returns NULL, use IsValid() to see if it's never been set
  466. const char *String() const;
  467. const char *Get() const { return String(); }
  468. operator const char *() const { return String(); }
  469. // returns the string directly (could be NULL)
  470. // useful for doing inline operations on the string
  471. char *Access()
  472. {
  473. // aggressive warning that there has been a bad error;
  474. // probably should not be retrieving the string by pointer.
  475. Assert(!m_data.HasError());
  476. if (!IsValid() || (Capacity() == 0))
  477. return NULL;
  478. return m_data.Access();
  479. }
  480. // return false if capacity can't be set. If false is returned,
  481. // the error state is set.
  482. bool EnsureCapacity(size_t nLength);
  483. // append in-place, causing a re-allocation
  484. void Append(const char *pchAddition);
  485. void Append(const char *pchAddition, size_t cbLen);
  486. void Append(const CUtlStringBuilder &str) { Append(str.String(), str.Length()); }
  487. //void Append( IFillStringFunctor& func );
  488. void AppendChar(char ch) { Append(&ch, 1); }
  489. void AppendRepeat(char ch, int cCount);
  490. // sets the string
  491. void SetValue(const char *pchString);
  492. void Set(const char *pchString);
  493. void Clear() { m_data.Clear(); }
  494. void SetPtr(char *pchString);
  495. void SetPtr(char *pchString, size_t nLength);
  496. void Swap(CUtlStringBuilder &src);
  497. // If you want to take ownership of the ptr, you can use this. So for instance if you had
  498. // a CUtlString you wanted to move it to a CUtlStringConst without making a copy, you
  499. // could do: CUtlStringConst strConst( strUtl.Detach() );
  500. // Also used for fast temporaries when a string that does not need to be retained is being
  501. // returned from a func. ie: return (str.Detach());
  502. // All strings in this file can take a CUtlStringResult as a constructor parm and will take ownership directly.
  503. //CUtlStringResult Detach();
  504. // Set directly and don't look for a null terminator in pValue.
  505. // nChars is the string length. "abcd" nChars==3 would copy and null
  506. // terminate "abc" in the string object.
  507. void SetDirect(const char *pchString, size_t nChars);
  508. // Get the length of the string in characters.
  509. size_t Length() const;
  510. bool IsEmpty() const;
  511. size_t Capacity() const { return m_data.Capacity(); } // how much room is there to scribble
  512. #if !defined(SWIG)
  513. // SWIG fails on PRINTF_FORMAT_STRING
  514. // Format like sprintf.
  515. size_t Format(PRINTF_FORMAT_STRING const char *pFormat, ...) FMTFUNCTION(2, 3);
  516. // format, then append what we crated in the format
  517. size_t AppendFormat(PRINTF_FORMAT_STRING const char *pFormat, ...) FMTFUNCTION(2, 3);
  518. #else
  519. size_t Format(const char *pFormat, ...);
  520. size_t AppendFormat(const char *pFormat, ...);
  521. #endif
  522. // replace a single character with another, returns hit count
  523. size_t Replace(char chTarget, char chReplacement);
  524. // replace a string with another string, returns hit count
  525. // replacement string might be NULL or "" to remove target substring
  526. size_t Replace(const char *pstrTarget, const char *pstrReplacement);
  527. // ASCII-only case-insensitivity.
  528. size_t ReplaceFastCaseless(const char *pstrTarget, const char *pstrReplacement);
  529. // replace a sequence of characters at a given point with a new string
  530. // replacement string might be NULL or "" to remove target substring
  531. bool ReplaceAt(size_t nIndex, size_t nOldChars, const char *pNewStr, size_t nNewChars = SIZE_MAX);
  532. ptrdiff_t IndexOf(const char *pstrTarget) const;
  533. // remove whitespace from the string; anything that is isspace()
  534. size_t RemoveWhitespace();
  535. // trim whitepace from the beginning and end of the string
  536. size_t TrimWhitespace();
  537. // Allows setting the size to anything under the current
  538. // capacity. Typically should not be used unless there was a specific
  539. // reason to scribble on the string. Will not touch the string contents,
  540. // but will append a NULL. Returns true if the length was changed.
  541. bool SetLength(size_t nLen);
  542. // Take responsibility for the string. May cause a heap alloc.
  543. char *TakeOwnership(size_t *pnLen, size_t *pnCapacity);
  544. // For operations that are long and/or complex - if something fails
  545. // along the way, the error will be set and can be queried at the end.
  546. // The string is undefined in the error state, but will likely hold the
  547. // last value before the error occurred. The string is cleared
  548. // if ClearError() is called. The error can be set be the user, and it
  549. // will also be set if a dynamic allocation fails in string operations
  550. // where it needs to grow the capacity.
  551. void SetError() { m_data.SetError(true); }
  552. void ClearError() { m_data.ClearError(); }
  553. bool HasError() const { return m_data.HasError(); }
  554. #ifdef DBGFLAG_VALIDATE
  555. void Validate(CValidator &validator, const char *pchName); // validate our internal structures
  556. #endif // DBGFLAG_VALIDATE
  557. size_t VFormat(const char *pFormat, va_list args);
  558. size_t VAppendFormat(const char *pFormat, va_list args);
  559. void Truncate(size_t nChars);
  560. // Access() With no assertion check - should only be used for tests
  561. char *AccessNoAssert()
  562. {
  563. if (!IsValid())
  564. return NULL;
  565. return m_data.Access();
  566. }
  567. // SetError() With no assertion check - should only be used for tests
  568. void SetErrorNoAssert() { m_data.SetError(false); }
  569. size_t ReplaceCaseless(const char *pstrTarget, const char *pstrReplacement) {
  570. return ReplaceFastCaseless(pstrTarget, pstrReplacement);
  571. }
  572. private:
  573. size_t ReplaceInternal(const char *pstrTarget, const char *pstrReplacement, const char *pfnCompare(const char*, const char*));
  574. operator bool() const { return IsValid(); }
  575. // nChars is the number of characters you want, NOT including the null
  576. char *PrepareBuffer(size_t nChars, bool bCopyOld = false, size_t nMinCapacity = 0)
  577. {
  578. char *pszString = NULL;
  579. size_t nCapacity = m_data.Capacity();
  580. if ((nChars <= nCapacity) && (nMinCapacity <= nCapacity))
  581. {
  582. // early out leaving it all alone, just update the length,
  583. // even if it shortens an existing heap string to a width
  584. // that would fit in the stack buffer.
  585. pszString = m_data.SetLength(nChars);
  586. // SetLength will have added the null. Pointer might
  587. // be NULL if there is an error state and no buffer
  588. Assert(!pszString || pszString[nChars] == '\0');
  589. return pszString;
  590. }
  591. if (HasError())
  592. return NULL;
  593. // Need to actually adjust the capacity
  594. return InternalPrepareBuffer(nChars, bCopyOld, Max(nChars, nMinCapacity));
  595. }
  596. char *InternalPrepareBuffer(size_t nChars, bool bCopyOld, size_t nMinCapacity);
  597. template <typename T>
  598. void Swap(T &p1, T &p2)
  599. {
  600. T t = p1;
  601. p1 = p2;
  602. p2 = t;
  603. }
  604. // correct for 32 or 64 bit
  605. static const uint8 MAX_STACK_STRLEN = (sizeof(void*) == 4 ? 15 : 19);
  606. enum
  607. {
  608. // Note: If it's ever desired to have the embedded string be larger than
  609. // 63 (0x40-1), just make the sentinal 0xFF, and the error something (0xFF also
  610. // is fine). Then shrink the scrap size by 1 and add a uint8 for the error state.
  611. // The error byte is only valid if the heap is on (already have that restriction).
  612. // and then embedded strings can get back to being up to 254. It's not done this
  613. // way now just to make the tests for IsHeap()/HasError() faster since they
  614. // are often both tested together the compiler can do nice bit test optimizations.
  615. STRING_TYPE_SENTINEL = 0x80,
  616. STRING_TYPE_ERROR = 0x40
  617. }; // if Data.Stack.BytesLeft() or Data.Heap.sentinel == this value, data is in heap
  618. union Data
  619. {
  620. struct _Heap
  621. { // 16 on 32 bit, sentinel == 0xff if Heap is the active union item
  622. private:
  623. char *m_pchString;
  624. uint32 m_nLength;
  625. uint32 m_nCapacity; // without trailing null; ie: m_pchString[m_nCapacity] = '\0' is not out of bounds
  626. uint8 scrap[3];
  627. uint8 sentinel;
  628. public:
  629. friend union Data;
  630. friend char *CUtlStringBuilder::InternalPrepareBuffer(size_t, bool, size_t);
  631. } Heap;
  632. struct _Stack
  633. {
  634. private:
  635. // last byte is doing a hack double duty. It holds how many bytes
  636. // are left in the string; so when the string is 'full' it will be
  637. // '0' and thus suffice as the terminating null. This is why
  638. // we hold remaining chars instead of 'string length'
  639. char m_szString[MAX_STACK_STRLEN + 1];
  640. public:
  641. uint8 BytesLeft() const { return (uint8)(m_szString[MAX_STACK_STRLEN]); }
  642. void SetBytesLeft(char n) { m_szString[MAX_STACK_STRLEN] = n; }
  643. friend char *CUtlStringBuilder::InternalPrepareBuffer(size_t, bool, size_t);
  644. friend union Data;
  645. } Stack;
  646. // set to a clear state without looking at the current state
  647. void Construct()
  648. {
  649. Stack.m_szString[0] = '\0';
  650. Stack.SetBytesLeft(MAX_STACK_STRLEN);
  651. }
  652. // If we have heap allocated data, free it
  653. void FreeHeap()
  654. {
  655. if (IsHeap() && Heap.m_pchString)
  656. MemAlloc_Free(Heap.m_pchString);
  657. }
  658. // Back to a clean state, but retain the error state.
  659. void Clear()
  660. {
  661. if (HasError())
  662. return;
  663. FreeHeap();
  664. Heap.m_pchString = NULL;
  665. Construct();
  666. }
  667. bool IsHeap() const { return ((Heap.sentinel & STRING_TYPE_SENTINEL) != 0); }
  668. char *Access() { return IsHeap() ? Heap.m_pchString : Stack.m_szString; }
  669. const char *String() const { return IsHeap() ? Heap.m_pchString : Stack.m_szString; }
  670. size_t Length() const { return IsHeap() ? Heap.m_nLength : (MAX_STACK_STRLEN - Stack.BytesLeft()); }
  671. bool IsEmpty() const
  672. {
  673. if (IsHeap())
  674. return Heap.m_nLength == 0;
  675. else
  676. return Stack.BytesLeft() == MAX_STACK_STRLEN; // empty if all the bytes are available
  677. }
  678. size_t Capacity() const { return IsHeap() ? Heap.m_nCapacity : MAX_STACK_STRLEN; }
  679. // Internally the code often needs the char * after setting the length, so
  680. // just return it from here for conveniences.
  681. char *SetLength(size_t nChars);
  682. // Give the string away and set to an empty state
  683. char *TakeOwnership(size_t &nLen, size_t &nCapacity)
  684. {
  685. MoveToHeap();
  686. if (HasError())
  687. {
  688. nLen = 0;
  689. nCapacity = 0;
  690. return NULL;
  691. }
  692. nLen = Heap.m_nLength;
  693. nCapacity = Heap.m_nCapacity;
  694. char *psz = Heap.m_pchString;
  695. Construct();
  696. return psz;
  697. }
  698. void SetPtr(char *pchString, size_t nLength);
  699. // Set the string to an error state
  700. void SetError(bool bEnableAssert);
  701. // clear the error state and reset the string
  702. void ClearError();
  703. // If string is in the heap and the error bit is set in the sentinel
  704. // the error state is true.
  705. bool HasError() const { return IsHeap() && ((Heap.sentinel & STRING_TYPE_ERROR) != 0); }
  706. // If it's stack based, get it to the heap and return if it is
  707. // successfully on the heap (or already was)
  708. bool MoveToHeap();
  709. private:
  710. //-----------------------------------------------------------------------------
  711. // Purpose: Needed facts for string class to work
  712. //-----------------------------------------------------------------------------
  713. void StaticAssertTests()
  714. {
  715. // If this fails when the heap sentinel and where the stack string stores its bytes left
  716. // aren't aliases. This is needed so that regardless of how the 'sentinel' to mark
  717. // that the string is on the heap is set, it is set as expected on both sides of the union.
  718. COMPILE_TIME_ASSERT(offsetof(_Heap, sentinel) == (offsetof(_Stack, m_szString) + MAX_STACK_STRLEN));
  719. // Lots of code assumes it can look at m_data.Stack.m_nBytesLeft for an empty string; which
  720. // means that it will equal MAX_STACK_STRLEN. Therefor it must be a different value than
  721. // the STRING_TYPE_SENTINEL which will be set if the string is in the heap.
  722. COMPILE_TIME_ASSERT(MAX_STACK_STRLEN < STRING_TYPE_SENTINEL);
  723. COMPILE_TIME_ASSERT(MAX_STACK_STRLEN < STRING_TYPE_ERROR);
  724. // this is a no brainer, and I don't know anywhere in the world this isn't true,
  725. // but this code does take this dependency.
  726. COMPILE_TIME_ASSERT(0 == '\0');
  727. }
  728. };
  729. private: // data
  730. Data m_data;
  731. };
  732. //-----------------------------------------------------------------------------
  733. // Purpose: constructor
  734. //-----------------------------------------------------------------------------
  735. inline CUtlStringBuilder::CUtlStringBuilder()
  736. {
  737. m_data.Construct();
  738. }
  739. //-----------------------------------------------------------------------------
  740. // Purpose: constructor
  741. //-----------------------------------------------------------------------------
  742. inline CUtlStringBuilder::CUtlStringBuilder(size_t nPreallocateBytes)
  743. {
  744. if (nPreallocateBytes <= MAX_STACK_STRLEN)
  745. {
  746. m_data.Construct();
  747. }
  748. else
  749. {
  750. m_data.Construct();
  751. PrepareBuffer(0, false, nPreallocateBytes);
  752. }
  753. }
  754. //-----------------------------------------------------------------------------
  755. // Purpose: constructor
  756. //-----------------------------------------------------------------------------
  757. inline CUtlStringBuilder::CUtlStringBuilder(const char *pchString)
  758. {
  759. m_data.Construct();
  760. SetDirect(pchString, pchString ? strlen(pchString) : 0);
  761. }
  762. //-----------------------------------------------------------------------------
  763. // Purpose: constructor
  764. //-----------------------------------------------------------------------------
  765. inline CUtlStringBuilder::CUtlStringBuilder(CUtlStringBuilder const &string)
  766. {
  767. m_data.Construct();
  768. SetDirect(string.String(), string.Length());
  769. // attempt the copy before checking for error. On the off chance there
  770. // is data there that can be set, it will help with debugging.
  771. if (string.HasError())
  772. m_data.SetError(false);
  773. }
  774. //-----------------------------------------------------------------------------
  775. // Purpose: destructor
  776. //-----------------------------------------------------------------------------
  777. inline CUtlStringBuilder::~CUtlStringBuilder()
  778. {
  779. m_data.FreeHeap();
  780. }
  781. //-----------------------------------------------------------------------------
  782. // Purpose: Pre-Widen a string to an expected length
  783. //-----------------------------------------------------------------------------
  784. inline bool CUtlStringBuilder::EnsureCapacity(size_t nLength)
  785. {
  786. return PrepareBuffer(Length(), true, nLength) != NULL;
  787. }
  788. //-----------------------------------------------------------------------------
  789. // Purpose: ask if the string has anything in it
  790. //-----------------------------------------------------------------------------
  791. inline bool CUtlStringBuilder::IsEmpty() const
  792. {
  793. return m_data.IsEmpty();
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Purpose: assignment
  797. //-----------------------------------------------------------------------------
  798. inline CUtlStringBuilder &CUtlStringBuilder::operator=(const char *pchString)
  799. {
  800. SetDirect(pchString, pchString ? strlen(pchString) : 0);
  801. return *this;
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Purpose: assignment
  805. //-----------------------------------------------------------------------------
  806. inline CUtlStringBuilder &CUtlStringBuilder::operator=(CUtlStringBuilder const &src)
  807. {
  808. if (&src != this)
  809. {
  810. SetDirect(src.String(), src.Length());
  811. // error propagate
  812. if (src.HasError())
  813. m_data.SetError(false);
  814. }
  815. return *this;
  816. }
  817. //-----------------------------------------------------------------------------
  818. // Purpose: comparison
  819. //-----------------------------------------------------------------------------
  820. inline bool CUtlStringBuilder::operator==(CUtlStringBuilder const &src) const
  821. {
  822. return !Q_strcmp(String(), src.String());
  823. }
  824. //-----------------------------------------------------------------------------
  825. // Purpose: comparison
  826. //-----------------------------------------------------------------------------
  827. inline bool CUtlStringBuilder::operator==(const char *pchString) const
  828. {
  829. return !Q_strcmp(String(), pchString);
  830. }
  831. //-----------------------------------------------------------------------------
  832. // Purpose: comparison
  833. //-----------------------------------------------------------------------------
  834. inline bool CUtlStringBuilder::operator!=(CUtlStringBuilder const &src) const
  835. {
  836. return !(*this == src);
  837. }
  838. //-----------------------------------------------------------------------------
  839. // Purpose: comparison
  840. //-----------------------------------------------------------------------------
  841. inline bool CUtlStringBuilder::operator!=(const char *pchString) const
  842. {
  843. return !(*this == pchString);
  844. }
  845. //-----------------------------------------------------------------------------
  846. // Purpose: comparison
  847. //-----------------------------------------------------------------------------
  848. inline bool CUtlStringBuilder::operator<(CUtlStringBuilder const &val) const
  849. {
  850. return operator<(val.String());
  851. }
  852. //-----------------------------------------------------------------------------
  853. // Purpose: comparison
  854. //-----------------------------------------------------------------------------
  855. inline bool CUtlStringBuilder::operator<(const char *pchString) const
  856. {
  857. return Q_strcmp(String(), pchString) < 0;
  858. }
  859. //-----------------------------------------------------------------------------
  860. // Purpose: comparison
  861. //-----------------------------------------------------------------------------
  862. inline bool CUtlStringBuilder::operator>(CUtlStringBuilder const &val) const
  863. {
  864. return Q_strcmp(String(), val.String()) > 0;
  865. }
  866. //-----------------------------------------------------------------------------
  867. // Purpose: comparison
  868. //-----------------------------------------------------------------------------
  869. inline bool CUtlStringBuilder::operator>(const char *pchString) const
  870. {
  871. return Q_strcmp(String(), pchString) > 0;
  872. }
  873. //-----------------------------------------------------------------------------
  874. // Return a string with this string and rhs joined together.
  875. inline CUtlStringBuilder& CUtlStringBuilder::operator+=(const char *rhs)
  876. {
  877. Append(rhs);
  878. return *this;
  879. }
  880. //-----------------------------------------------------------------------------
  881. // Purpose: returns true if the string is not null
  882. //-----------------------------------------------------------------------------
  883. inline bool CUtlStringBuilder::IsValid() const
  884. {
  885. return !HasError();
  886. }
  887. //-----------------------------------------------------------------------------
  888. // Purpose: data accessor
  889. //-----------------------------------------------------------------------------
  890. inline const char *CUtlStringBuilder::String() const
  891. {
  892. const char *pszString = m_data.String();
  893. if (pszString)
  894. return pszString;
  895. // pszString can be NULL in the error state. For const char*
  896. // never return NULL.
  897. return "";
  898. }
  899. //-----------------------------------------------------------------------------
  900. // Purpose: Sets the string to be the new value, taking a copy of it
  901. //-----------------------------------------------------------------------------
  902. inline void CUtlStringBuilder::SetValue(const char *pchString)
  903. {
  904. size_t nLen = (pchString ? strlen(pchString) : 0);
  905. SetDirect(pchString, nLen);
  906. }
  907. //-----------------------------------------------------------------------------
  908. // Purpose: Set directly and don't look for a null terminator in pValue.
  909. //-----------------------------------------------------------------------------
  910. inline void CUtlStringBuilder::SetDirect(const char *pchSource, size_t nChars)
  911. {
  912. if (HasError())
  913. return;
  914. if (m_data.IsHeap() && Get() == pchSource)
  915. return;
  916. if (!pchSource || !nChars)
  917. {
  918. m_data.Clear();
  919. return;
  920. }
  921. char *pszString = PrepareBuffer(nChars);
  922. if (pszString)
  923. {
  924. memcpy(pszString, pchSource, nChars);
  925. // PrepareBuffer already allocated space for the terminating null,
  926. // and inserted it for us. Make sure we didn't clobber it.
  927. // Also assign it anyways so we don't risk the caller having a buffer
  928. // running into random bytes.
  929. #ifdef _DEBUG
  930. // Suppress a bogus noisy warning:
  931. // warning C6385: Invalid data: accessing 'pszString', the readable size is 'nChars' bytes, but '1001' bytes might be read
  932. ANALYZE_SUPPRESS(6385);
  933. Assert(pszString[nChars] == '\0');
  934. pszString[nChars] = '\0';
  935. #endif
  936. }
  937. }
  938. //-----------------------------------------------------------------------------
  939. // Purpose: Sets the string to be the new value, taking a copy of it
  940. //-----------------------------------------------------------------------------
  941. inline void CUtlStringBuilder::Set(const char *pchString)
  942. {
  943. SetValue(pchString);
  944. }
  945. //-----------------------------------------------------------------------------
  946. // Purpose: Sets the string to be the new value, taking ownership of the pointer
  947. //-----------------------------------------------------------------------------
  948. inline void CUtlStringBuilder::SetPtr(char *pchString)
  949. {
  950. size_t nLength = pchString ? strlen(pchString) : 0;
  951. SetPtr(pchString, nLength);
  952. }
  953. //-----------------------------------------------------------------------------
  954. // Purpose: Sets the string to be the new value, taking ownership of the pointer
  955. // This API will clear the error state if it was set.
  956. //-----------------------------------------------------------------------------
  957. inline void CUtlStringBuilder::SetPtr(char *pchString, size_t nLength)
  958. {
  959. m_data.Clear();
  960. if (!pchString || !nLength)
  961. {
  962. if (pchString)
  963. MemAlloc_Free(pchString); // we don't hang onto empty strings.
  964. return;
  965. }
  966. m_data.SetPtr(pchString, nLength);
  967. }
  968. //-----------------------------------------------------------------------------
  969. // Purpose: return the conceptual 'strlen' of the string.
  970. //-----------------------------------------------------------------------------
  971. inline size_t CUtlStringBuilder::Length() const
  972. {
  973. return m_data.Length();
  974. }
  975. //-----------------------------------------------------------------------------
  976. // Purpose: format something sprintf() style, and take it as the new value of this CUtlStringBuilder
  977. //-----------------------------------------------------------------------------
  978. inline size_t CUtlStringBuilder::Format(const char *pFormat, ...)
  979. {
  980. va_list args;
  981. va_start(args, pFormat);
  982. size_t nLen = VFormat(pFormat, args);
  983. va_end(args);
  984. return nLen;
  985. }
  986. int V_vscprintf(const char *format, va_list argptr);
  987. //-----------------------------------------------------------------------------
  988. // Purpose: Helper for Format() method
  989. //-----------------------------------------------------------------------------
  990. inline size_t CUtlStringBuilder::VFormat(const char *pFormat, va_list args)
  991. {
  992. if (HasError())
  993. return 0;
  994. int len = 0;
  995. #ifdef _WIN32
  996. // how much space will we need?
  997. len = V_vscprintf(pFormat, args);
  998. #else
  999. // ISO spec defines the NULL/0 case as being valid and will return the
  1000. // needed length. Verified on PS3 as well. Ignore that bsd/linux/mac
  1001. // have vasprintf which will allocate a buffer. We'd rather have the
  1002. // self growing buffer management ourselves. Even the best implementations
  1003. // There does not seem to be a magic vasprintf that is significantly
  1004. // faster than 2 passes (some guess and get lucky).
  1005. // Scope ReuseArgs.
  1006. {
  1007. CReuseVaList ReuseArgs(args);
  1008. len = V_vsnprintf(NULL, 0, pFormat, ReuseArgs.m_ReuseList);
  1009. }
  1010. #endif
  1011. if (len > 0)
  1012. {
  1013. // get it
  1014. char *pszString = PrepareBuffer(len, true);
  1015. if (pszString)
  1016. len = V_vsnprintf(pszString, len + 1, pFormat, args);
  1017. else
  1018. len = 0;
  1019. }
  1020. Assert(len > 0 || HasError());
  1021. return len;
  1022. }
  1023. //-----------------------------------------------------------------------------
  1024. // format a string and append the result to the string we hold
  1025. //-----------------------------------------------------------------------------
  1026. inline size_t CUtlStringBuilder::AppendFormat(const char *pFormat, ...)
  1027. {
  1028. va_list args;
  1029. va_start(args, pFormat);
  1030. size_t nLen = VAppendFormat(pFormat, args);
  1031. va_end(args);
  1032. return nLen;
  1033. }
  1034. //-----------------------------------------------------------------------------
  1035. // Purpose: implementation helper for AppendFormat()
  1036. //-----------------------------------------------------------------------------
  1037. inline size_t CUtlStringBuilder::VAppendFormat(const char *pFormat, va_list args)
  1038. {
  1039. if (HasError())
  1040. return 0;
  1041. int len = 0;
  1042. #ifdef _WIN32
  1043. // how much space will we need?
  1044. len = _vscprintf(pFormat, args);
  1045. #else
  1046. // ISO spec defines the NULL/0 case as being valid and will return the
  1047. // needed length. Verified on PS3 as well. Ignore that bsd/linux/mac
  1048. // have vasprintf which will allocate a buffer. We'd rather have the
  1049. // self growing buffer management ourselves. Even the best implementations
  1050. // There does not seem to be a magic vasprintf that is significantly
  1051. // faster than 2 passes (some guess and get lucky).
  1052. // Scope ReuseArgs.
  1053. {
  1054. CReuseVaList ReuseArgs(args);
  1055. len = vsnprintf(NULL, 0, pFormat, ReuseArgs.m_ReuseList);
  1056. }
  1057. #endif
  1058. size_t nOldLen = Length();
  1059. if (len > 0)
  1060. {
  1061. // get it
  1062. char *pszString = PrepareBuffer(nOldLen + len, true);
  1063. if (pszString)
  1064. len = _vsnprintf(&pszString[nOldLen], len + 1, pFormat, args);
  1065. else
  1066. len = 0;
  1067. }
  1068. Assert(len > 0 || HasError());
  1069. return nOldLen + len;
  1070. }
  1071. //-----------------------------------------------------------------------------
  1072. // Purpose: concatenate the provided string to our current content
  1073. //-----------------------------------------------------------------------------
  1074. inline void CUtlStringBuilder::Append(const char *pchAddition)
  1075. {
  1076. if (pchAddition && pchAddition[0])
  1077. {
  1078. size_t cchLen = strlen(pchAddition);
  1079. Append(pchAddition, cchLen);
  1080. }
  1081. }
  1082. //-----------------------------------------------------------------------------
  1083. // Purpose: concatenate the provided string to our current content
  1084. // when the additional string length is known
  1085. //-----------------------------------------------------------------------------
  1086. inline void CUtlStringBuilder::Append(const char *pchAddition, size_t cbLen)
  1087. {
  1088. if (pchAddition && pchAddition[0] && cbLen)
  1089. {
  1090. if (IsEmpty())
  1091. {
  1092. SetDirect(pchAddition, cbLen);
  1093. }
  1094. else
  1095. {
  1096. size_t cbOld = Length();
  1097. char *pstrNew = PrepareBuffer(cbOld + cbLen, true);
  1098. // make sure we use raw memcpy to get intrinsic
  1099. if (pstrNew)
  1100. memcpy(pstrNew + cbOld, pchAddition, cbLen);
  1101. }
  1102. }
  1103. }
  1104. //-----------------------------------------------------------------------------
  1105. // Purpose: append a repeated series of a single character
  1106. //-----------------------------------------------------------------------------
  1107. inline void CUtlStringBuilder::AppendRepeat(char ch, int cCount)
  1108. {
  1109. size_t cbOld = Length();
  1110. char *pstrNew = PrepareBuffer(cbOld + cCount, true);
  1111. if (pstrNew)
  1112. memset(pstrNew + cbOld, ch, cCount);
  1113. }
  1114. //-----------------------------------------------------------------------------
  1115. // Purpose: Swaps string contents
  1116. //-----------------------------------------------------------------------------
  1117. inline void CUtlStringBuilder::Swap(CUtlStringBuilder &src)
  1118. {
  1119. // swapping m_data instead of '*this' prevents having to
  1120. // copy dynamic strings. Important that m_data doesn't know
  1121. // any lifetime rules about its members (ie: it should not have
  1122. // a destructor that frees the dynamic string pointer).
  1123. Swap(m_data, src.m_data);
  1124. }
  1125. //-----------------------------------------------------------------------------
  1126. // Purpose: replace all occurrences of one character with another
  1127. //-----------------------------------------------------------------------------
  1128. inline size_t CUtlStringBuilder::Replace(char chTarget, char chReplacement)
  1129. {
  1130. size_t cReplacements = 0;
  1131. if (!IsEmpty() && !HasError())
  1132. {
  1133. char *pszString = Access();
  1134. for (char *pstrWalker = pszString; *pstrWalker != 0; pstrWalker++)
  1135. {
  1136. if (*pstrWalker == chTarget)
  1137. {
  1138. *pstrWalker = chReplacement;
  1139. cReplacements++;
  1140. }
  1141. }
  1142. }
  1143. return cReplacements;
  1144. }
  1145. //-----------------------------------------------------------------------------
  1146. // replace a sequence of characters at a given point with a new string
  1147. // replacement string might be NULL or "" to remove target substring
  1148. //-----------------------------------------------------------------------------
  1149. inline bool CUtlStringBuilder::ReplaceAt(size_t nIndex, size_t nOldChars, const char *pNewStr, size_t nNewChars)
  1150. {
  1151. Assert(nIndex < Length() && nIndex + nOldChars <= Length());
  1152. if (nNewChars == SIZE_MAX)
  1153. {
  1154. nNewChars = pNewStr ? V_strlen(pNewStr) : 0;
  1155. }
  1156. size_t nOldLength = Length();
  1157. ptrdiff_t nDelta = nNewChars - nOldChars;
  1158. if (nDelta < 0)
  1159. {
  1160. char *pBuf = Access();
  1161. memmove(pBuf + nIndex + nNewChars, pBuf + nIndex + nOldChars, nOldLength - nIndex - nOldChars);
  1162. SetLength(nOldLength + nDelta);
  1163. }
  1164. else if (nDelta > 0)
  1165. {
  1166. char *pBuf = PrepareBuffer(nOldLength + nDelta, true);
  1167. if (!pBuf)
  1168. {
  1169. return false;
  1170. }
  1171. memmove(pBuf + nIndex + nNewChars, pBuf + nIndex + nOldChars, nOldLength - nIndex - nOldChars);
  1172. }
  1173. if (nNewChars)
  1174. {
  1175. memcpy(Access() + nIndex, pNewStr, nNewChars);
  1176. }
  1177. return true;
  1178. }
  1179. //-----------------------------------------------------------------------------
  1180. //-----------------------------------------------------------------------------
  1181. // Purpose: Truncates the string to the specified number of characters
  1182. //-----------------------------------------------------------------------------
  1183. inline void CUtlStringBuilder::Truncate(size_t nChars)
  1184. {
  1185. if (IsEmpty() || HasError())
  1186. return;
  1187. size_t nLen = Length();
  1188. if (nLen <= nChars)
  1189. return;
  1190. // we may be shortening enough to fit in the small buffer, but
  1191. // the external buffer is already allocated, so just keep using it.
  1192. m_data.SetLength(nChars);
  1193. }
  1194. //-----------------------------------------------------------------------------
  1195. // Data and memory validation
  1196. //-----------------------------------------------------------------------------
  1197. #ifdef DBGFLAG_VALIDATE
  1198. inline void CUtlStringBuilder::Validate(CValidator &validator, const char *pchName)
  1199. {
  1200. #ifdef _WIN32
  1201. validator.Push(typeid(*this).raw_name(), this, pchName);
  1202. #else
  1203. validator.Push(typeid(*this).name(), this, pchName);
  1204. #endif
  1205. if (m_data.IsHeap())
  1206. validator.ClaimMemory(Access());
  1207. validator.Pop();
  1208. }
  1209. #endif // DBGFLAG_VALIDATE
  1210. #endif // UTLSTRING_H