/* * 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 : Custom reference counted string class. // Can easily be substituted instead of string #ifndef CRYINCLUDE_CRYCOMMON_CRYSTRING_H #define CRYINCLUDE_CRYCOMMON_CRYSTRING_H #pragma once #include #if !defined(NOT_USE_CRY_STRING) #include #include #include #include #include #include "CompileTimeAssert.h" #include "platform.h" #include "LegacyAllocator.h" #define CRY_STRING // forward declaration of CryStackString template class CryStackStringT; class CConstCharWrapper; //forward declaration for special const char * without memory allocations //extern void CryDebugStr( const char *format,... ); //#define CRY_STRING_DEBUG(s) { if (*s) CryDebugStr( "[%6d] %s",_usedMemory(0),(s) );} #define CRY_STRING_DEBUG(s) class CryStringAllocator : public AZ::SimpleSchemaAllocator { public: AZ_TYPE_INFO(CryStringAllocator, "{763DFC83-8A6E-4FD9-B6BC-BBF56E93E4EE}"); using Base = AZ::SimpleSchemaAllocator; using Descriptor = Base::Descriptor; CryStringAllocator() : Base("CryStringAllocator", "Allocator for CryString") { Descriptor desc; desc.m_systemChunkSize = 4 * 1024 * 1024; // grow by 4 MB at a time desc.m_subAllocator = &AZ::AllocatorInstance::Get(); Create(desc); } }; ////////////////////////////////////////////////////////////////////////// // CryStringT class. ////////////////////////////////////////////////////////////////////////// template class CryStringT { public: ////////////////////////////////////////////////////////////////////////// // Types compatible with STL string. ////////////////////////////////////////////////////////////////////////// typedef CryStringT _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; enum _npos_type { npos = (size_type) ~0 }; ////////////////////////////////////////////////////////////////////////// // Constructors ////////////////////////////////////////////////////////////////////////// CryStringT(); protected: CryStringT(const CConstCharWrapper& str); //ctor for strings without memory allocations friend class CConstCharWrapper; public: CryStringT(const _Self& str); CryStringT(const _Self& str, size_type nOff, size_type nCount); // Before September 2012 this constructor looked like this: // explicit CryStringT( value_type ch, size_type nRepeat = 1 ); // It was very error-prone, because the matching constructor // std::string constructor is different: // std::string( size_type nRepeat, value_type ch ); // // To prevent hard-to-catch bugs, we removed all calls of this // constructor in the existing CryEngine code (in September 2012) // and started using proper order of parameters (matching std::). // // To catch calls using the reversed arguments in other projects, // we retain the previous function with reversed arguments, // and declare it private. CryStringT(size_type nRepeat, value_type ch); private: CryStringT(value_type ch, size_type nRepeat); public: CryStringT(const_str str); CryStringT(const_str str, size_type nLength); CryStringT(const_iterator _First, const_iterator _Last); ~CryStringT(); ////////////////////////////////////////////////////////////////////////// // 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(). 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. 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; const_iterator begin() const { return m_str; }; const_iterator end() const { return m_str + length(); }; // Following functions are commented out because they provide direct write access to // the string and such access doesn't work properly with our current reference-count // implementation. // If you really need write access to your string's elements, please consider // using CryStackStringT<> instead of CryString<>. Alternatively, you can modify // your string by multiple calls of erase() and append(). // Note: If you need *linear memory read* access to your string's elements, use data() // or c_str(). If you need *linear memory write* access to your string's elements, // use a non-string class (std::vector<>, DynArray<>, etc.) instead of CryString<>. //value_type& at( size_type index ); //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 char* _Ptr) const; int compare(const wchar_t* _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 rfind(const _Self& subs, size_type pos = 0) 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; size_type find_last_of(value_type _Ch, size_type _Off = npos) const; size_type find_last_of(const value_type* _Ptr, size_type _Off = npos) const; size_type find_last_of(const value_type* _Ptr, size_type _Off, size_type _Count) const; size_type find_last_of(const _Self& _Str, size_type _Off = npos) const; size_type find_last_not_of(value_type _Ch, size_type _Off = npos) const; size_type find_last_not_of(const value_type* _Ptr, size_type _Off = npos) const; size_type find_last_not_of(const value_type* _Ptr, size_type _Off, size_type _Count) const; size_type find_last_not_of(const _Self& _Str, size_type _Off = npos) const; void swap(_Self& _Str); ////////////////////////////////////////////////////////////////////////// // overloaded operators. ////////////////////////////////////////////////////////////////////////// // overloaded indexing. //value_type operator[]( size_type index ) const; // same as at() // 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); template CryStringT(const CryStackStringT& str); protected: // we prohibit an implicit conversion from CryStackString to make user aware of allocation! // -> use string(stackedString) instead // as the private statement seems to be ignored (VS C++), we add a compile time error, see below template _Self& operator=(const CryStackStringT& str) { // we add a compile-time error as the Visual C++ compiler seems to ignore the private statement? #if defined(__clang__) //CLANG_TODO: clang verifies things differently #else STATIC_CHECK(0, Use_Explicit_String_Assignment_When_Assigning_From_StackString); #endif // not reached, as above will generate a compile time error _Assign(str.c_str(), str.length()); return *this; } public: // string concatenation _Self& operator+=(const _Self& str); _Self& operator+=(value_type ch); _Self& operator+=(const_str str); //template friend CryStringT operator+( const CryStringT& str1, const CryStringT& str2 ); //template friend CryStringT operator+( const CryStringT& str, value_type ch ); //template friend CryStringT operator+( value_type ch, const CryStringT& str ); //template friend CryStringT operator+( const CryStringT& str1, const_str str2 ); //template friend CryStringT operator+( const_str str1, const CryStringT& str2 ); size_t GetAllocatedMemory() const { StrHeader* header = _header(); if (header == _emptyHeader()) { return 0; } return sizeof(StrHeader) + (header->nAllocSize + 1) * sizeof(value_type); } ////////////////////////////////////////////////////////////////////////// // 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, ...); //! 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 size_type _strlen(const_str str); static size_type _strnlen(const_str str, size_type maxLen); static const_str _strchr(const_str str, value_type c); static const_str _strrchr(const_str str, value_type c); static value_type* _strstr(value_type* str, const_str strSearch); static bool _IsValidString(const_str str); #if defined(WIN32) || defined(WIN64) static int _vscpf(const_str format, va_list args); #endif static int _vsnpf(value_type* buf, int cnt, const_str format, va_list args); public: ////////////////////////////////////////////////////////////////////////// // Only used for debugging statistics. ////////////////////////////////////////////////////////////////////////// static size_t _usedMemory(ptrdiff_t size) { static size_t s_used_memory = 0; s_used_memory += size; return s_used_memory; } protected: value_type* m_str; // pointer to ref counted string data // String header. Immediately after this header in memory starts actual string data. struct StrHeader { int nRefCount; int nLength; int nAllocSize; // Size of memory allocated at the end of this class. value_type* GetChars() { return (value_type*)(this + 1); } void AddRef() { nRefCount++; /*InterlockedIncrement(&_header()->nRefCount);*/}; int Release() { return --nRefCount; }; }; static StrHeader* _emptyHeader() { // Define 2 static buffers in a row. The 2nd is a dummy object to hold a single empty char string. static StrHeader sEmptyStringBuffer[2] = { {-1, 0, 0}, {0, 0, 0} }; return &sEmptyStringBuffer[0]; } // implementation helpers StrHeader* _header() const; void _AllocData(size_type nLen); static void _FreeData(StrHeader* 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(); static void _copy(value_type* dest, const value_type* src, size_type count); static void _move(value_type* dest, const value_type* src, size_type count); static void _set(value_type* dest, value_type ch, size_type count); }; // Variant of CryStringT which does not share memory with other strings. template class CryStringLocalT : public CryStringT { public: typedef CryStringT BaseType; typedef typename BaseType::const_str const_str; typedef typename BaseType::value_type value_type; typedef typename BaseType::size_type size_type; typedef typename BaseType::iterator iterator; CryStringLocalT() {} CryStringLocalT(const CryStringLocalT& str) : BaseType(str.c_str()) {} CryStringLocalT(const BaseType& str) : BaseType(str.c_str()) {} template CryStringLocalT(const CryStackStringT& str) : BaseType(str.c_str()) {} CryStringLocalT(const_str str) : BaseType(str) {} CryStringLocalT(const_str str, size_t len) : BaseType(str, len) {} CryStringLocalT(const_str begin, const_str end) : BaseType(begin, end) {} CryStringLocalT(size_type nRepeat, value_type ch) : BaseType(nRepeat, ch) {} CryStringLocalT(const typename CryStringT::_Self& str, size_type nOff, size_type nCount) : BaseType(str, nOff, nCount) {} CryStringLocalT& operator=(const BaseType& str) { BaseType::operator=(str.c_str()); return *this; } CryStringLocalT& operator=(const CryStringLocalT& str) { BaseType::operator=(str.c_str()); return *this; } CryStringLocalT& operator=(const_str str) { BaseType::operator=(str); return *this; } iterator begin() { return BaseType::m_str; } using BaseType::begin; // const version iterator end() { return BaseType::m_str + BaseType::length(); } using BaseType::end; // const version }; typedef CryStringLocalT CryStringLocal; // wrapper class for creation of strings without memory allocation // it creates a string with pointer pointing to const char* location // destructor sets the string to empty // NOTE: never copy a string from it, just use it as function parameters instead of const char* itself class CConstCharWrapper { public: //passing *this is safe since the char pointer is already set and therefore is the this-ptr constructed complete enough #pragma warning (push) #pragma warning (disable : 4355) CConstCharWrapper(const char* const cpString) : cpChar(cpString) , str(*this){assert(cpString); } //create stack string #pragma warning (pop) ~CConstCharWrapper(){str.m_str = CryStringT::_emptyHeader()->GetChars(); }//reset string operator const CryStringT&() const { return str; } //cast operator to const string reference private: const char* const cpChar; CryStringT str; char* GetCharPointer() const {return const_cast(cpChar); } //access function for string ctor friend class CryStringT; //both are bidirectional friends to avoid any other accesses }; //macro needed because compiler somehow cannot find the cast operator when not invoked directly #define CONST_TEMP_STRING(a) ((const string&)CConstCharWrapper(a)) ///////////////////////////////////////////////////////////////////////////// // CryStringT Implementation ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::StrHeader * CryStringT::_header() const { assert(m_str != NULL); return ((StrHeader*)m_str) - 1; } template inline typename CryStringT::size_type CryStringT::_strlen(const_str str) { return (str == NULL) ? 0 : (size_type)::strlen(str); } template <> inline CryStringT::size_type CryStringT::_strlen(const_str str) { return (str == NULL) ? 0 : (size_type)::wcslen(str); } template inline typename CryStringT::size_type CryStringT::_strnlen(const_str str, size_type maxLen) { size_type len = 0; if (str) { while (len < maxLen && *str != '\0') { len++; str++; } } return len; } template inline typename CryStringT::const_str CryStringT::_strchr(const_str str, value_type c) { return (str == NULL) ? 0 : ::strchr(str, c); } template <> inline CryStringT::const_str CryStringT::_strchr(const_str str, value_type c) { return (str == NULL) ? 0 : ::wcschr(str, c); } template inline typename CryStringT::const_str CryStringT::_strrchr(const_str str, value_type c) { return (str == NULL) ? 0 : ::strrchr(str, c); } template <> inline CryStringT::const_str CryStringT::_strrchr(const_str str, value_type c) { return (str == NULL) ? 0 : ::wcsrchr(str, c); } template inline typename CryStringT::value_type * CryStringT::_strstr(value_type * str, const_str strSearch) { return (str == NULL) ? 0 : (value_type*)::strstr(str, strSearch); } template <> inline CryStringT::value_type * CryStringT::_strstr(value_type * str, const_str strSearch) { return (str == NULL) ? 0 : ::wcsstr(str, strSearch); } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_copy(value_type* dest, const value_type* src, size_type count) { if (dest != src) { memcpy(dest, src, count * sizeof(value_type)); } } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_move(value_type* dest, const value_type* src, size_type count) { memmove(dest, src, count * sizeof(value_type)); } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_set(value_type* dest, value_type ch, size_type count) { COMPILE_TIME_ASSERT(sizeof(value_type) == sizeof(T)); COMPILE_TIME_ASSERT(sizeof(value_type) == 1); memset(dest, ch, count); } ////////////////////////////////////////////////////////////////////////// template <> inline void CryStringT::_set(value_type* dest, value_type ch, size_type count) { COMPILE_TIME_ASSERT(sizeof(value_type) == sizeof(wchar_t)); wmemset(dest, ch, count); } #if defined(WIN32) || defined(WIN64) template<> inline int CryStringT::_vscpf(const_str format, va_list args) { return _vscprintf(format, args); } template<> inline int CryStringT::_vscpf(const_str format, va_list args) { return _vscwprintf(format, args); } template<> inline int CryStringT::_vsnpf(value_type* buf, int cnt, const_str format, va_list args) { #pragma warning( push ) #pragma warning(disable: 4996) return _vsnprintf(buf, cnt, format, args); #pragma warning( pop ) } template<> inline int CryStringT::_vsnpf(value_type* buf, int cnt, const_str format, va_list args) { #pragma warning( push ) #pragma warning(disable: 4996) return _vsnwprintf(buf, cnt, format, args); #pragma warning( pop ) } #else template<> inline int CryStringT::_vsnpf(value_type* buf, int cnt, const_str format, va_list args) { return vsnprintf(buf, cnt, format, args); } template<> inline int CryStringT::_vsnpf(value_type* buf, int cnt, const_str format, va_list args) { return vswprintf(buf, cnt, format, args); } #endif ////////////////////////////////////////////////////////////////////////// template inline bool CryStringT::_IsValidString(const_str) { /* if (str == NULL) return false; int nLength = _strlen(str); return !::IsBadStringPtrA(str, nLength); */ return true; } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_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 (_header()->nRefCount > 1 || nLen > capacity()) { _Free(); _AllocData(nLen); } // Copy characters from new string to this buffer. _copy(m_str, sStr, nLen); // Set new length. check_convert(_header()->nLength) = nLen; // Make null terminated string. m_str[nLen] = 0; CRY_STRING_DEBUG(m_str) } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_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); _copy(m_str, sStr1, nLen1); _copy(m_str + nLen1, sStr2, nLen2); check_convert(_header()->nLength) = nLen1 + nLen2; m_str[nLen1 + nLen2] = 0; } CRY_STRING_DEBUG(m_str) } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_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 (_header()->nRefCount > 1 || length() + nLen > capacity()) { StrHeader* pOldData = _header(); _Concatenate(m_str, length(), sStr, nLen); _FreeData(pOldData); } else { _copy(m_str + length(), sStr, nLen); check_convert(_header()->nLength) = _header()->nLength + nLen; m_str[_header()->nLength] = 0; // Make null terminated string. } } } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_MakeUnique() { if (_header()->nRefCount > 1) { // If string is shared, make a copy of string buffer. StrHeader* pOldData = _header(); // This will not free header because reference count is greater then 1. _Free(); // Allocate a new string buffer. _AllocData(pOldData->nLength); // Full copy of null terminated string. _copy(m_str, pOldData->GetChars(), pOldData->nLength + 1); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_Initialize() { m_str = _emptyHeader()->GetChars(); } // always allocate one extra character for '\0' termination // assumes [optimistically] that data length will equal allocation length template inline void CryStringT::_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 = sizeof(StrHeader) + (nLen + 1) * sizeof(value_type); StrHeader* pData = (StrHeader*)azmalloc(allocLen, 32, CryStringAllocator); _usedMemory(allocLen); // For statistics. pData->nRefCount = 1; m_str = pData->GetChars(); check_convert(pData->nLength) = nLen; check_convert(pData->nAllocSize) = nLen; m_str[nLen] = 0; // null terminated string. } } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_Free() { if (_header()->nRefCount >= 0) // Not empty string. { _FreeData(_header()); _Initialize(); } } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::_FreeData(StrHeader* pData) { //Cry uses -1 to represent strings on the stack. if (pData->nRefCount < 0) { return; } if (pData->nRefCount == 0 || pData->Release() <= 0) { azfree((void*)pData, CryStringAllocator); } } ////////////////////////////////////////////////////////////////////////// template inline CryStringT::CryStringT() { _Initialize(); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT::CryStringT(const CryStringT& str) { assert(str._header()->nRefCount != 0); if (str._header()->nRefCount >= 0) { m_str = str.m_str; _header()->AddRef(); } else { _Initialize(); } } ////////////////////////////////////////////////////////////////////////// template inline CryStringT::CryStringT(const CryStringT& str, size_type nOff, size_type nCount) { _Initialize(); assign(str, nOff, nCount); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT::CryStringT(const_str str) { _Initialize(); // Make a copy of C string. size_type nLen = _strlen(str); if (nLen != 0) { _AllocData(nLen); _copy(m_str, str, nLen); CRY_STRING_DEBUG(m_str) } } template inline CryStringT::CryStringT(const CConstCharWrapper& str) { _Initialize(); m_str = const_cast(str.GetCharPointer()); } template template inline CryStringT::CryStringT(const CryStackStringT& str) { _Initialize(); const size_type nLength = str.length(); if (nLength > 0) { _AllocData(nLength); _copy(m_str, str, nLength); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// template inline CryStringT::CryStringT(const_str str, size_type nLength) { _Initialize(); if (nLength > 0) { _AllocData(nLength); _copy(m_str, str, nLength); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// template inline CryStringT::CryStringT(size_type nRepeat, value_type ch) { _Initialize(); if (nRepeat > 0) { _AllocData(nRepeat); _set(m_str, ch, nRepeat); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// template inline CryStringT::CryStringT(const_iterator _First, const_iterator _Last) { _Initialize(); size_type nLength = (size_type)(_Last - _First); if (nLength > 0) { _AllocData(nLength); _copy(m_str, _First, nLength); CRY_STRING_DEBUG(m_str) } } ////////////////////////////////////////////////////////////////////////// template inline CryStringT::~CryStringT() { _FreeData(_header()); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::length() const { return _header()->nLength; } template inline typename CryStringT::size_type CryStringT::size() const { return _header()->nLength; } template inline typename CryStringT::size_type CryStringT::capacity() const { return _header()->nAllocSize; } template inline bool CryStringT::empty() const { return length() == 0; } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::clear() { if (length() == 0) { return; } if (_header()->nRefCount >= 0) { _Free(); } else { resize(0); } assert(length() == 0); assert(_header()->nRefCount < 0 || capacity() == 0); } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::reserve(size_type nCount) { // Reserve of 0 is shrinking container to fit number of characters in it.. if (nCount > capacity()) { StrHeader* pOldData = _header(); _AllocData(nCount); _copy(m_str, pOldData->GetChars(), pOldData->nLength); _header()->nLength = pOldData->nLength; m_str[pOldData->nLength] = 0; _FreeData(pOldData); } else if (nCount == 0) { if (length() != capacity()) { StrHeader* pOldData = _header(); _AllocData(length()); _copy(m_str, pOldData->GetChars(), pOldData->nLength); _FreeData(pOldData); } } CRY_STRING_DEBUG(m_str) } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::append(const_str _Ptr) { *this += _Ptr; return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::append(const_str _Ptr, size_type nCount) { _ConcatenateInPlace(_Ptr, nCount); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::append(const CryStringT& _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 CryStringT& CryStringT::append(const CryStringT& _Str) { *this += _Str; return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::append(size_type nCount, value_type _Ch) { if (nCount > 0) { if (_header()->nRefCount > 1 || length() + nCount > capacity()) { StrHeader* pOldData = _header(); _AllocData(length() + nCount); _copy(m_str, pOldData->GetChars(), pOldData->nLength); _set(m_str + pOldData->nLength, _Ch, nCount); _FreeData(pOldData); } else { size_type nOldLength = length(); _set(m_str + nOldLength, _Ch, nCount); check_convert(_header()->nLength) = nOldLength + nCount; m_str[length()] = 0; // Make null terminated string. } } CRY_STRING_DEBUG(m_str) return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::append(const_iterator _First, const_iterator _Last) { append(_First, (size_type)(_Last - _First)); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::assign(const_str _Ptr) { *this = _Ptr; return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::assign(const_str _Ptr, size_type nCount) { size_type len = _strnlen(_Ptr, nCount); _Assign(_Ptr, len); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::assign(const CryStringT& _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 CryStringT& CryStringT::assign(const CryStringT& _Str) { *this = _Str; return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::assign(size_type nCount, value_type _Ch) { if (nCount >= 1) { _AllocData(nCount); _set(m_str, _Ch, nCount); CRY_STRING_DEBUG(m_str) } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::assign(const_iterator _First, const_iterator _Last) { assign(_First, (size_type)(_Last - _First)); return *this; } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::value_type CryStringT::at(size_type index) const { assert(index >= 0 && index < length()); return m_str[index]; } /* inline value_type& CryStringT::at( size_type index ) { // same as GetAt assert( index >= 0 && index < length() ); return m_str[index]; } */ /* inline CryStringT::value_type CryStringT::operator[]( size_type index ) const { assert( index >= 0 && index < length() ); return m_str[index]; } */ /* inline value_type& CryStringT::operator[]( size_type index ) { // same as GetAt assert( index >= 0 && index < length() ); return m_str[index]; } */ ////////////////////////////////////////////////////////////////////////// template inline int CryStringT::compare(const CryStringT& _Str) const { return compare(_Str.m_str); } template inline int CryStringT::compare(size_type _Pos1, size_type _Num1, const CryStringT& _Str) const { return compare(_Pos1, _Num1, _Str.m_str, npos); } template inline int CryStringT::compare(size_type _Pos1, size_type _Num1, const CryStringT& _Str, size_type nOff, size_type nCount) const { assert(nOff < _Str.length()); return compare(_Pos1, _Num1, _Str.m_str + nOff, nCount); } template inline int CryStringT::compare(const char* _Ptr) const { return strcmp(m_str, _Ptr); } template inline int CryStringT::compare(const wchar_t* _Ptr) const { return wcscmp(m_str, _Ptr); } template inline int CryStringT::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 : 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 CryStringT::compareNoCase(const CryStringT& _Str) const { return _stricmp(m_str, _Str.m_str); } template inline int CryStringT::compareNoCase(size_type _Pos1, size_type _Num1, const CryStringT& _Str) const { return compareNoCase(_Pos1, _Num1, _Str.m_str, npos); } template inline int CryStringT::compareNoCase(size_type _Pos1, size_type _Num1, const CryStringT& _Str, size_type nOff, size_type nCount) const { assert(nOff < _Str.length()); return compareNoCase(_Pos1, _Num1, _Str.m_str + nOff, nCount); } template inline int CryStringT::compareNoCase(const value_type* _Ptr) const { return _stricmp(m_str, _Ptr); } template inline int CryStringT::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 : _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 CryStringT::size_type CryStringT::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; } _copy(_Ptr, m_str + nOff, nCount); return nCount; } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::resize(size_type nCount, value_type _Ch) { _MakeUnique(); if (nCount > length()) { size_type numToAdd = nCount - length(); append(numToAdd, _Ch); } else if (nCount < length()) { _header()->nLength = nCount; m_str[length()] = 0; // Make null terminated string. } } ////////////////////////////////////////////////////////////////////////// //! compare helpers template inline bool operator==(const CryStringT& s1, const CryStringT& s2) { return s1.compare(s2) == 0; } template inline bool operator==(const CryStringT& s1, const typename CryStringT::value_type* s2) { return s1.compare(s2) == 0; } template inline bool operator==(const typename CryStringT::value_type* s1, const CryStringT& s2) { return s2.compare(s1) == 0; } template inline bool operator!=(const CryStringT& s1, const CryStringT& s2) { return s1.compare(s2) != 0; } template inline bool operator!=(const CryStringT& s1, const typename CryStringT::value_type* s2) { return s1.compare(s2) != 0; } template inline bool operator!=(const typename CryStringT::value_type* s1, const CryStringT& s2) { return s2.compare(s1) != 0; } template inline bool operator<(const CryStringT& s1, const CryStringT& s2) { return s1.compare(s2) < 0; } template inline bool operator<(const CryStringT& s1, const typename CryStringT::value_type* s2) { return s1.compare(s2) < 0; } template inline bool operator<(const typename CryStringT::value_type* s1, const CryStringT& s2) { return s2.compare(s1) > 0; } template inline bool operator>(const CryStringT& s1, const CryStringT& s2) { return s1.compare(s2) > 0; } template inline bool operator>(const CryStringT& s1, const typename CryStringT::value_type* s2) { return s1.compare(s2) > 0; } template inline bool operator>(const typename CryStringT::value_type* s1, const CryStringT& s2) { return s2.compare(s1) < 0; } template inline bool operator<=(const CryStringT& s1, const CryStringT& s2) { return s1.compare(s2) <= 0; } template inline bool operator<=(const CryStringT& s1, const typename CryStringT::value_type* s2) { return s1.compare(s2) <= 0; } template inline bool operator<=(const typename CryStringT::value_type* s1, const CryStringT& s2) { return s2.compare(s1) >= 0; } template inline bool operator>=(const CryStringT& s1, const CryStringT& s2) { return s1.compare(s2) >= 0; } template inline bool operator>=(const CryStringT& s1, const typename CryStringT::value_type* s2) { return s1.compare(s2) >= 0; } template inline bool operator>=(const typename CryStringT::value_type* s1, const CryStringT& s2) { return s2.compare(s1) <= 0; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::operator=(value_type ch) { _Assign(&ch, 1); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT operator+(const CryStringT& string1, typename CryStringT::value_type ch) { CryStringT s(string1); s.append(1, ch); return s; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT operator+(typename CryStringT::value_type ch, const CryStringT& str) { CryStringT s; s.reserve(str.size() + 1); s.append(1, ch); s.append(str); return s; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT operator+(const CryStringT& string1, const CryStringT& string2) { CryStringT s(string1); s.append(string2); return s; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT operator+(const CryStringT& str1, const typename CryStringT::value_type* str2) { CryStringT s(str1); s.append(str2); return s; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT operator+(const typename CryStringT::value_type* str1, const CryStringT& str2) { assert(str1 == NULL || CryStringT::_IsValidString(str1)); CryStringT s; s.reserve(CryStringT::_strlen(str1) + str2.size()); s.append(str1); s.append(str2); return s; } template inline CryStringT& CryStringT::operator=(const CryStringT& str) { if (m_str != str.m_str) { if (_header()->nRefCount < 0) { // Empty string. // _Assign( str.m_str,str.length() ); if (str._header()->nRefCount < 0) { ; // two empty strings... } else { m_str = str.m_str; _header()->AddRef(); } } else if (str._header()->nRefCount < 0) { // If source string is empty. _Free(); m_str = str.m_str; } else { // Copy string reference. _Free(); m_str = str.m_str; _header()->AddRef(); } } return *this; } template inline CryStringT& CryStringT::operator=(const_str str) { assert(str == NULL || _IsValidString(str)); _Assign(str, _strlen(str)); return *this; } template inline CryStringT& CryStringT::operator+=(const_str str) { assert(str == NULL || _IsValidString(str)); _ConcatenateInPlace(str, _strlen(str)); return *this; } template inline CryStringT& CryStringT::operator+=(value_type ch) { _ConcatenateInPlace(&ch, 1); return *this; } template inline CryStringT& CryStringT::operator+=(const CryStringT& str) { _ConcatenateInPlace(str.m_str, str.length()); return *this; } //! find first single character template inline typename CryStringT::size_type CryStringT::find(value_type ch, size_type pos) const { if (!(pos >= 0 && pos <= length())) { return (typename CryStringT::size_type)npos; } const_str str = _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 CryStringT::size_type CryStringT::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 = _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 CryStringT::size_type CryStringT::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 CryStringT::size_type CryStringT::rfind(const CryStringT& subs, size_type pos) const { size_type res = npos; for (int i = (int)size(); i >= (int)pos; --i) { size_type findRes = find(subs, i); if (findRes != npos) { res = findRes; break; } } return res; } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::find_first_of(const CryStringT& _Str, size_type _Off) const { return find_first_of(_Str.m_str, _Off); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::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) ? (size_type) - 1 : (size_type)(str - m_str); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::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); } template <> inline CryStringT::size_type CryStringT::find_first_of(const_str charSet, size_type nOff) const { assert(_IsValidString(charSet)); if (!(nOff >= 0 && nOff <= length())) { return npos; } const_str str = wcspbrk(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 CryStringT::size_type CryStringT::find_first_not_of(const value_type* _Ptr, size_type _Off) const { return find_first_not_of(_Ptr, _Off, _strlen(_Ptr)); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::find_first_not_of(const CryStringT& _Str, size_type _Off) const { return find_first_not_of(_Str.m_str, _Off); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::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 CryStringT::size_type CryStringT::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 typename CryStringT::size_type CryStringT::find_last_of(value_type _Ch, size_type _Off) const { size_type nLenght(length()); // Empty strings, always return npos (same semantic as std::string). if (nLenght == 0) { return npos; } // If the offset is is bigger than the size of the string if (_Off >= nLenght) { // We set it to the size of the string -1, so we will not do bad pointer operations nor we will // test the null terminating character. _Off = nLenght - 1; } // From the character at the offset position, going to to the direction of the first character. for (const value_type* str = begin() + _Off; true; --str) { // We found a character in the string which matches the input character. if (*str == _Ch) { return size_type(str - begin()); // Character found! } // If the next element will be begin()-1, then we should stop. if (str == begin()) { break; } } // We found nothing. return npos; } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::find_last_of(const value_type* _Ptr, size_type _Off) const { // This function is actually a convenience alias... // BTW: what will happeb if wchar_t is used here? return find_last_of(_Ptr, _Off, _strlen(_Ptr)); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::find_last_of(const value_type* _Ptr, size_type _Off, size_type _Count) const { size_type nLenght(length()); // Empty strings, always return npos (same semantic as std::string). if (nLenght == 0) { return npos; } // If the offset is is bigger than the size of the string if (_Off >= nLenght) { // We set it to the size of the string -1, so we will not do bad pointer operations nor we will // test the null terminating character. _Off = nLenght - 1; } // From the character at the offset position, going to to the direction of the first character. const value_type* charsFirst = _Ptr, * charsLast = _Ptr + _Count; for (const value_type* str = begin() + _Off; true; --str) { const value_type* c; // For every character in the character set. for (c = charsFirst; c != charsLast; ++c) { // If the current character matches any of the charcaters in the input string... if (*c == *str) { // This is the value we must return. return size_type(str - begin()); } } // If the next element will be begin()-1, then we should stop. if (str == begin()) { break; } } // We couldn't find any character of the input string in the current string. return npos; } ///////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::find_last_of(const _Self& strCharSet, size_type _Off) const { size_type nLenght(length()); // Empty strings, always return npos (same semantic as std::string). if (nLenght == 0) { return npos; } // If the offset is is bigger than the size of the string if (_Off >= nLenght) { // We set it to the size of the string -1, so we will not do bad pointer operations nor we will // test the null terminating character. _Off = nLenght - 1; } // From the character at the offset position, going to to the direction of the first character. for (const value_type* str = begin() + _Off; true; --str) { // We check every character of the input string. for (const value_type* strInputCharacter = strCharSet.begin(); strInputCharacter != strCharSet.end(); ++strInputCharacter) { // If any character matches. if (*str == *strInputCharacter) { // We return the position where we found it. return size_type(str - begin()); // Character found! } } // If the next element will be begin()-1, then we should stop. if (str == begin()) { break; } } // As we couldn't find any matching character...we return the appropriate value. return npos; } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::find_last_not_of(value_type _Ch, size_type _Off) const { size_type nLenght(length()); // Empty strings, always return npos (same semantic as std::string). if (nLenght == 0) { return npos; } // If the offset is is bigger than the size of the string if (_Off >= nLenght) { // We set it to the size of the string -1, so we will not do bad pointer operations nor we will // test the null terminating character. _Off = nLenght - 1; } // From the character at the offset position, going to to the direction of the first character. for (const value_type* str = begin() + _Off; true; --str) { // If the current character being analyzed is different of the input character. if (*str != _Ch) { // We found the last item which is not the input character before the given offset. return size_type(str - begin()); // Character found! } // If the next element will be begin()-1, then we should stop. if (str == begin()) { break; } } // As we couldn't find any matching character...we return the appropriate value. return npos; } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::find_last_not_of(const value_type* _Ptr, size_type _Off) const { // This function is actually a convenience alias... // BTW: what will happeb if wchar_t is used here? return find_last_not_of(_Ptr, _Off, _strlen(_Ptr)); } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::find_last_not_of(const value_type* _Ptr, size_type _Off, size_type _Count) const { size_type nLenght(length()); // Empty strings, always return npos (same semantic as std::string). if (nLenght == 0) { return npos; } // If the offset is is bigger than the size of the string if (_Off >= nLenght) { // We set it to the size of the string -1, so we will not do bad pointer operations nor we will // test the null terminating character. _Off = nLenght - 1; } // From the character at the offset position, going to to the direction of the first character. const value_type* charsFirst = _Ptr, * charsLast = _Ptr + _Count; for (const value_type* str = begin() + _Off; true; --str) { bool boFoundAny(false); const value_type* c; // For every character in the character set. for (c = charsFirst; c != charsLast; ++c) { // If the current character matches any of the charcaters in the input string... if (*c == *str) { // So we signal it was found and stop this search. boFoundAny = true; break; } } // Using a different solution of the other similar methods // to make it easier to read. // If the character being analyzed is not in the set... if (!boFoundAny) { //.. we return the position where we found it. return size_type(str - begin()); } // If the next element will be begin()-1, then we should stop. if (str == begin()) { break; } } // We couldn't find any character of the input string not in the character set. return npos; } ////////////////////////////////////////////////////////////////////////// template inline typename CryStringT::size_type CryStringT::find_last_not_of(const _Self& _Str, size_type _Off) const { size_type nLenght(length()); // Empty strings, always return npos (same semantic as std::string). if (nLenght == 0) { return npos; } // If the offset is is bigger than the size of the string if (_Off >= nLenght) { // We set it to the size of the string -1, so we will not do bad pointer operations nor we will // test the null terminating character. _Off = nLenght - 1; } // From the character at the offset position, going to to the direction of the first character. for (const value_type* str = begin() + _Off; true; --str) { bool boFoundAny(false); for (const value_type* strInputCharacter = _Str.begin(); strInputCharacter != _Str.end(); ++strInputCharacter) { // The character matched one of the character set... if (*strInputCharacter == *str) { // So we signal it was found and stop this search. boFoundAny = true; break; } } // Using a different solution of the other similar methods // to make it easier to read. // If the character being analyzed is not in the set... if (!boFoundAny) { //.. we return the position where we found it. return size_type(str - begin()); } // If the next element will be begin()-1, then we should stop. if (str == begin()) { break; } } // As we couldn't find any matching character...we return the appropriate value. return npos; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT CryStringT::substr(size_type pos, size_type count) const { if (pos >= length()) { return CryStringT(); } if (count == npos) { count = length() - pos; } if (pos + count > length()) { count = length() - pos; } return CryStringT(m_str + pos, count); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::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; _move(m_str + nIndex, m_str + nIndex + nCount, nNumToCopy); _header()->nLength = length() - nCount; } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::insert(size_type nIndex, value_type ch) { return insert(nIndex, 1, ch); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::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) { StrHeader* pOldData = _header(); const_str pstr = m_str; _AllocData(nNewLength); _copy(m_str, pstr, pOldData->nLength + 1); _FreeData(pOldData); } _move(m_str + nIndex + nCount, m_str + nIndex, (nNewLength - nIndex - nCount) + 1); _set(m_str + nIndex, ch, nCount); _header()->nLength = nNewLength; CRY_STRING_DEBUG(m_str) return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::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) { StrHeader* pOldData = _header(); const_str pOldStr = m_str; _AllocData(nNewLength); _copy(m_str, pOldStr, (pOldData->nLength + 1)); _FreeData(pOldData); } _move(m_str + nIndex + nInsertLength, m_str + nIndex, (nNewLength - nIndex - nInsertLength + 1)); _copy(m_str + nIndex, pstr, nInsertLength); _header()->nLength = nNewLength; m_str[length()] = 0; } CRY_STRING_DEBUG(m_str) return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::insert(size_type nIndex, const_str pstr) { return insert(nIndex, pstr, _strlen(pstr)); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::replace(size_type pos, size_type count, const_str strNew) { return replace(pos, count, strNew, _strlen(strNew)); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::replace(size_type pos, size_type count, const_str strNew, size_type count2) { erase(pos, count); insert(pos, strNew, count2); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::replace(size_type pos, size_type count, size_type nNumChars, value_type chNew) { erase(pos, count); insert(pos, nNumChars, chNew); return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::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 CryStringT& CryStringT::replace(const_str strOld, const_str strNew) { size_type nSourceLen = _strlen(strOld); if (nSourceLen == 0) { return *this; } size_type nReplacementLen = _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 = _strstr(strStart, strOld)) != NULL) { nCount++; strStart = strTarget + nSourceLen; } strStart += _strlen(strStart) + 1; } if (nCount > 0) { _MakeUnique(); size_type nOldLength = length(); size_type nNewLength = nOldLength + (nReplacementLen - nSourceLen) * nCount; if (capacity() < nNewLength || _header()->nRefCount > 1) { StrHeader* pOldData = _header(); const_str pstr = m_str; _AllocData(nNewLength); _copy(m_str, pstr, pOldData->nLength); _FreeData(pOldData); } strStart = m_str; strEnd = m_str + length(); while (strStart < strEnd) { while ((strTarget = _strstr(strStart, strOld)) != NULL) { size_type nBalance = nOldLength - ((size_type)(strTarget - m_str) + nSourceLen); _move(strTarget + nReplacementLen, strTarget + nSourceLen, nBalance); _copy(strTarget, strNew, nReplacementLen); strStart = strTarget + nReplacementLen; strStart[nBalance] = 0; nOldLength += (nReplacementLen - nSourceLen); } strStart += _strlen(strStart) + 1; } _header()->nLength = nNewLength; } CRY_STRING_DEBUG(m_str) return *this; } ////////////////////////////////////////////////////////////////////////// template inline void CryStringT::swap(CryStringT& _Str) { value_type* temp = _Str.m_str; _Str.m_str = m_str; m_str = temp; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::Format(const_str format, ...) { assert(_IsValidString(format)); #if defined(WIN32) || defined(WIN64) va_list argList; va_start(argList, format); int n = _vscpf(format, argList); if (n < 0) { n = 0; } resize(n); //this will actually allocate n+1 elements to accommodate the null terminator _vsnpf(m_str, n, format, argList); va_end(argList); return *this; #else value_type temp[4096]; // Limited to 4096 characters! va_list argList; va_start(argList, format); _vsnpf(temp, 4096, format, argList); temp[4095] = '\0'; va_end(argList); *this = temp; return *this; #endif } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::MakeLower() { _MakeUnique(); for (value_type* s = m_str; *s != 0; s++) { const value_type c = *s; *s = (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; // ASCII only, standard "C" locale } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::MakeUpper() { _MakeUnique(); for (value_type* s = m_str; *s != 0; s++) { const value_type c = *s; *s = (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; // ASCII only, standard "C" locale } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::Trim() { return TrimRight().TrimLeft(); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::Trim(value_type ch) { _MakeUnique(); const value_type chset[2] = { ch, 0 }; return TrimRight(chset).TrimLeft(chset); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::Trim(const value_type* sCharSet) { _MakeUnique(); return TrimRight(sCharSet).TrimLeft(sCharSet); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::TrimRight(value_type ch) { const value_type chset[2] = { ch, 0 }; return TrimRight(chset); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::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) && (_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(); _header()->nLength = nNewLength; m_str[nNewLength] = 0; } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::TrimRight() { if (length() < 1) { return *this; } const value_type* last = m_str + length() - 1; const value_type* str = last; while ((str != m_str) && (isspace((unsigned char)*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(); _header()->nLength = nNewLength; m_str[nNewLength] = 0; } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::TrimLeft(value_type ch) { const value_type chset[2] = { ch, 0 }; return TrimLeft(chset); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::TrimLeft(const value_type* sCharSet) { if (!sCharSet || !(*sCharSet)) { return *this; } const value_type* str = m_str; while ((*str != 0) && (_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; _move(m_str, m_str + nOff, nNewLength + 1); _header()->nLength = nNewLength; m_str[nNewLength] = 0; } return *this; } ////////////////////////////////////////////////////////////////////////// template inline CryStringT& CryStringT::TrimLeft() { const value_type* str = m_str; while ((*str != 0) && (isspace((unsigned char)*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; _move(m_str, m_str + nOff, nNewLength + 1); _header()->nLength = nNewLength; m_str[nNewLength] = 0; } return *this; } template inline CryStringT CryStringT::Right(size_type count) const { if (count == npos) { return CryStringT(); } else if (count > length()) { return *this; } return CryStringT(m_str + length() - count, count); } template inline CryStringT CryStringT::Left(size_type count) const { if (count == npos) { return CryStringT(); } else if (count > length()) { count = length(); } return CryStringT(m_str, count); } // strspn equivalent template inline CryStringT CryStringT::SpanIncluding(const_str charSet) const { assert(_IsValidString(charSet)); return Left((size_type)strspn(m_str, charSet)); } // strcspn equivalent template inline CryStringT CryStringT::SpanExcluding(const_str charSet) const { assert(_IsValidString(charSet)); return Left((size_type)strcspn(m_str, charSet)); } ////////////////////////////////////////////////////////////////////////// template inline CryStringT CryStringT::Tokenize(const_str charSet, int& nStart) const { if (nStart < 0) { return CryStringT(); } if (!charSet) { return *this; } const_str sPlace = m_str + nStart; const_str sEnd = m_str + length(); if (sPlace < sEnd) { int nIncluding = (int)strspn(sPlace, charSet); if ((sPlace + nIncluding) < sEnd) { sPlace += nIncluding; int nExcluding = (int)strcspn(sPlace, charSet); int nFrom = nStart + nIncluding; nStart = nFrom + nExcluding + 1; return substr(nFrom, nExcluding); } } // Return empty string. nStart = -1; return CryStringT(); } ////////////////////////////////////////////////////////////////////////// // This code prevents std::string compiling in Win32 with STLPort ////////////////////////////////////////////////////////////////////////// #if defined(WIN32) && !defined(WIN64) && defined(_STLP_BEGIN_NAMESPACE) && !defined(DONT_BAN_STD_STRING) #define CRYINCLUDE_STLP_STRING_FWD_H #define CRYINCLUDE_STLP_INTERNAL_STRING_H namespace std { //const char* __get_c_string( const CryStringT &str ) { return str.c_str(); }; class string { // std::string must not be used if CryString included. // Use string instead. }; } ////////////////////////////////////////////////////////////////////////// #endif // WIN64 #if !defined(RESOURCE_COMPILER) typedef CryStringT string; typedef CryStringT wstring; #else typedef CryStringLocalT string; typedef CryStringLocalT wstring; #endif // __CryString_h__ #else // !defined(NOT_USE_CRY_STRING) #include // STL string typedef std::string string; typedef std::wstring wstring; #endif // !defined(NOT_USE_CRY_STRING) namespace AZStd { template <> struct hash<::string> { typedef ::string argument_type; typedef size_t result_type; inline result_type operator()(const argument_type& value) const { return hash_string(value.c_str(), value.length()); } static size_t hash_string(const char* str, size_t length) { size_t hash = 14695981039346656037ULL; const size_t fnvPrime = 1099511628211ULL; const char* cptr = str; for (; length; --length) { hash ^= static_cast(*cptr++); hash *= fnvPrime; } return hash; } }; } #endif // CRYINCLUDE_CRYCOMMON_CRYSTRING_H