You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Legacy/CryCommon/CryFixedString.h

2337 lines
72 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
// 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 <string.h>
#include <wchar.h>
#include <limits.h>
#include <stdarg.h>
#include <ctype.h>
#include <wctype.h>
#include <AzCore/base.h>
#include "CryString.h"
#ifndef CRY_STRING_DEBUG
#define CRY_STRING_DEBUG(s)
#endif
#define UNITTEST_CRYFIXEDSTRING (0)
template <class T>
class CharTraits;
// traits for char
template <>
class CharTraits<char>
{
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<value_type>(toupper(c));
}
ILINE value_type _traits_tolower(value_type c) const
{
return static_cast<value_type>(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<wchar_t>
{
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 T, size_t S>
class CryStackStringT
: public CharTraits<T>
{
public:
//////////////////////////////////////////////////////////////////////////
// Types compatible with STL string.
//////////////////////////////////////////////////////////////////////////
typedef CryStackStringT<T, S> _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<T>& 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<T>& str);
void move(_Self& src);
#if defined(LINUX) || defined(APPLE)
template<size_t AnySize>
_Self& operator=(const CryStackStringT<T, AnySize>& 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<T>& 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<T,S> Implementation
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline bool CryStackStringT<T, S>::_IsValidString(const_str)
{
return true;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T, S>::_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<T>::_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 <class T, size_t S>
inline void CryStackStringT<T, S>::_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<T>::_copy(m_str, sStr1, nLen1);
CharTraits<T>::_copy(m_str + nLen1, sStr2, nLen2);
m_nLength = nLen1 + nLen2;
m_str[nLen1 + nLen2] = 0;
}
CRY_STRING_DEBUG(m_str)
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T, S>::_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<T>::_copy(m_str + length(), sStr, nLen);
m_nLength += nLen;
m_str[m_nLength] = 0; // Make null terminated string.
}
}
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T, S>::_MakeUnique()
{
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T, S>::_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 <class T, size_t S>
inline void CryStackStringT<T, S>::_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 <class T, size_t S>
inline void CryStackStringT<T, S>::_Free()
{
_FreeData(m_str);
_Initialize();
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T, S>::_FreeData(value_type* pData)
{
if (pData != m_strBuf)
{
size_t allocLen = (m_nAllocSize + 1) * sizeof(value_type);
_usedMemory(-check_cast<ptrdiff_t>(allocLen)); // For statistics.
CryModuleFree(pData);
}
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>::CryStackStringT()
{
_Initialize();
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>::CryStackStringT(const CryStackStringT<T, S>& str)
{
_Initialize();
_Assign(str.c_str(), str.length());
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>::CryStackStringT(const CryStackStringT<T, S>& str, size_type nOff, size_type nCount)
{
_Initialize();
assign(str, nOff, nCount);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>::CryStackStringT(const_str str)
{
_Initialize();
// Make a copy of C string.
size_type nLen = this->_strlen(str);
if (nLen != 0)
{
_AllocData(nLen);
CharTraits<T>::_copy(m_str, str, nLen);
CRY_STRING_DEBUG(m_str)
}
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>::CryStackStringT(const CryStringT<T>& str)
{
_Initialize();
size_t nLength = str.size();
if (nLength > 0)
{
_AllocData(nLength);
CharTraits<T>::_copy(m_str, str.c_str(), nLength);
CRY_STRING_DEBUG(m_str)
}
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>::CryStackStringT(const_str str, size_type nLength)
{
_Initialize();
if (nLength > 0)
{
_AllocData(nLength);
CharTraits<T>::_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 <class T, size_t S>
inline CryStackStringT<T, S>::CryStackStringT(size_type nRepeat, value_type ch)
{
_Initialize();
if (nRepeat > 0)
{
_AllocData(nRepeat);
CharTraits<T>::_set(m_str, ch, nRepeat);
CRY_STRING_DEBUG(m_str)
}
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>::CryStackStringT(const_iterator _First, const_iterator _Last)
{
_Initialize();
size_type nLength = (size_type)(_Last - _First);
if (nLength > 0)
{
_AllocData(nLength);
CharTraits<T>::_copy(m_str, _First, nLength);
CRY_STRING_DEBUG(m_str)
}
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>::~CryStackStringT()
{
_FreeData(m_str);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::length() const
{
return m_nLength;
}
template <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::size() const
{
return m_nLength;
}
template <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::capacity() const
{
return m_nAllocSize;
}
template <class T, size_t S>
inline bool CryStackStringT<T, S>::empty() const
{
return length() == 0;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T, S>::clear()
{
if (length() == 0)
{
return;
}
_Free();
assert(length() == 0);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T, S>::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<T>::_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<T>::_copy(m_str, pOldData, nOldLength); // we can safely use CharTraits<T>::_copy, as we never overlap here (in case of static buffer, we don't shrink anyway)
_FreeData(pOldData);
// }
}
}
}
CRY_STRING_DEBUG(m_str)
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::append(const_str _Ptr)
{
*this += _Ptr;
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::append(const_str _Ptr, size_type nCount)
{
_ConcatenateInPlace(_Ptr, nCount);
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::append(const CryStackStringT<T, S>& _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 <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::append(const CryStackStringT<T, S>& _Str)
{
*this += _Str;
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::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<T>::_copy(m_str, pOldData, nOldLength);
CharTraits<T>::_set(m_str + nOldLength, _Ch, nCount);
_FreeData(pOldData);
}
else
{
size_type nOldLength = length();
CharTraits<T>::_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 <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::append(const_iterator _First, const_iterator _Last)
{
append(_First, (size_type)(_Last - _First));
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::assign(const_str _Ptr)
{
*this = _Ptr;
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::assign(const_str _Ptr, size_type nCount)
{
size_type len = this->_strlen(_Ptr);
_Assign(_Ptr, (nCount < len) ? nCount : len);
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::assign(const CryStackStringT<T, S>& _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 <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::assign(const CryStackStringT<T, S>& _Str)
{
*this = _Str;
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::assign(size_type nCount, value_type _Ch)
{
if (nCount >= 1)
{
_AllocData(nCount);
CharTraits<T>::_set(m_str, _Ch, nCount);
CRY_STRING_DEBUG(m_str)
}
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::assign(const_iterator _First, const_iterator _Last)
{
assign(_First, (size_type)(_Last - _First));
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline typename CryStackStringT<T, S>::value_type CryStackStringT<T, S>::at(size_type index) const
{
assert(index >= 0 && index < length());
return m_str[index];
}
/*
inline value_type& CryStackStringT<T,S>::at( size_type index )
{
// same as GetAt
assert( index >= 0 && index < length() );
return m_str[index];
}
*/
template <class T, size_t S>
inline typename CryStackStringT<T, S>::value_type CryStackStringT<T, S>::operator[](size_type index) const
{
assert(index < length());
return m_str[index];
}
/*
inline value_type& CryStackStringT<T,S>::operator[]( size_type index )
{
// same as GetAt
assert( index >= 0 && index < length() );
return m_str[index];
}
*/
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline int CryStackStringT<T, S>::compare(const CryStackStringT<T, S>& _Str) const
{
return CharTraits<T>::_strcmp(m_str, _Str.m_str);
}
template <class T, size_t S>
inline int CryStackStringT<T, S>::compare(size_type _Pos1, size_type _Num1, const CryStackStringT<T, S>& _Str) const
{
return compare(_Pos1, _Num1, _Str.m_str, npos);
}
template <class T, size_t S>
inline int CryStackStringT<T, S>::compare(size_type _Pos1, size_type _Num1, const CryStackStringT<T, S>& _Str, size_type nOff, size_type nCount) const
{
assert(nOff < _Str.length());
return compare(_Pos1, _Num1, _Str.m_str + nOff, nCount);
}
template <class T, size_t S>
inline int CryStackStringT<T, S>::compare(const value_type* _Ptr) const
{
return CharTraits<T>::_strcmp(m_str, _Ptr);
}
template <class T, size_t S>
inline int CryStackStringT<T, S>::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<T>::_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 <class T, size_t S>
inline int CryStackStringT<T, S>::compareNoCase(const CryStackStringT<T, S>& _Str) const
{
return CharTraits<T>::_stricmp(m_str, _Str.m_str);
}
template <class T, size_t S>
inline int CryStackStringT<T, S>::compareNoCase(size_type _Pos1, size_type _Num1, const CryStackStringT<T, S>& _Str) const
{
return compareNoCase(_Pos1, _Num1, _Str.m_str, npos);
}
template <class T, size_t S>
inline int CryStackStringT<T, S>::compareNoCase(size_type _Pos1, size_type _Num1, const CryStackStringT<T, S>& _Str, size_type nOff, size_type nCount) const
{
assert(nOff < _Str.length());
return compareNoCase(_Pos1, _Num1, _Str.m_str + nOff, nCount);
}
template <class T, size_t S>
inline int CryStackStringT<T, S>::compareNoCase(const value_type* _Ptr) const
{
return CharTraits<T>::_stricmp(m_str, _Ptr);
}
template <class T, size_t S>
inline int CryStackStringT<T, S>::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<T>::_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 <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::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<T>::_copy(_Ptr, m_str + nOff, nCount);
return nCount;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T, S>::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 <class T, size_t S>
inline bool operator==(const CryStackStringT<T, S>& s1, const CryStackStringT<T, S>& s2)
{ return s1.compare(s2) == 0; }
template <class T, size_t S>
inline bool operator==(const CryStackStringT<T, S>& s1, const typename CryStackStringT<T, S>::value_type* s2)
{ return s1.compare(s2) == 0; }
template <class T, size_t S>
inline bool operator==(const typename CryStackStringT<T, S>::value_type* s1, const CryStackStringT<T, S>& s2)
{ return s2.compare(s1) == 0; }
template <class T, size_t S>
inline bool operator!=(const CryStackStringT<T, S>& s1, const CryStackStringT<T, S>& s2)
{ return s1.compare(s2) != 0; }
template <class T, size_t S>
inline bool operator!=(const CryStackStringT<T, S>& s1, const typename CryStackStringT<T, S>::value_type* s2)
{ return s1.compare(s2) != 0; }
template <class T, size_t S>
inline bool operator!=(const typename CryStackStringT<T, S>::value_type* s1, const CryStackStringT<T, S>& s2)
{ return s2.compare(s1) != 0; }
template <class T, size_t S>
inline bool operator<(const CryStackStringT<T, S>& s1, const CryStackStringT<T, S>& s2)
{ return s1.compare(s2) < 0; }
template <class T, size_t S>
inline bool operator<(const CryStackStringT<T, S>& s1, const typename CryStackStringT<T, S>::value_type* s2)
{ return s1.compare(s2) < 0; }
template <class T, size_t S>
inline bool operator<(const typename CryStackStringT<T, S>::value_type* s1, const CryStackStringT<T, S>& s2)
{ return s2.compare(s1) > 0; }
template <class T, size_t S>
inline bool operator>(const CryStackStringT<T, S>& s1, const CryStackStringT<T, S>& s2)
{ return s1.compare(s2) > 0; }
template <class T, size_t S>
inline bool operator>(const CryStackStringT<T, S>& s1, const typename CryStackStringT<T, S>::value_type* s2)
{ return s1.compare(s2) > 0; }
template <class T, size_t S>
inline bool operator>(const typename CryStackStringT<T, S>::value_type* s1, const CryStackStringT<T, S>& s2)
{ return s2.compare(s1) < 0; }
template <class T, size_t S>
inline bool operator<=(const CryStackStringT<T, S>& s1, const CryStackStringT<T, S>& s2)
{ return s1.compare(s2) <= 0; }
template <class T, size_t S>
inline bool operator<=(const CryStackStringT<T, S>& s1, const typename CryStackStringT<T, S>::value_type* s2)
{ return s1.compare(s2) <= 0; }
template <class T, size_t S>
inline bool operator<=(const typename CryStackStringT<T, S>::value_type* s1, const CryStackStringT<T, S>& s2)
{ return s2.compare(s1) >= 0; }
template <class T, size_t S>
inline bool operator>=(const CryStackStringT<T, S>& s1, const CryStackStringT<T, S>& s2)
{ return s1.compare(s2) >= 0; }
template <class T, size_t S>
inline bool operator>=(const CryStackStringT<T, S>& s1, const typename CryStackStringT<T, S>::value_type* s2)
{ return s1.compare(s2) >= 0; }
template <class T, size_t S>
inline bool operator>=(const typename CryStackStringT<T, S>::value_type* s1, const CryStackStringT<T, S>& s2)
{ return s2.compare(s1) <= 0; }
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::operator=(value_type ch)
{
_Assign(&ch, 1);
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S> operator+(const CryStackStringT<T, S>& string1, typename CryStackStringT<T, S>::value_type ch)
{
CryStackStringT<T, S> s(string1);
s.append(1, ch);
return s;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S> operator+(typename CryStackStringT<T, S>::value_type ch, const CryStackStringT<T, S>& str)
{
CryStackStringT<T, S> s;
s.reserve(str.size() + 1);
s.append(1, ch);
s.append(str);
return s;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S> operator+(const CryStackStringT<T, S>& string1, const CryStackStringT<T, S>& string2)
{
CryStackStringT<T, S> s(string1);
s.append(string2);
return s;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S> operator+(const CryStackStringT<T, S>& str1, const typename CryStackStringT<T, S>::value_type* str2)
{
CryStackStringT<T, S> s(str1);
s.append(str2);
return s;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S> operator+(const typename CryStackStringT<T, S>::value_type* str1, const CryStackStringT<T, S>& str2)
{
assert(str1 == NULL || (CryStackStringT<T, S>::_IsValidString(str1)));
CryStackStringT<T, S> s;
s.reserve(CharTraits<T>::_strlen(str1) + str2.size());
s.append(str1);
s.append(str2);
return s;
}
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::operator=(const CryStackStringT<T, S>& str)
{
_Assign (str.c_str(), str.length());
return *this;
}
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::operator=(const_str str)
{
assert(str == NULL || _IsValidString(str));
_Assign(str, this->_strlen(str));
return *this;
}
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::operator=(const CryStringT<T>& str)
{
_Assign(str.c_str(), str.size());
return *this;
}
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::operator+=(const CryStringT<T>& str)
{
_ConcatenateInPlace(str.c_str(), str.size());
return *this;
}
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::operator+=(const_str str)
{
assert(str == NULL || _IsValidString(str));
_ConcatenateInPlace(str, this->_strlen(str));
return *this;
}
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::operator+=(value_type ch)
{
_ConcatenateInPlace(&ch, 1);
return *this;
}
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::operator+=(const CryStackStringT<T, S>& str)
{
_ConcatenateInPlace(str.m_str, str.length());
return *this;
}
//! find first single character
template <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::find(value_type ch, size_type pos) const
{
if (!(/*pos >= 0 && */ pos <= length()))
{
return (typename CryStackStringT<T, S>::size_type)npos;
}
const_str str = CharTraits<T>::_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 <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::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<T>::_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 <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::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 <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::find_first_of(const CryStackStringT<T, S>& _Str, size_type _Off) const
{
return find_first_of(_Str.m_str, _Off);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::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 <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::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 <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::find_first_not_of(const value_type* _Ptr, size_type _Off) const
{ return find_first_not_of(_Ptr, _Off, this->_strlen(_Ptr)); }
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::find_first_not_of(const CryStackStringT<T, S>& _Str, size_type _Off) const
{ return find_first_not_of(_Str.m_str, _Off); }
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::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 <class T, size_t S>
inline typename CryStackStringT<T, S>::size_type CryStackStringT<T, S>::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 <class T, size_t S>
inline CryStackStringT<T, S> CryStackStringT<T, S>::substr(size_type pos, size_type count) const
{
if (pos >= length())
{
return CryStackStringT<T, S>();
}
if (count == npos)
{
count = length() - pos;
}
if (pos + count > length())
{
count = length() - pos;
}
return CryStackStringT<T, S>(m_str + pos, count);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::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<T>::_move(m_str + nIndex, m_str + nIndex + nCount, nNumToCopy);
m_nLength = length() - nCount;
}
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::insert(size_type nIndex, value_type ch)
{
return insert(nIndex, 1, ch);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::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<T>::_copy(m_str, pstr, nOldLength + 1);
_FreeData(pOldData);
}
CharTraits<T>::_move(m_str + nIndex + nCount, m_str + nIndex, (nNewLength - nIndex));
CharTraits<T>::_set(m_str + nIndex, ch, nCount);
m_nLength = nNewLength;
CRY_STRING_DEBUG(m_str)
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::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<T>::_copy(m_str, pOldStr, (nOldLength + 1));
_FreeData(pOldData);
}
CharTraits<T>::_move(m_str + nIndex + nInsertLength, m_str + nIndex, (nNewLength - nIndex - nInsertLength + 1));
CharTraits<T>::_copy(m_str + nIndex, pstr, nInsertLength);
m_nLength = nNewLength;
m_str[length()] = 0;
}
CRY_STRING_DEBUG(m_str)
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::insert(size_type nIndex, const_str pstr)
{
return insert(nIndex, pstr, this->_strlen(pstr));
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::replace(size_type pos, size_type count, const_str strNew)
{
return replace(pos, count, strNew, this->_strlen(strNew));
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::replace(size_type pos, size_type count, const_str strNew, size_type count2)
{
erase(pos, count);
insert(pos, strNew, count2);
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::replace(size_type pos, size_type count, size_type nNumChars, value_type chNew)
{
erase(pos, count);
insert(pos, nNumChars, chNew);
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::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 <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::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<T>::_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<T>::_copy(m_str, pstr, nPrevLength);
_FreeData(pOldData);
}
strStart = m_str;
strEnd = m_str + length();
while (strStart < strEnd)
{
while ((strTarget = CharTraits<T>::_strstr(strStart, strOld)) != NULL)
{
size_type nBalance = nOldLength - ((size_type)(strTarget - m_str) + nSourceLen);
CharTraits<T>::_move(strTarget + nReplacementLen, strTarget + nSourceLen, nBalance);
CharTraits<T>::_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 <class T, size_t S>
inline void CryStackStringT<T, S>::move(CryStackStringT<T, S>& str)
{
memcpy(this, &str, sizeof(*this));
if (str.m_str == str.m_strBuf)
{
m_str = m_strBuf;
}
}
template <class T, size_t S>
inline void CryStackStringT<T, S>::swap(CryStackStringT<T, S>& _Str)
{
CryStackStringT<T, S> temp;
temp.move(*this);
move(_Str);
_Str.move(temp);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::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 <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::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 <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::MakeLower()
{
_MakeUnique();
for (value_type* s = m_str; *s != 0; s++)
{
*s = this->_ascii_tolower(*s);
}
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::MakeUpper()
{
_MakeUnique();
for (value_type* s = m_str; *s != 0; s++)
{
*s = this->_ascii_toupper(*s);
}
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::Trim()
{
return TrimRight().TrimLeft();
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::Trim(value_type ch)
{
_MakeUnique();
const value_type chset[2] = { ch, 0 };
return TrimRight(chset).TrimLeft(chset);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::Trim(const value_type* sCharSet)
{
_MakeUnique();
return TrimRight(sCharSet).TrimLeft(sCharSet);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::TrimRight(value_type ch)
{
const value_type chset[2] = { ch, 0 };
return TrimRight(chset);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::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<T>::_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 <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::TrimRight()
{
if (length() < 1)
{
return *this;
}
const value_type* last = m_str + length() - 1;
const value_type* str = last;
while ((str != m_str) && (CharTraits<T>::_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 <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::TrimLeft(value_type ch)
{
const value_type chset[2] = { ch, 0 };
return TrimLeft(chset);
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::TrimLeft(const value_type* sCharSet)
{
if (!sCharSet || !(*sCharSet))
{
return *this;
}
const value_type* str = m_str;
while ((*str != 0) && (CharTraits<T>::_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<T>::_move(m_str, m_str + nOff, nNewLength + 1);
m_nLength = nNewLength;
m_str[nNewLength] = 0;
}
return *this;
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S>& CryStackStringT<T, S>::TrimLeft()
{
const value_type* str = m_str;
while ((*str != 0) && (CharTraits<T>::_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<T>::_move(m_str, m_str + nOff, nNewLength + 1);
m_nLength = nNewLength;
m_str[nNewLength] = 0;
}
return *this;
}
template <class T, size_t S>
inline CryStackStringT<T, S> CryStackStringT<T, S>::Right(size_type count) const
{
if (count == npos)
{
return CryStackStringT<T, S>();
}
else if (count > length())
{
return *this;
}
return CryStackStringT<T, S>(m_str + length() - count, count);
}
template <class T, size_t S>
inline CryStackStringT<T, S> CryStackStringT<T, S>::Left(size_type count) const
{
if (count == npos)
{
return CryStackStringT<T, S>();
}
else if (count > length())
{
count = length();
}
return CryStackStringT<T, S>(m_str, count);
}
// strspn equivalent
template <class T, size_t S>
inline CryStackStringT<T, S> CryStackStringT<T, S>::SpanIncluding(const_str charSet) const
{
assert(_IsValidString(charSet));
return Left((size_type)this->_strspn(m_str, charSet));
}
// strcspn equivalent
template <class T, size_t S>
inline CryStackStringT<T, S> CryStackStringT<T, S>::SpanExcluding(const_str charSet) const
{
assert(_IsValidString(charSet));
return Left((size_type)this->_strcspn(m_str, charSet));
}
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T, S> CryStackStringT<T, S>::Tokenize(const_str charSet, int& nStart) const
{
if (nStart < 0)
{
return CryStackStringT<T, S>();
}
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<T, S>();
}
#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<size_t S>
class CryFixedStringT
: public CryStackStringT<char, S>
{
public:
typedef CryStackStringT<char, S> _parentType;
typedef CryFixedStringT<S> _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<size_t AnySize>
_Self& operator=(const CryFixedStringT<AnySize>& str)
{
_parentType::operator = (str);
ASSERT_LEN;
return *this;
}
template<size_t AnySize>
_Self& operator=(const CryStackStringT<char, AnySize>& 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<size_t maxElements, size_t stringSize>
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<stringSize> m_data[NUM_MAX_ELEMENTS];
int32 m_currentAmount;
};
// a template specialization for wchar_t
template<size_t S>
class CryFixedWStringT
: public CryStackStringT<wchar_t, S>
{
public:
typedef CryStackStringT<wchar_t, S> _parentType;
typedef CryFixedWStringT<S> _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<size_t AnySize>
_Self& operator=(const CryFixedWStringT<AnySize>& str)
{
_parentType::operator = (str);
ASSERT_WLEN;
return *this;
}
template<size_t AnySize>
_Self& operator=(const CryStackStringT<wchar_t, AnySize>& str)
{
_parentType::operator = (str);
ASSERT_WLEN;
return *this;
}
};
#undef ASSERT_LEN
#undef ASSERT_WLEN
typedef CryStackStringT<char, 512> stack_string;
// Special string type used for specifying file paths.
typedef CryStackStringT<char, 512> 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<char, 10> str1;
CryStackStringT<char, 10> str2;
CryStackStringT<char, 4> str3;
CryStackStringT<char, 10> str4;
CryStackStringT<char, 5 + 1> str5;
CryStackStringT<wchar_t, 16> wstr1;
CryStackStringT<wchar_t, 255> wstr2;
CryFixedStringT<100> fixedString100;
CryFixedStringT<200> fixedString200;
typedef CryStackStringT<char, 10> 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<char, 10> 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