/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. // Description : Stack-based fixed-size String class, similar to CryString. // will switch to heap-based allocation when string does no longer fit // Can easily be substituted instead of CryString. #ifndef CRYINCLUDE_CRYCOMMON_CRYFIXEDSTRING_H #define CRYINCLUDE_CRYCOMMON_CRYFIXEDSTRING_H #pragma once #include #include #include #include #include #include #include #include "CryString.h" #ifndef CRY_STRING_DEBUG #define CRY_STRING_DEBUG(s) #endif #define UNITTEST_CRYFIXEDSTRING (0) template class CharTraits; // traits for char template <> class CharTraits { public: typedef size_t size_type; typedef char value_type; typedef const value_type* const_str; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef pointer iterator; typedef const_pointer const_iterator; ILINE int _isspace(value_type c) const { return ::isspace((int)c); } ILINE value_type _traits_toupper(value_type c) const { return static_cast(toupper(c)); } ILINE value_type _traits_tolower(value_type c) const { return static_cast(tolower(c)); } ILINE value_type _ascii_tolower(value_type c) const { return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } ILINE value_type _ascii_toupper(value_type c) const { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } ILINE int _strcmp (const_str a, const_str b) const { return ::strcmp(a, b); } ILINE int _strncmp (const_str a, const_str b, size_type n) const { return ::strncmp(a, b, n); } ILINE int _stricmp (const_str a, const_str b) const { return ::azstricmp(a, b); } ILINE int _strnicmp (const_str a, const_str b, size_type n) const { return ::azstrnicmp(a, b, n); } ILINE size_type _strspn(const_str str, const_str strCharSet) const { return (str == NULL) ? 0 : (size_type)::strspn(str, strCharSet); } ILINE size_type _strcspn(const_str str, const_str strCharSet) const { return (str == NULL) ? 0 : (size_type)::strcspn(str, strCharSet); } static ILINE size_type _strlen(const_str str) { return (str == NULL) ? 0 : (size_type)::strlen(str); } ILINE const_str _strchr(const_str str, value_type c) const { return (str == NULL) ? 0 : ::strchr(str, c); } ILINE value_type* _strstr(value_type* str, const_str strSearch) const { return (str == NULL) ? 0 : (value_type*) ::strstr(str, strSearch); } ILINE void _copy(value_type* dest, const value_type* src, size_type count) { memcpy(dest, src, count * sizeof(value_type)); } ILINE void _move(value_type* dest, const value_type* src, size_type count) { memmove(dest, src, count * sizeof(value_type)); } ILINE void _set(value_type* dest, value_type ch, size_type count) { memset(dest, ch, count * sizeof(value_type)); } ILINE int _vsnprintf(value_type* str, size_type size, const_str format, va_list ap) { return ::azvsnprintf(str, size, format, ap); } }; // traits for wchar_t template <> class CharTraits { public: typedef size_t size_type; typedef wchar_t value_type; typedef const value_type* const_str; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef pointer iterator; typedef const_pointer const_iterator; ILINE int _isspace(value_type c) const { return iswspace(c); } ILINE value_type _traits_toupper(value_type c) const { return towupper(c); } ILINE value_type _traits_tolower(value_type c) const { return towlower(c); } ILINE value_type _ascii_tolower(value_type c) const { return ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)); } ILINE value_type _ascii_toupper(value_type c) const { return ((((c) >= 'a') && ((c) <= 'z')) ? ((c) - 'a' + 'A') : (c)); } ILINE int _strcmp (const_str a, const_str b) const { return wcscmp (a, b); } ILINE int _strncmp (const_str a, const_str b, size_type n) const { return wcsncmp (a, b, n); } ILINE int _stricmp (const_str a, const_str b) const { return azwcsicmp(a, b); } ILINE int _strnicmp (const_str a, const_str b, size_type n) const { return azwcsnicmp(a, b, n); } ILINE size_type _strspn(const_str str, const_str strCharSet) const { return (str == NULL) ? 0 : (size_type)::wcsspn(str, strCharSet); } ILINE size_type _strcspn(const_str str, const_str strCharSet) const { return (str == NULL) ? 0 : (size_type)::wcscspn(str, strCharSet); } static ILINE size_type _strlen(const_str str) { return (str == NULL) ? 0 : (size_type)::wcslen(str); } ILINE const_str _strchr(const_str str, value_type c) const { return (str == NULL) ? 0 : ::wcschr(str, c); } ILINE value_type* _strstr(value_type* str, const_str strSearch) const { return (str == NULL) ? 0 : ::wcsstr(str, strSearch); } ILINE void _copy(value_type* dest, const value_type* src, size_type count) { memcpy(dest, src, count * sizeof(value_type)); } ILINE void _move(value_type* dest, const value_type* src, size_type count) { memmove(dest, src, count * sizeof(value_type)); } ILINE void _set(value_type* dest, value_type ch, size_type count) { wmemset(dest, ch, count); } ILINE int _vsnprintf(value_type* str, size_type size, const_str format, va_list ap) { return ::_vsnwprintf_s(str, size + 1, size, format, ap); } }; template class CryStackStringT : public CharTraits { public: ////////////////////////////////////////////////////////////////////////// // Types compatible with STL string. ////////////////////////////////////////////////////////////////////////// typedef CryStackStringT _Self; typedef size_t size_type; typedef T value_type; typedef const value_type* const_str; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef pointer iterator; typedef const_pointer const_iterator; static const size_type MAX_SIZE = S; enum _npos_type { npos = (size_type) ~0 }; ////////////////////////////////////////////////////////////////////////// // Constructors ////////////////////////////////////////////////////////////////////////// CryStackStringT(); public: CryStackStringT(const _Self& str); CryStackStringT(const _Self& str, size_type nOff, size_type nCount); CryStackStringT(size_type nRepeat, value_type ch); // The reason of making this constructor unavailable (for a while) is // explained in comments in front of the declaration of // CryStringT::CryStringT(size_type nRepeat, value_type ch) // (see CryString.h). private: CryStackStringT(value_type ch, size_type nRepeat); public: CryStackStringT(const_str str); CryStackStringT(const CryStringT& str); CryStackStringT(const_str str, size_type nLength); CryStackStringT(const_iterator _First, const_iterator _Last); ~CryStackStringT(); ////////////////////////////////////////////////////////////////////////// // STL string like interface. ////////////////////////////////////////////////////////////////////////// //! Operators. size_type length() const; size_type size() const; bool empty() const; void clear(); // free up the data //! Returns the storage currently allocated to hold the string, a value at least as large as length(). // Also: capacity is always >= (MAX_SIZE-1) size_type capacity() const; // Sets the capacity of the string to a number at least as great as a specified number. // nCount = 0 is shrinking string to fit number of characters in it. // Shrink to fit post-cond: capacity() >= (MAX_SIZE-1) void reserve(size_type nCount = 0); _Self& append(const value_type* _Ptr); _Self& append(const value_type* _Ptr, size_type nCount); _Self& append(const _Self& _Str, size_type nOff, size_type nCount); _Self& append(const _Self& _Str); _Self& append(size_type nCount, value_type _Ch); _Self& append(const_iterator _First, const_iterator _Last); _Self& assign(const_str _Ptr); _Self& assign(const_str _Ptr, size_type nCount); _Self& assign(const _Self& _Str, size_type off, size_type nCount); _Self& assign(const _Self& _Str); _Self& assign(size_type nCount, value_type _Ch); _Self& assign(const_iterator _First, const_iterator _Last); value_type at(size_type index) const; //value_type& at( size_type index ); const_iterator begin() const { return m_str; }; const_iterator end() const { return m_str + length(); }; iterator begin() { return m_str; }; iterator end() { return m_str + length(); }; //! cast to C string operator. operator const_str() const { return m_str; } //! cast to C string. const value_type* c_str() const { return m_str; } const value_type* data() const { return m_str; }; ////////////////////////////////////////////////////////////////////////// // string comparison. ////////////////////////////////////////////////////////////////////////// int compare(const _Self& _Str) const; int compare(size_type _Pos1, size_type _Num1, const _Self& _Str) const; int compare(size_type _Pos1, size_type _Num1, const _Self& _Str, size_type nOff, size_type nCount) const; int compare(const value_type* _Ptr) const; int compare(size_type _Pos1, size_type _Num1, const value_type* _Ptr, size_type _Num2 = npos) const; // Case insensitive comparison int compareNoCase(const _Self& _Str) const; int compareNoCase(size_type _Pos1, size_type _Num1, const _Self& _Str) const; int compareNoCase(size_type _Pos1, size_type _Num1, const _Self& _Str, size_type nOff, size_type nCount) const; int compareNoCase(const value_type* _Ptr) const; int compareNoCase(size_type _Pos1, size_type _Num1, const value_type* _Ptr, size_type _Num2 = npos) const; // Copies at most a specified number of characters from an indexed position in a source string to a target character array. size_type copy(value_type* _Ptr, size_type nCount, size_type nOff = 0) const; void push_back(value_type _Ch) { _ConcatenateInPlace(&_Ch, 1); } void resize(size_type nCount, value_type _Ch = ' '); //! simple sub-string extraction _Self substr(size_type pos, size_type count = npos) const; // replace part of string. _Self& replace(value_type chOld, value_type chNew); _Self& replace(const_str strOld, const_str strNew); _Self& replace(size_type pos, size_type count, const_str strNew); _Self& replace(size_type pos, size_type count, const_str strNew, size_type count2); _Self& replace(size_type pos, size_type count, size_type nNumChars, value_type chNew); // insert new elements to string. _Self& insert(size_type nIndex, value_type ch); _Self& insert(size_type nIndex, size_type nCount, value_type ch); _Self& insert(size_type nIndex, const_str pstr); _Self& insert(size_type nIndex, const_str pstr, size_type nCount); //! delete count characters starting at zero-based index _Self& erase(size_type nIndex, size_type count = npos); //! searching (return starting index, or -1 if not found) //! look for a single character match //! like "C" strchr size_type find(value_type ch, size_type pos = 0) const; //! look for a specific sub-string //! like "C" strstr size_type find(const_str subs, size_type pos = 0) const; size_type rfind(value_type ch, size_type pos = npos) const; size_type find_first_of(value_type _Ch, size_type nOff = 0) const; size_type find_first_of(const_str charSet, size_type nOff = 0) const; //size_type find_first_of( const value_type* _Ptr,size_type _Off,size_type _Count ) const; size_type find_first_of(const _Self& _Str, size_type _Off = 0) const; size_type find_first_not_of(value_type _Ch, size_type _Off = 0) const; size_type find_first_not_of(const value_type* _Ptr, size_type _Off = 0) const; size_type find_first_not_of(const value_type* _Ptr, size_type _Off, size_type _Count) const; size_type find_first_not_of(const _Self& _Str, size_type _Off = 0) const; void swap(_Self& _Str); ////////////////////////////////////////////////////////////////////////// // overloaded operators. ////////////////////////////////////////////////////////////////////////// // overloaded indexing. value_type operator[](size_type index) const; // value_type& operator[]( size_type index ); // same as at() // overloaded assignment _Self& operator=(const _Self& str); _Self& operator=(value_type ch); _Self& operator=(const_str str); _Self& operator=(const CryStringT& str); void move(_Self& src); #if defined(LINUX) || defined(APPLE) template _Self& operator=(const CryStackStringT& str) { _Assign(str.c_str(), str.size()); return *this; } #endif // string concatenation _Self& operator+=(const _Self& str); _Self& operator+=(value_type ch); _Self& operator+=(const_str str); _Self& operator+=(const CryStringT& str); size_t GetAllocatedMemory() const { size_t size = sizeof(*this); if (m_str != m_strBuf) { size += (m_nAllocSize + 1) * sizeof(value_type); } return size; } ////////////////////////////////////////////////////////////////////////// // Extended functions. // This functions are not in the STL string. // They have an ATL CString interface. ////////////////////////////////////////////////////////////////////////// //! Format string, use (sprintf) _Self& Format(const value_type* format, ...); //! Format string fast, directly formats into string's buffer. // Make sure there is enough space to hold the string _Self& FormatFast (const value_type* format, ...); //! Converts the string to lower-case. // This function uses the "C" locale for case-conversion (ie, A-Z only). _Self& MakeLower(); //! Converts the string to upper-case. // This function uses the "C" locale for case-conversion (ie, A-Z only). _Self& MakeUpper(); _Self& Trim(); _Self& Trim(value_type ch); _Self& Trim(const value_type* sCharSet); _Self& TrimLeft(); _Self& TrimLeft(value_type ch); _Self& TrimLeft(const value_type* sCharSet); _Self& TrimRight(); _Self& TrimRight(value_type ch); _Self& TrimRight(const value_type* sCharSet); _Self SpanIncluding(const_str charSet) const; _Self SpanExcluding(const_str charSet) const; _Self Tokenize(const_str charSet, int& nStart) const; _Self Mid(size_type nFirst, size_type nCount = npos) const { return substr(nFirst, nCount); }; _Self Left(size_type count) const; _Self Right(size_type count) const; ////////////////////////////////////////////////////////////////////////// // public utilities. static bool _IsValidString(const_str str); public: ////////////////////////////////////////////////////////////////////////// // Only used for debugging statistics. ////////////////////////////////////////////////////////////////////////// static size_t _usedMemory(size_t size) { static size_t s_used_memory = 0; s_used_memory += size; return s_used_memory; } //private: public: size_type m_nLength; size_type m_nAllocSize; value_type* m_str; // pointer to ref counted string data value_type m_strBuf[MAX_SIZE]; // implementation helpers void _AllocData(size_type nLen); void _FreeData(value_type* pData); void _Free(); void _Initialize(); void _Concatenate(const_str sStr1, size_type nLen1, const_str sStr2, size_type nLen2); void _ConcatenateInPlace(const_str sStr, size_type nLen); void _Assign(const_str sStr, size_type nLen); void _MakeUnique(); }; ///////////////////////////////////////////////////////////////////////////// // CryStackStringT Implementation ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// template inline bool CryStackStringT::_IsValidString(const_str) { return true; } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::_Assign(const_str sStr, size_type nLen) { // Check if this string is shared (reference count greater then 1) or not enough capacity to store new string. // Then allocate new string buffer. if (nLen > capacity()) { _Free(); _AllocData(nLen); } // Copy characters from new string to this buffer. CharTraits::_copy(m_str, sStr, nLen); // Set new length. m_nLength = nLen; // Make null terminated string. m_str[nLen] = 0; CRY_STRING_DEBUG(m_str) } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::_Concatenate(const_str sStr1, size_type nLen1, const_str sStr2, size_type nLen2) { size_type nLen = nLen1 + nLen2; if (nLen1 * 2 > nLen) { nLen = nLen1 * 2; } if (nLen != 0) { if (nLen < 8) { nLen = 8; } _AllocData(nLen); CharTraits::_copy(m_str, sStr1, nLen1); CharTraits::_copy(m_str + nLen1, sStr2, nLen2); m_nLength = nLen1 + nLen2; m_str[nLen1 + nLen2] = 0; } CRY_STRING_DEBUG(m_str) } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::_ConcatenateInPlace(const_str sStr, size_type nLen) { if (nLen != 0) { // Check if this string is shared (reference count greater then 1) or not enough capacity to store new string. // Then allocate new string buffer. if (length() + nLen > capacity()) { value_type* pOldData = m_str; _Concatenate(m_str, length(), sStr, nLen); _FreeData(pOldData); } else { CharTraits::_copy(m_str + length(), sStr, nLen); m_nLength += nLen; m_str[m_nLength] = 0; // Make null terminated string. } } } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::_MakeUnique() { } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::_Initialize() { m_strBuf[0] = 0; m_str = m_strBuf; m_nLength = 0; m_nAllocSize = MAX_SIZE - 1; // 0 termination not counted! } // always allocate one extra character for '\0' termination // assumes [optimistically] that data length will equal allocation length template inline void CryStackStringT::_AllocData(size_type nLen) { assert(nLen >= 0); assert(nLen <= INT_MAX - 1); // max size (enough room for 1 extra) if (nLen == 0) { _Initialize(); } else { size_type allocLen = (nLen + 1) * sizeof(value_type); value_type* pData = m_strBuf; if (allocLen > MAX_SIZE) { pData = (value_type*)CryModuleMalloc(allocLen); _usedMemory(allocLen); // For statistics. m_nAllocSize = nLen; } else { m_nAllocSize = MAX_SIZE - 1; } m_nLength = nLen; m_str = pData; m_str[nLen] = 0; // null terminated string. } } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::_Free() { _FreeData(m_str); _Initialize(); } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::_FreeData(value_type* pData) { if (pData != m_strBuf) { size_t allocLen = (m_nAllocSize + 1) * sizeof(value_type); _usedMemory(-check_cast(allocLen)); // For statistics. CryModuleFree(pData); } } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT::CryStackStringT() { _Initialize(); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT::CryStackStringT(const CryStackStringT& str) { _Initialize(); _Assign(str.c_str(), str.length()); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT::CryStackStringT(const CryStackStringT& str, size_type nOff, size_type nCount) { _Initialize(); assign(str, nOff, nCount); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT::CryStackStringT(const_str str) { _Initialize(); // Make a copy of C string. size_type nLen = this->_strlen(str); if (nLen != 0) { _AllocData(nLen); CharTraits::_copy(m_str, str, nLen); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT::CryStackStringT(const CryStringT& str) { _Initialize(); size_t nLength = str.size(); if (nLength > 0) { _AllocData(nLength); CharTraits::_copy(m_str, str.c_str(), nLength); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT::CryStackStringT(const_str str, size_type nLength) { _Initialize(); if (nLength > 0) { _AllocData(nLength); CharTraits::_copy(m_str, str, nLength); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// // The reason of making this constructor unavailable (for a while) is // explained in comments in front of the declaration of // CryStringT::CryStringT(size_type nRepeat, value_type ch) // (see CryString.h). template inline CryStackStringT::CryStackStringT(size_type nRepeat, value_type ch) { _Initialize(); if (nRepeat > 0) { _AllocData(nRepeat); CharTraits::_set(m_str, ch, nRepeat); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT::CryStackStringT(const_iterator _First, const_iterator _Last) { _Initialize(); size_type nLength = (size_type)(_Last - _First); if (nLength > 0) { _AllocData(nLength); CharTraits::_copy(m_str, _First, nLength); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT::~CryStackStringT() { _FreeData(m_str); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::size_type CryStackStringT::length() const { return m_nLength; } template inline typename CryStackStringT::size_type CryStackStringT::size() const { return m_nLength; } template inline typename CryStackStringT::size_type CryStackStringT::capacity() const { return m_nAllocSize; } template inline bool CryStackStringT::empty() const { return length() == 0; } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::clear() { if (length() == 0) { return; } _Free(); assert(length() == 0); } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::reserve(size_type nCount) { // Reserve of 0 is shrinking container to fit number of characters in it.. if (nCount > capacity()) { value_type* pOldData = m_str; size_type nOldLength = m_nLength; _AllocData(nCount); CharTraits::_copy(m_str, pOldData, nOldLength); m_nLength = nOldLength; m_str[m_nLength] = 0; _FreeData(pOldData); } else if (nCount == 0) { if (length() != capacity()) { value_type* pOldData = m_str; if (pOldData != m_strBuf) // in case we fit into our static buffer, we cannot shrink anyway { size_type nOldLength = m_nLength; _AllocData(m_nLength); // if (pOldData != m_strBuf || m_str != m_strBuf) // actually always true // { CharTraits::_copy(m_str, pOldData, nOldLength); // we can safely use CharTraits::_copy, as we never overlap here (in case of static buffer, we don't shrink anyway) _FreeData(pOldData); // } } } } CRY_STRING_DEBUG(m_str) } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::append(const_str _Ptr) { *this += _Ptr; return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::append(const_str _Ptr, size_type nCount) { _ConcatenateInPlace(_Ptr, nCount); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::append(const CryStackStringT& _Str, size_type off, size_type nCount) { size_type len = _Str.length(); if (off > len) { return *this; } if (off + nCount > len) { nCount = len - off; } _ConcatenateInPlace(_Str.m_str + off, nCount); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::append(const CryStackStringT& _Str) { *this += _Str; return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::append(size_type nCount, value_type _Ch) { if (nCount > 0) { if (length() + nCount >= capacity()) { value_type* pOldData = m_str; size_type nOldLength = m_nLength; _AllocData(length() + nCount); CharTraits::_copy(m_str, pOldData, nOldLength); CharTraits::_set(m_str + nOldLength, _Ch, nCount); _FreeData(pOldData); } else { size_type nOldLength = length(); CharTraits::_set(m_str + nOldLength, _Ch, nCount); m_nLength = nOldLength + nCount; m_str[length()] = 0; // Make null terminated string. } } CRY_STRING_DEBUG(m_str) return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::append(const_iterator _First, const_iterator _Last) { append(_First, (size_type)(_Last - _First)); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::assign(const_str _Ptr) { *this = _Ptr; return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::assign(const_str _Ptr, size_type nCount) { size_type len = this->_strlen(_Ptr); _Assign(_Ptr, (nCount < len) ? nCount : len); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::assign(const CryStackStringT& _Str, size_type off, size_type nCount) { size_type len = _Str.length(); if (off > len) { return *this; } if (off + nCount > len) { nCount = len - off; } _Assign(_Str.m_str + off, nCount); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::assign(const CryStackStringT& _Str) { *this = _Str; return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::assign(size_type nCount, value_type _Ch) { if (nCount >= 1) { _AllocData(nCount); CharTraits::_set(m_str, _Ch, nCount); CRY_STRING_DEBUG(m_str) } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::assign(const_iterator _First, const_iterator _Last) { assign(_First, (size_type)(_Last - _First)); return *this; } ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::value_type CryStackStringT::at(size_type index) const { assert(index >= 0 && index < length()); return m_str[index]; } /* inline value_type& CryStackStringT::at( size_type index ) { // same as GetAt assert( index >= 0 && index < length() ); return m_str[index]; } */ template inline typename CryStackStringT::value_type CryStackStringT::operator[](size_type index) const { assert(index < length()); return m_str[index]; } /* inline value_type& CryStackStringT::operator[]( size_type index ) { // same as GetAt assert( index >= 0 && index < length() ); return m_str[index]; } */ ////////////////////////////////////////////////////////////////////////// template inline int CryStackStringT::compare(const CryStackStringT& _Str) const { return CharTraits::_strcmp(m_str, _Str.m_str); } template inline int CryStackStringT::compare(size_type _Pos1, size_type _Num1, const CryStackStringT& _Str) const { return compare(_Pos1, _Num1, _Str.m_str, npos); } template inline int CryStackStringT::compare(size_type _Pos1, size_type _Num1, const CryStackStringT& _Str, size_type nOff, size_type nCount) const { assert(nOff < _Str.length()); return compare(_Pos1, _Num1, _Str.m_str + nOff, nCount); } template inline int CryStackStringT::compare(const value_type* _Ptr) const { return CharTraits::_strcmp(m_str, _Ptr); } template inline int CryStackStringT::compare(size_type _Pos1, size_type _Num1, const value_type* _Ptr, size_type _Num2) const { assert(_Pos1 < length()); if (length() - _Pos1 < _Num1) { _Num1 = length() - _Pos1; // trim to size } int res = _Num1 == 0 ? 0 : CharTraits::_strncmp(m_str + _Pos1, _Ptr, (_Num1 < _Num2) ? _Num1 : _Num2); return (res != 0 ? res : _Num2 == npos && _Ptr[_Num1] == 0 ? 0 : _Num1 < _Num2 ? -1 : _Num1 == _Num2 ? 0 : +1); } ////////////////////////////////////////////////////////////////////////// template inline int CryStackStringT::compareNoCase(const CryStackStringT& _Str) const { return CharTraits::_stricmp(m_str, _Str.m_str); } template inline int CryStackStringT::compareNoCase(size_type _Pos1, size_type _Num1, const CryStackStringT& _Str) const { return compareNoCase(_Pos1, _Num1, _Str.m_str, npos); } template inline int CryStackStringT::compareNoCase(size_type _Pos1, size_type _Num1, const CryStackStringT& _Str, size_type nOff, size_type nCount) const { assert(nOff < _Str.length()); return compareNoCase(_Pos1, _Num1, _Str.m_str + nOff, nCount); } template inline int CryStackStringT::compareNoCase(const value_type* _Ptr) const { return CharTraits::_stricmp(m_str, _Ptr); } template inline int CryStackStringT::compareNoCase(size_type _Pos1, size_type _Num1, const value_type* _Ptr, size_type _Num2) const { assert(_Pos1 < length()); if (length() - _Pos1 < _Num1) { _Num1 = length() - _Pos1; // trim to size } int res = _Num1 == 0 ? 0 : CharTraits::_strnicmp(m_str + _Pos1, _Ptr, (_Num1 < _Num2) ? _Num1 : _Num2); return (res != 0 ? res : _Num2 == npos && _Ptr[_Num1] == 0 ? 0 : _Num1 < _Num2 ? -1 : _Num1 == _Num2 ? 0 : +1); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::size_type CryStackStringT::copy(value_type* _Ptr, size_type nCount, size_type nOff) const { assert(nOff < length()); if (nCount < 0) { nCount = 0; } if (nOff + nCount > length()) // trim to offset. { nCount = length() - nOff; } CharTraits::_copy(_Ptr, m_str + nOff, nCount); return nCount; } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::resize(size_type nCount, value_type _Ch) { _MakeUnique(); if (nCount > length()) { size_type numToAdd = nCount - length(); append(numToAdd, _Ch); } else if (nCount < length()) { m_nLength = nCount; m_str[length()] = 0; // Make null terminated string. } } ////////////////////////////////////////////////////////////////////////// //! compare helpers template inline bool operator==(const CryStackStringT& s1, const CryStackStringT& s2) { return s1.compare(s2) == 0; } template inline bool operator==(const CryStackStringT& s1, const typename CryStackStringT::value_type* s2) { return s1.compare(s2) == 0; } template inline bool operator==(const typename CryStackStringT::value_type* s1, const CryStackStringT& s2) { return s2.compare(s1) == 0; } template inline bool operator!=(const CryStackStringT& s1, const CryStackStringT& s2) { return s1.compare(s2) != 0; } template inline bool operator!=(const CryStackStringT& s1, const typename CryStackStringT::value_type* s2) { return s1.compare(s2) != 0; } template inline bool operator!=(const typename CryStackStringT::value_type* s1, const CryStackStringT& s2) { return s2.compare(s1) != 0; } template inline bool operator<(const CryStackStringT& s1, const CryStackStringT& s2) { return s1.compare(s2) < 0; } template inline bool operator<(const CryStackStringT& s1, const typename CryStackStringT::value_type* s2) { return s1.compare(s2) < 0; } template inline bool operator<(const typename CryStackStringT::value_type* s1, const CryStackStringT& s2) { return s2.compare(s1) > 0; } template inline bool operator>(const CryStackStringT& s1, const CryStackStringT& s2) { return s1.compare(s2) > 0; } template inline bool operator>(const CryStackStringT& s1, const typename CryStackStringT::value_type* s2) { return s1.compare(s2) > 0; } template inline bool operator>(const typename CryStackStringT::value_type* s1, const CryStackStringT& s2) { return s2.compare(s1) < 0; } template inline bool operator<=(const CryStackStringT& s1, const CryStackStringT& s2) { return s1.compare(s2) <= 0; } template inline bool operator<=(const CryStackStringT& s1, const typename CryStackStringT::value_type* s2) { return s1.compare(s2) <= 0; } template inline bool operator<=(const typename CryStackStringT::value_type* s1, const CryStackStringT& s2) { return s2.compare(s1) >= 0; } template inline bool operator>=(const CryStackStringT& s1, const CryStackStringT& s2) { return s1.compare(s2) >= 0; } template inline bool operator>=(const CryStackStringT& s1, const typename CryStackStringT::value_type* s2) { return s1.compare(s2) >= 0; } template inline bool operator>=(const typename CryStackStringT::value_type* s1, const CryStackStringT& s2) { return s2.compare(s1) <= 0; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::operator=(value_type ch) { _Assign(&ch, 1); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT operator+(const CryStackStringT& string1, typename CryStackStringT::value_type ch) { CryStackStringT s(string1); s.append(1, ch); return s; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT operator+(typename CryStackStringT::value_type ch, const CryStackStringT& str) { CryStackStringT s; s.reserve(str.size() + 1); s.append(1, ch); s.append(str); return s; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT operator+(const CryStackStringT& string1, const CryStackStringT& string2) { CryStackStringT s(string1); s.append(string2); return s; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT operator+(const CryStackStringT& str1, const typename CryStackStringT::value_type* str2) { CryStackStringT s(str1); s.append(str2); return s; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT operator+(const typename CryStackStringT::value_type* str1, const CryStackStringT& str2) { assert(str1 == NULL || (CryStackStringT::_IsValidString(str1))); CryStackStringT s; s.reserve(CharTraits::_strlen(str1) + str2.size()); s.append(str1); s.append(str2); return s; } template inline CryStackStringT& CryStackStringT::operator=(const CryStackStringT& str) { _Assign (str.c_str(), str.length()); return *this; } template inline CryStackStringT& CryStackStringT::operator=(const_str str) { assert(str == NULL || _IsValidString(str)); _Assign(str, this->_strlen(str)); return *this; } template inline CryStackStringT& CryStackStringT::operator=(const CryStringT& str) { _Assign(str.c_str(), str.size()); return *this; } template inline CryStackStringT& CryStackStringT::operator+=(const CryStringT& str) { _ConcatenateInPlace(str.c_str(), str.size()); return *this; } template inline CryStackStringT& CryStackStringT::operator+=(const_str str) { assert(str == NULL || _IsValidString(str)); _ConcatenateInPlace(str, this->_strlen(str)); return *this; } template inline CryStackStringT& CryStackStringT::operator+=(value_type ch) { _ConcatenateInPlace(&ch, 1); return *this; } template inline CryStackStringT& CryStackStringT::operator+=(const CryStackStringT& str) { _ConcatenateInPlace(str.m_str, str.length()); return *this; } //! find first single character template inline typename CryStackStringT::size_type CryStackStringT::find(value_type ch, size_type pos) const { if (!(/*pos >= 0 && */ pos <= length())) { return (typename CryStackStringT::size_type)npos; } const_str str = CharTraits::_strchr(m_str + pos, ch); // return npos if not found and index otherwise return (str == NULL) ? npos : (size_type)(str - m_str); } //! find a sub-string (like strstr) template inline typename CryStackStringT::size_type CryStackStringT::find(const_str subs, size_type pos) const { assert(_IsValidString(subs)); if (!(pos >= 0 && pos <= length())) { return npos; } // find first matching substring const_str str = CharTraits::_strstr(m_str + pos, subs); // return npos for not found, distance from beginning otherwise return (str == NULL) ? npos : (size_type)(str - m_str); } //! find last single character template inline typename CryStackStringT::size_type CryStackStringT::rfind(value_type ch, size_type pos) const { const_str str; if (pos == npos) { // find last single character str = strrchr(m_str, ch); // return -1 if not found, distance from beginning otherwise return (str == NULL) ? (size_type) - 1 : (size_type)(str - m_str); } else { if (pos == npos) { pos = length(); } if (!(pos >= 0 && pos <= length())) { return npos; } value_type tmp = m_str[pos + 1]; m_str[pos + 1] = 0; str = strrchr(m_str, ch); m_str[pos + 1] = tmp; } // return -1 if not found, distance from beginning otherwise return (str == NULL) ? (size_type) - 1 : (size_type)(str - m_str); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::size_type CryStackStringT::find_first_of(const CryStackStringT& _Str, size_type _Off) const { return find_first_of(_Str.m_str, _Off); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::size_type CryStackStringT::find_first_of(value_type _Ch, size_type nOff) const { if (!(nOff >= 0 && nOff <= length())) { return npos; } value_type charSet[2] = { _Ch, 0 }; const_str str = strpbrk(m_str + nOff, charSet); return (str == NULL) ? -1 : (size_type)(str - m_str); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::size_type CryStackStringT::find_first_of(const_str charSet, size_type nOff) const { assert(_IsValidString(charSet)); if (!(nOff >= 0 && nOff <= length())) { return npos; } const_str str = strpbrk(m_str + nOff, charSet); return (str == NULL) ? (size_type) - 1 : (size_type)(str - m_str); } //size_type find_first_not_of(const _Self& __s, size_type __pos = 0) const //{ return find_first_not_of(__s._M_start, __pos, __s.size()); } //size_type find_first_not_of(const _CharT* __s, size_type __pos = 0) const //{ _STLP_FIX_LITERAL_BUG(__s) return find_first_not_of(__s, __pos, _Traits::length(__s)); } //size_type find_first_not_of(const _CharT* __s, size_type __pos, size_type __n) const; //size_type find_first_not_of(_CharT __c, size_type __pos = 0) const; ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::size_type CryStackStringT::find_first_not_of(const value_type* _Ptr, size_type _Off) const { return find_first_not_of(_Ptr, _Off, this->_strlen(_Ptr)); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::size_type CryStackStringT::find_first_not_of(const CryStackStringT& _Str, size_type _Off) const { return find_first_not_of(_Str.m_str, _Off); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::size_type CryStackStringT::find_first_not_of(value_type _Ch, size_type _Off) const { if (_Off > length()) { return npos; } else { for (const value_type* str = begin() + _Off; str != end(); ++str) { if (*str != _Ch) { return size_type(str - begin()); // Character found! } } return npos; } } ////////////////////////////////////////////////////////////////////////// template inline typename CryStackStringT::size_type CryStackStringT::find_first_not_of(const value_type* _Ptr, size_type _Off, size_type _Count) const { if (_Off > length()) { return npos; } else { const value_type* charsFirst = _Ptr, * charsLast = _Ptr + _Count; for (const value_type* str = begin() + _Off; str != end(); ++str) { const value_type* c; for (c = charsFirst; c != charsLast; ++c) { if (*c == *str) { break; } } if (c == charsLast) { return size_type(str - begin());// Current character not in char set. } } return npos; } } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT CryStackStringT::substr(size_type pos, size_type count) const { if (pos >= length()) { return CryStackStringT(); } if (count == npos) { count = length() - pos; } if (pos + count > length()) { count = length() - pos; } return CryStackStringT(m_str + pos, count); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::erase(size_type nIndex, size_type nCount) { if (nIndex < 0) { nIndex = 0; } if (nCount < 0 || nCount > length() - nIndex) { nCount = length() - nIndex; } if (nCount > 0 && nIndex < length()) { _MakeUnique(); size_type nNumToCopy = length() - (nIndex + nCount) + 1; CharTraits::_move(m_str + nIndex, m_str + nIndex + nCount, nNumToCopy); m_nLength = length() - nCount; } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::insert(size_type nIndex, value_type ch) { return insert(nIndex, 1, ch); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::insert(size_type nIndex, size_type nCount, value_type ch) { _MakeUnique(); if (nIndex < 0) { nIndex = 0; } size_type nNewLength = length(); if (nIndex > nNewLength) { nIndex = nNewLength; } nNewLength += nCount; if (capacity() < nNewLength) { value_type* pOldData = m_str; size_type nOldLength = m_nLength; const_str pstr = m_str; _AllocData(nNewLength); CharTraits::_copy(m_str, pstr, nOldLength + 1); _FreeData(pOldData); } CharTraits::_move(m_str + nIndex + nCount, m_str + nIndex, (nNewLength - nIndex)); CharTraits::_set(m_str + nIndex, ch, nCount); m_nLength = nNewLength; CRY_STRING_DEBUG(m_str) return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::insert(size_type nIndex, const_str pstr, size_type nCount) { if (nIndex < 0) { nIndex = 0; } size_type nInsertLength = nCount; size_type nNewLength = length(); if (nInsertLength > 0) { _MakeUnique(); if (nIndex > nNewLength) { nIndex = nNewLength; } nNewLength += nInsertLength; if (capacity() < nNewLength) { value_type* pOldData = m_str; size_type nOldLength = m_nLength; const_str pOldStr = m_str; _AllocData(nNewLength); CharTraits::_copy(m_str, pOldStr, (nOldLength + 1)); _FreeData(pOldData); } CharTraits::_move(m_str + nIndex + nInsertLength, m_str + nIndex, (nNewLength - nIndex - nInsertLength + 1)); CharTraits::_copy(m_str + nIndex, pstr, nInsertLength); m_nLength = nNewLength; m_str[length()] = 0; } CRY_STRING_DEBUG(m_str) return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::insert(size_type nIndex, const_str pstr) { return insert(nIndex, pstr, this->_strlen(pstr)); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::replace(size_type pos, size_type count, const_str strNew) { return replace(pos, count, strNew, this->_strlen(strNew)); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::replace(size_type pos, size_type count, const_str strNew, size_type count2) { erase(pos, count); insert(pos, strNew, count2); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::replace(size_type pos, size_type count, size_type nNumChars, value_type chNew) { erase(pos, count); insert(pos, nNumChars, chNew); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::replace(value_type chOld, value_type chNew) { if (chOld != chNew) { _MakeUnique(); value_type* strend = m_str + length(); for (value_type* str = m_str; str != strend; ++str) { if (*str == chOld) { *str = chNew; } } } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::replace(const_str strOld, const_str strNew) { size_type nSourceLen = this->_strlen(strOld); if (nSourceLen == 0) { return *this; } size_type nReplacementLen = this->_strlen(strNew); size_type nCount = 0; value_type* strStart = m_str; value_type* strEnd = m_str + length(); value_type* strTarget; while (strStart < strEnd) { while ((strTarget = CharTraits::_strstr(strStart, strOld)) != NULL) { nCount++; strStart = strTarget + nSourceLen; } strStart += this->_strlen(strStart) + 1; } if (nCount > 0) { _MakeUnique(); size_type nOldLength = length(); size_type nNewLength = nOldLength + (nReplacementLen - nSourceLen) * nCount; if (capacity() < nNewLength) { value_type* pOldData = m_str; size_type nPrevLength = m_nLength; const_str pstr = m_str; _AllocData(nNewLength); CharTraits::_copy(m_str, pstr, nPrevLength); _FreeData(pOldData); } strStart = m_str; strEnd = m_str + length(); while (strStart < strEnd) { while ((strTarget = CharTraits::_strstr(strStart, strOld)) != NULL) { size_type nBalance = nOldLength - ((size_type)(strTarget - m_str) + nSourceLen); CharTraits::_move(strTarget + nReplacementLen, strTarget + nSourceLen, nBalance); CharTraits::_copy(strTarget, strNew, nReplacementLen); strStart = strTarget + nReplacementLen; strStart[nBalance] = 0; nOldLength += (nReplacementLen - nSourceLen); } strStart += this->_strlen(strStart) + 1; } m_nLength = nNewLength; } CRY_STRING_DEBUG(m_str) return *this; } ////////////////////////////////////////////////////////////////////////// template inline void CryStackStringT::move(CryStackStringT& str) { memcpy(this, &str, sizeof(*this)); if (str.m_str == str.m_strBuf) { m_str = m_strBuf; } } template inline void CryStackStringT::swap(CryStackStringT& _Str) { CryStackStringT temp; temp.move(*this); move(_Str); _Str.move(temp); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::Format(const_str format, ...) { assert(_IsValidString(format)); value_type temp[4096]; // Limited to 4096 characters! va_list argList; va_start(argList, format); this->_vsnprintf(temp, 4095, format, argList); temp[4095] = '\0'; va_end(argList); *this = temp; return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::FormatFast(const_str format, ...) { assert(_IsValidString(format)); va_list argList; va_start(argList, format); int newLength = this->_vsnprintf(m_str, capacity(), format, argList); if (newLength >= 0) { m_nLength = (size_type)newLength; } else { m_nLength = capacity(); m_str[capacity()] = '\0'; } va_end(argList); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::MakeLower() { _MakeUnique(); for (value_type* s = m_str; *s != 0; s++) { *s = this->_ascii_tolower(*s); } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::MakeUpper() { _MakeUnique(); for (value_type* s = m_str; *s != 0; s++) { *s = this->_ascii_toupper(*s); } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::Trim() { return TrimRight().TrimLeft(); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::Trim(value_type ch) { _MakeUnique(); const value_type chset[2] = { ch, 0 }; return TrimRight(chset).TrimLeft(chset); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::Trim(const value_type* sCharSet) { _MakeUnique(); return TrimRight(sCharSet).TrimLeft(sCharSet); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::TrimRight(value_type ch) { const value_type chset[2] = { ch, 0 }; return TrimRight(chset); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::TrimRight(const value_type* sCharSet) { if (!sCharSet || !(*sCharSet) || length() < 1) { return *this; } const value_type* last = m_str + length() - 1; const value_type* str = last; while ((str != m_str) && (CharTraits::_strchr(sCharSet, *str) != 0)) { str--; } if (str != last) { // Just shrink length of the string. size_type nNewLength = (size_type)(str - m_str) + 1; // m_str can change in _MakeUnique _MakeUnique(); m_nLength = nNewLength; m_str[nNewLength] = 0; } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::TrimRight() { if (length() < 1) { return *this; } const value_type* last = m_str + length() - 1; const value_type* str = last; while ((str != m_str) && (CharTraits::_isspace(*str) != 0)) { str--; } if (str != last) // something changed? { // Just shrink length of the string. size_type nNewLength = (size_type)(str - m_str) + 1; // m_str can change in _MakeUnique _MakeUnique(); m_nLength = nNewLength; m_str[nNewLength] = 0; } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::TrimLeft(value_type ch) { const value_type chset[2] = { ch, 0 }; return TrimLeft(chset); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::TrimLeft(const value_type* sCharSet) { if (!sCharSet || !(*sCharSet)) { return *this; } const value_type* str = m_str; while ((*str != 0) && (CharTraits::_strchr(sCharSet, *str) != 0)) { str++; } if (str != m_str) { size_type nOff = (size_type)(str - m_str); // m_str can change in _MakeUnique _MakeUnique(); size_type nNewLength = length() - nOff; CharTraits::_move(m_str, m_str + nOff, nNewLength + 1); m_nLength = nNewLength; m_str[nNewLength] = 0; } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT& CryStackStringT::TrimLeft() { const value_type* str = m_str; while ((*str != 0) && (CharTraits::_isspace(*str) != 0)) { str++; } if (str != m_str) { size_type nOff = (size_type)(str - m_str); // m_str can change in _MakeUnique _MakeUnique(); size_type nNewLength = length() - nOff; CharTraits::_move(m_str, m_str + nOff, nNewLength + 1); m_nLength = nNewLength; m_str[nNewLength] = 0; } return *this; } template inline CryStackStringT CryStackStringT::Right(size_type count) const { if (count == npos) { return CryStackStringT(); } else if (count > length()) { return *this; } return CryStackStringT(m_str + length() - count, count); } template inline CryStackStringT CryStackStringT::Left(size_type count) const { if (count == npos) { return CryStackStringT(); } else if (count > length()) { count = length(); } return CryStackStringT(m_str, count); } // strspn equivalent template inline CryStackStringT CryStackStringT::SpanIncluding(const_str charSet) const { assert(_IsValidString(charSet)); return Left((size_type)this->_strspn(m_str, charSet)); } // strcspn equivalent template inline CryStackStringT CryStackStringT::SpanExcluding(const_str charSet) const { assert(_IsValidString(charSet)); return Left((size_type)this->_strcspn(m_str, charSet)); } ////////////////////////////////////////////////////////////////////////// template inline CryStackStringT CryStackStringT::Tokenize(const_str charSet, int& nStart) const { if (nStart < 0) { return CryStackStringT(); } if (!charSet) { return *this; } const_str sPlace = m_str + nStart; const_str sEnd = m_str + length(); if (sPlace < sEnd) { int nIncluding = (int)this->_strspn(sPlace, charSet); if ((sPlace + nIncluding) < sEnd) { sPlace += nIncluding; int nExcluding = (int)this->_strcspn(sPlace, charSet); int nFrom = nStart + nIncluding; nStart = nFrom + nExcluding + 1; return substr(nFrom, nExcluding); } } // Return empty string. nStart = -1; return CryStackStringT(); } ////////////////////////////////////////////////////////////////////////// // Specialization providing efficient move semantics for array classes. template bool raw_movable(const CryStackStringT& str) { return false; } template void move_init(CryStackStringT& dest, CryStackStringT& source) { dest.move(source); } #if defined(_RELEASE) #define ASSERT_LEN (void)(0) #define ASSERT_WLEN (void)(0) #else #define ASSERT_LEN CRY_ASSERT_TRACE(this->length() <= S, ("String '%s' is %u character(s) longer than MAX_SIZE=%u", this->c_str(), this->length() - S, S)) #define ASSERT_WLEN CRY_ASSERT_TRACE(this->length() <= S, ("Wide-char string '%ls' is %u character(s) longer than MAX_SIZE=%u", this->c_str(), this->length() - S, S)) #endif // a template specialization for char template class CryFixedStringT : public CryStackStringT { public: typedef CryStackStringT _parentType; typedef CryFixedStringT _Self; typedef size_t size_type; typedef char value_type; typedef const value_type* const_str; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef pointer iterator; typedef const_pointer const_iterator; static const size_type MAX_SIZE = S; CryFixedStringT() : _parentType() {} CryFixedStringT(const _parentType& str) : _parentType(str) {ASSERT_LEN; } CryFixedStringT(const _parentType& str, size_type nOff, size_type nCount) : _parentType(str, nOff, nCount) {ASSERT_LEN; } CryFixedStringT(const _Self& str) : _parentType(str) {ASSERT_LEN; } CryFixedStringT(const _Self& str, size_type nOff, size_type nCount) : _parentType(str, nOff, nCount) {ASSERT_LEN; } CryFixedStringT(size_type nRepeat, value_type ch) : _parentType(nRepeat, ch) {ASSERT_LEN; } CryFixedStringT(const_str str) : _parentType (str) {ASSERT_LEN; } CryFixedStringT(const_str str, size_type nLength) : _parentType(str, nLength) {ASSERT_LEN; } CryFixedStringT(const_iterator _First, const_iterator _Last) : _parentType(_First, _Last) {ASSERT_LEN; } template _Self& operator=(const CryFixedStringT& str) { _parentType::operator = (str); ASSERT_LEN; return *this; } template _Self& operator=(const CryStackStringT& str) { _parentType::operator = (str); ASSERT_LEN; return *this; } _Self& operator=(value_type ch) { _parentType::operator = (ch); ASSERT_LEN; return *this; } void GetMemoryUsage(class ICrySizer* pSizer) const{} }; // a template specialization for a fixed list of CryFixedString [Jan M.] template class CCryFixedStringListT { public: CCryFixedStringListT() { Clear(); } void Clear() { m_currentAmount = -1; for (int a = 0; a < NUM_MAX_ELEMENTS; ++a) { m_data[a] = ""; } } void Add(const char* name) { m_data[++m_currentAmount] = name; if (m_currentAmount == NUM_MAX_ELEMENTS) { m_currentAmount = -1; } } const char* operator[](int index) { if (index <= m_currentAmount) { return m_data[index].c_str(); } return NULL; } ILINE int Size() { return m_currentAmount + 1; } CryFixedStringT<32>* GetData(int& amount) { amount = m_currentAmount + 1; return m_data; } private: const static int NUM_MAX_ELEMENTS = maxElements; CryFixedStringT m_data[NUM_MAX_ELEMENTS]; int32 m_currentAmount; }; // a template specialization for wchar_t template class CryFixedWStringT : public CryStackStringT { public: typedef CryStackStringT _parentType; typedef CryFixedWStringT _Self; typedef size_t size_type; typedef wchar_t value_type; typedef const value_type* const_str; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef pointer iterator; typedef const_pointer const_iterator; static const size_type MAX_SIZE = S; CryFixedWStringT() : _parentType() {} CryFixedWStringT(const _parentType& str) : _parentType(str) {ASSERT_WLEN; } CryFixedWStringT(const _parentType& str, size_type nOff, size_type nCount) : _parentType(str, nOff, nCount) {ASSERT_WLEN; } CryFixedWStringT(const _Self& str) : _parentType(str) {ASSERT_WLEN; } CryFixedWStringT(const _Self& str, size_type nOff, size_type nCount) : _parentType(str, nOff, nCount) {ASSERT_WLEN; } CryFixedWStringT(size_type nRepeat, value_type ch) : _parentType(nRepeat, ch) {ASSERT_WLEN; } CryFixedWStringT(const_str str) : _parentType (str) {ASSERT_WLEN; } CryFixedWStringT(const_str str, size_type nLength) : _parentType(str, nLength) {ASSERT_WLEN; } CryFixedWStringT(const_iterator _First, const_iterator _Last) : _parentType(_First, _Last) {ASSERT_WLEN; } template _Self& operator=(const CryFixedWStringT& str) { _parentType::operator = (str); ASSERT_WLEN; return *this; } template _Self& operator=(const CryStackStringT& str) { _parentType::operator = (str); ASSERT_WLEN; return *this; } }; #undef ASSERT_LEN #undef ASSERT_WLEN typedef CryStackStringT stack_string; // Special string type used for specifying file paths. typedef CryStackStringT CryPathString; #if UNITTEST_CRYFIXEDSTRING struct SUnitTest_FixedString { bool UnitAssert(const char* message, const char* value, const char* refValue) { int res = strcmp(value, refValue); CRY_ASSERT_MESSAGE(res == 0, message); return res == 0; } bool UnitAssert(const char* message, const wchar_t* value, const wchar_t* refValue) { int res = wcscmp(value, refValue); CRY_ASSERT_MESSAGE(res == 0, message); return res == 0; } bool UnitAssert(const char* message, bool cond) { CRY_ASSERT_MESSAGE(cond, message); return cond; } bool UnitAssert(const char* message, size_t a, size_t b) { CRY_ASSERT_MESSAGE(a == b, message); return a == b; } int UnitTest() { CryStackStringT str1; CryStackStringT str2; CryStackStringT str3; CryStackStringT str4; CryStackStringT str5; CryStackStringT wstr1; CryStackStringT wstr2; CryFixedStringT<100> fixedString100; CryFixedStringT<200> fixedString200; typedef CryStackStringT T; T* pStr = new T; * pStr = "adads"; delete pStr; str1 = "abcd"; UnitAssert ("Assignment1-EnoughSpace", str1, "abcd"); str2 = "efg"; UnitAssert ("Assignment2-EnoughSpace", str2, "efg"); str2 = str1; UnitAssert ("Assignment3-EnoughSpace", str2, "abcd"); str3 = str1; UnitAssert ("Assignment4-NotEnoughSpace", str3, "abcd"); str1 += "XY"; UnitAssert ("Concatenate-EnoughSpace", str1, "abcdXY"); str2 += "efghijk"; UnitAssert ("Concatenate-NotEnoughSpace", str2, "abcdefghijk"); str1.replace("bc", ""); UnitAssert ("Replace-Shrink-EnoughSpace", str1, "adXY"); str1.replace("XY", "1234"); UnitAssert ("Replace-Grow-EnoughSpace", str1, "ad1234"); str1.replace("1234", "1234567890"); UnitAssert ("Replace-Grow-NotEnoughSpace", str1, "ad1234567890"); str1.reserve(200); UnitAssert ("Reserve200-SameString", str1, "ad1234567890"); UnitAssert ("Reserve200-Capacity", str1.capacity() == 200); str1.reserve(0); UnitAssert ("Reserve0-SameString", str1, "ad1234567890"); UnitAssert ("Reserve0-Capacity==Length", str1.capacity() == str1.length()); str1.erase(7); // doesn't change capacity UnitAssert ("Erase-SameString", str1, "ad12345"); str4.assign("abc"); UnitAssert ("Str4 Assignment", str4, "abc"); str4.reserve(9); UnitAssert ("Str4", str4.capacity() >= 9); // capacity is always >= MAX_SIZE-1 str4.reserve(0); UnitAssert ("Str4-Shrink", str4.capacity() >= 9); // capacity is always >= MAX_SIZE-1 size_t idx = str1.find("123"); UnitAssert ("Str1-Find", idx == 2); idx = str1.find("123", 3); UnitAssert ("Str1-Find", idx == str1.npos); wstr1 = L"abc"; UnitAssert ("WStr1-Assign", wstr1, L"abc"); UnitAssert ("WStr1-CompareCaseGT", wstr1.compare(L"aBc") > 0); UnitAssert ("WStr1-CompareCaseLT", wstr1.compare(L"babc") < 0); UnitAssert ("WStr1-CompareNoCase", wstr1.compareNoCase(L"aBc") == 0); str1.Format("This is a %s %S with %d params", "mixed", L"string", 3); str2.Format("This is a %S %s with %d params", L"mixed", "string", 3); UnitAssert ("Str1-Format1", str1, "This is a mixed string with 3 params"); UnitAssert ("Str1-Format2", str1, str2); wstr1.Format(L"This is a %s %S with %d params", L"mixed", "string", 3); wstr2.Format(L"This is a %S %s with %d params", "mixed", L"string", 3); UnitAssert ("WStr1-Format1", wstr1, L"This is a mixed string with 3 params"); UnitAssert ("WStr1-Format2", wstr1, wstr2); str5.FormatFast("%s", "12345"); UnitAssert ("Str5-FormatFast", str5, "12345"); str5.FormatFast("%s", "012345"); UnitAssert ("Str5-FormatFast-Truncate", str5, "01234"); fixedString100 = str5; str2 = fixedString200; fixedString200 = fixedString100; UnitAssert ("FixedString-Test2", fixedString100, "01234"); UnitAssert ("FixedString-Test1", fixedString100, fixedString200); CryStackStringT testStr; CryFixedStringT<100> testStr2; CryFixedWStringT<100> testWStr1; string normalString; wstring normalWString; normalString = string(testStr); normalString = string(testStr2); normalString.assign(testStr2.c_str()); // normalString = testStr; // <- must NOT compile, as we don't allow it! // normalWString = testWStr1; // <- must NOT compile, as we don't allow it! normalWString = wstring(testWStr1); return 0; } }; #endif // #if UNITTEST_CRYFIXEDSTRING #endif // CRYINCLUDE_CRYCOMMON_CRYFIXEDSTRING_H