#define __IRR_STRING_H_INCLUDED__\r
\r
#include "irrTypes.h"\r
-#include "irrAllocator.h"\r
-#include "irrMath.h"\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-#include <wchar.h>\r
+#include <string>\r
+#include <algorithm>\r
+#include <cstdio>\r
+#include <cstring>\r
+#include <cwchar>\r
\r
namespace irr\r
{\r
*/\r
\r
// forward declarations\r
-template <typename T, typename TAlloc = irrAllocator<T> >\r
+template <typename T>\r
class string;\r
static size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize);\r
static size_t wStringToMultibyte(string<c8>& destination, const wchar_t* source, u32 sourceSize);\r
-//inline bool isdigit(s32 c);\r
\r
//! Returns a character converted to lower case\r
static inline u32 locale_lower ( u32 x )\r
}\r
\r
\r
-template <typename T, typename TAlloc>\r
+template <typename T>\r
class string\r
{\r
public:\r
\r
//! Default constructor\r
string()\r
- : array(0), allocated(1), used(1)\r
- {\r
- array = allocator.allocate(1); // new T[1];\r
- array[0] = 0;\r
- }\r
+ {}\r
\r
\r
- //! Constructor\r
- string(const string<T,TAlloc>& other)\r
- : array(0), allocated(0), used(0)\r
+ //! Copy constructor\r
+ string(const string<T>& other)\r
{\r
*this = other;\r
}\r
\r
//! Constructor from other string types\r
- template <class B, class A>\r
- string(const string<B, A>& other)\r
- : array(0), allocated(0), used(0)\r
+ template <class B>\r
+ string(const string<B>& other)\r
{\r
*this = other;\r
}\r
\r
//! Constructs a string from a float\r
explicit string(const double number)\r
- : array(0), allocated(0), used(0)\r
{\r
- c8 tmpbuf[255];\r
- snprintf_irr(tmpbuf, 255, "%0.6f", number);\r
- *this = tmpbuf;\r
+ c8 tmpbuf[32];\r
+ snprintf_irr(tmpbuf, sizeof(tmpbuf), "%0.6f", number);\r
+ str = tmpbuf;\r
}\r
\r
\r
//! Constructs a string from an int\r
explicit string(int number)\r
- : array(0), allocated(0), used(0)\r
{\r
- // store if negative and make positive\r
-\r
- bool negative = false;\r
- if (number < 0)\r
- {\r
- number *= -1;\r
- negative = true;\r
- }\r
-\r
- // temporary buffer for 16 numbers\r
-\r
- c8 tmpbuf[16]={0};\r
- u32 idx = 15;\r
-\r
- // special case '0'\r
-\r
- if (!number)\r
- {\r
- tmpbuf[14] = '0';\r
- *this = &tmpbuf[14];\r
- return;\r
- }\r
-\r
- // add numbers\r
-\r
- while(number && idx)\r
- {\r
- --idx;\r
- tmpbuf[idx] = (c8)('0' + (number % 10));\r
- number /= 10;\r
- }\r
-\r
- // add sign\r
-\r
- if (negative)\r
- {\r
- --idx;\r
- tmpbuf[idx] = '-';\r
- }\r
-\r
- *this = &tmpbuf[idx];\r
+ str = std::to_string(number);\r
}\r
\r
\r
//! Constructs a string from an unsigned int\r
explicit string(unsigned int number)\r
- : array(0), allocated(0), used(0)\r
{\r
- // temporary buffer for 16 numbers\r
-\r
- c8 tmpbuf[16]={0};\r
- u32 idx = 15;\r
-\r
- // special case '0'\r
-\r
- if (!number)\r
- {\r
- tmpbuf[14] = '0';\r
- *this = &tmpbuf[14];\r
- return;\r
- }\r
-\r
- // add numbers\r
-\r
- while(number && idx)\r
- {\r
- --idx;\r
- tmpbuf[idx] = (c8)('0' + (number % 10));\r
- number /= 10;\r
- }\r
-\r
- *this = &tmpbuf[idx];\r
+ str = std::to_string(number);\r
}\r
\r
\r
//! Constructs a string from a long\r
explicit string(long number)\r
- : array(0), allocated(0), used(0)\r
{\r
- // store if negative and make positive\r
-\r
- bool negative = false;\r
- if (number < 0)\r
- {\r
- number *= -1;\r
- negative = true;\r
- }\r
-\r
- // temporary buffer for 16 numbers\r
-\r
- c8 tmpbuf[16]={0};\r
- u32 idx = 15;\r
-\r
- // special case '0'\r
-\r
- if (!number)\r
- {\r
- tmpbuf[14] = '0';\r
- *this = &tmpbuf[14];\r
- return;\r
- }\r
-\r
- // add numbers\r
-\r
- while(number && idx)\r
- {\r
- --idx;\r
- tmpbuf[idx] = (c8)('0' + (number % 10));\r
- number /= 10;\r
- }\r
-\r
- // add sign\r
-\r
- if (negative)\r
- {\r
- --idx;\r
- tmpbuf[idx] = '-';\r
- }\r
-\r
- *this = &tmpbuf[idx];\r
+ str = std::to_string(number);\r
}\r
\r
\r
//! Constructs a string from an unsigned long\r
explicit string(unsigned long number)\r
- : array(0), allocated(0), used(0)\r
{\r
- // temporary buffer for 16 numbers\r
-\r
- c8 tmpbuf[16]={0};\r
- u32 idx = 15;\r
-\r
- // special case '0'\r
-\r
- if (!number)\r
- {\r
- tmpbuf[14] = '0';\r
- *this = &tmpbuf[14];\r
- return;\r
- }\r
-\r
- // add numbers\r
-\r
- while(number && idx)\r
- {\r
- --idx;\r
- tmpbuf[idx] = (c8)('0' + (number % 10));\r
- number /= 10;\r
- }\r
-\r
- *this = &tmpbuf[idx];\r
+ str = std::to_string(number);\r
}\r
\r
\r
//! Constructor for copying a string from a pointer with a given length\r
template <class B>\r
string(const B* const c, u32 length)\r
- : array(0), allocated(0), used(0)\r
{\r
if (!c)\r
- {\r
- // correctly init the string to an empty one\r
- *this="";\r
return;\r
- }\r
-\r
- allocated = used = length+1;\r
- array = allocator.allocate(used); // new T[used];\r
\r
+ str.resize(length);\r
for (u32 l = 0; l<length; ++l)\r
- array[l] = (T)c[l];\r
-\r
- array[length] = 0;\r
+ str[l] = (T)c[l];\r
}\r
\r
\r
//! Constructor for Unicode and ASCII strings\r
template <class B>\r
string(const B* const c)\r
- : array(0), allocated(0), used(0)\r
{\r
*this = c;\r
}\r
\r
//! Destructor\r
~string()\r
- {\r
- allocator.deallocate(array); // delete [] array;\r
- }\r
+ {}\r
\r
\r
//! Assignment operator\r
- string<T,TAlloc>& operator=(const string<T,TAlloc>& other)\r
+ string<T>& operator=(const string<T>& other)\r
{\r
if (this == &other)\r
return *this;\r
\r
- used = other.size()+1;\r
- if (used>allocated)\r
- {\r
- allocator.deallocate(array); // delete [] array;\r
- allocated = used;\r
- array = allocator.allocate(used); //new T[used];\r
- }\r
-\r
- const T* p = other.c_str();\r
- for (u32 i=0; i<used; ++i, ++p)\r
- array[i] = *p;\r
-\r
+ str = other.str;\r
return *this;\r
}\r
\r
//! Assignment operator for other string types\r
- template <class B, class A>\r
- string<T,TAlloc>& operator=(const string<B,A>& other)\r
+ template <class B>\r
+ string<T>& operator=(const string<B>& other)\r
{\r
*this = other.c_str();\r
return *this;\r
\r
//! Assignment operator for strings, ASCII and Unicode\r
template <class B>\r
- string<T,TAlloc>& operator=(const B* const c)\r
+ string<T>& operator=(const B* const c)\r
{\r
if (!c)\r
{\r
- if (!array)\r
- {\r
- array = allocator.allocate(1); //new T[1];\r
- allocated = 1;\r
- }\r
- used = 1;\r
- array[0] = 0x0;\r
+ clear();\r
return *this;\r
}\r
\r
- if ((void*)c == (void*)array)\r
- return *this;\r
-\r
- u32 len = 0;\r
- const B* p = c;\r
- do\r
- {\r
- ++len;\r
- } while(*p++);\r
-\r
- // we'll keep the old string for a while, because the new\r
- // string could be a part of the current string.\r
- T* oldArray = array;\r
-\r
- used = len;\r
- if (used>allocated)\r
- {\r
- allocated = used;\r
- array = allocator.allocate(used); //new T[used];\r
- }\r
+ // no longer allowed!\r
+ _IRR_DEBUG_BREAK_IF((void*)c == (void*)c_str());\r
\r
+ u32 len = calclen(c);\r
+ str.resize(len);\r
for (u32 l = 0; l<len; ++l)\r
- array[l] = (T)c[l];\r
-\r
- if (oldArray != array)\r
- allocator.deallocate(oldArray); // delete [] oldArray;\r
+ str[l] = (T)c[l];\r
\r
return *this;\r
}\r
\r
\r
//! Append operator for other strings\r
- string<T,TAlloc> operator+(const string<T,TAlloc>& other) const\r
+ string<T> operator+(const string<T>& other) const\r
{\r
- string<T,TAlloc> str(*this);\r
- str.append(other);\r
+ string<T> tmp(*this);\r
+ tmp.append(other);\r
\r
- return str;\r
+ return tmp;\r
}\r
\r
\r
//! Append operator for strings, ASCII and Unicode\r
template <class B>\r
- string<T,TAlloc> operator+(const B* const c) const\r
+ string<T> operator+(const B* const c) const\r
{\r
- string<T,TAlloc> str(*this);\r
- str.append(c);\r
+ string<T> tmp(*this);\r
+ tmp.append(c);\r
\r
- return str;\r
+ return tmp;\r
}\r
\r
\r
//! Direct access operator\r
T& operator [](const u32 index)\r
{\r
- _IRR_DEBUG_BREAK_IF(index>=used) // bad index\r
- return array[index];\r
+ return str[index];\r
}\r
\r
\r
//! Direct access operator\r
const T& operator [](const u32 index) const\r
{\r
- _IRR_DEBUG_BREAK_IF(index>=used) // bad index\r
- return array[index];\r
+ return str[index];\r
}\r
\r
\r
//! Equality operator\r
- bool operator==(const T* const str) const\r
+ bool operator==(const T* const other) const\r
{\r
- if (!str)\r
+ if (!other)\r
return false;\r
-\r
- u32 i;\r
- for (i=0; array[i] && str[i]; ++i)\r
- if (array[i] != str[i])\r
- return false;\r
-\r
- return (!array[i] && !str[i]);\r
+ return !cmp(c_str(), other);\r
}\r
\r
\r
//! Equality operator\r
- bool operator==(const string<T,TAlloc>& other) const\r
+ bool operator==(const string<T>& other) const\r
{\r
- for (u32 i=0; array[i] && other.array[i]; ++i)\r
- if (array[i] != other.array[i])\r
- return false;\r
-\r
- return used == other.used;\r
+ return str == other.str;\r
}\r
\r
\r
//! Is smaller comparator\r
- bool operator<(const string<T,TAlloc>& other) const\r
+ bool operator<(const string<T>& other) const\r
{\r
- for (u32 i=0; array[i] && other.array[i]; ++i)\r
- {\r
- const s32 diff = array[i] - other.array[i];\r
- if (diff)\r
- return (diff < 0);\r
- }\r
-\r
- return (used < other.used);\r
+ return str < other.str;\r
}\r
\r
\r
//! Inequality operator\r
- bool operator!=(const T* const str) const\r
+ bool operator!=(const T* const other) const\r
{\r
- return !(*this == str);\r
+ return !(*this == other);\r
}\r
\r
\r
//! Inequality operator\r
- bool operator!=(const string<T,TAlloc>& other) const\r
+ bool operator!=(const string<T>& other) const\r
{\r
return !(*this == other);\r
}\r
the trailing NUL. */\r
u32 size() const\r
{\r
- return used-1;\r
+ return str.size();\r
}\r
\r
//! Informs if the string is empty or not.\r
//! \return True if the string is empty, false if not.\r
bool empty() const\r
{\r
- return (size() == 0);\r
+ return str.empty();\r
}\r
\r
void clear(bool releaseMemory=true)\r
{\r
- if ( releaseMemory )\r
- {\r
- reallocate(1);\r
+ if (releaseMemory) {\r
+ stl_type empty;\r
+ std::swap(str, empty);\r
+ } else {\r
+ str.clear();\r
}\r
- array[0] = 0;\r
- used = 1;\r
}\r
\r
//! Returns character string\r
/** \return pointer to C-style NUL terminated string. */\r
const T* c_str() const\r
{\r
- return array;\r
+ return str.c_str();\r
}\r
\r
\r
//! Makes the string lower case.\r
- string<T,TAlloc>& make_lower()\r
+ string<T>& make_lower()\r
{\r
- for (u32 i=0; array[i]; ++i)\r
- array[i] = locale_lower ( array[i] );\r
+ std::transform(str.begin(), str.end(), str.begin(), [](const T& c) {\r
+ return locale_lower(c);\r
+ });\r
return *this;\r
}\r
\r
\r
//! Makes the string upper case.\r
- string<T,TAlloc>& make_upper()\r
+ string<T>& make_upper()\r
{\r
- for (u32 i=0; array[i]; ++i)\r
- array[i] = locale_upper ( array[i] );\r
+ std::transform(str.begin(), str.end(), str.begin(), [](const T& c) {\r
+ return locale_upper(c);\r
+ });\r
return *this;\r
}\r
\r
//! Compares the strings ignoring case.\r
/** \param other: Other string to compare.\r
\return True if the strings are equal ignoring case. */\r
- bool equals_ignore_case(const string<T,TAlloc>& other) const\r
+ bool equals_ignore_case(const string<T>& other) const\r
{\r
+ const T* array = c_str();\r
for(u32 i=0; array[i] && other[i]; ++i)\r
- if (locale_lower( array[i]) != locale_lower(other[i]))\r
+ if (locale_lower(array[i]) != locale_lower(other[i]))\r
return false;\r
\r
- return used == other.used;\r
+ return size() == other.size();\r
}\r
\r
//! Compares the strings ignoring case.\r
/** \param other: Other string to compare.\r
\param sourcePos: where to start to compare in the string\r
\return True if the strings are equal ignoring case. */\r
- bool equals_substring_ignore_case(const string<T,TAlloc>&other, const s32 sourcePos = 0 ) const\r
+ bool equals_substring_ignore_case(const string<T>&other, const u32 sourcePos = 0 ) const\r
{\r
- if ( (u32) sourcePos >= used )\r
+ if ( sourcePos >= size() + 1 )\r
return false;\r
\r
+ const T* array = c_str();\r
u32 i;\r
- for( i=0; array[sourcePos + i] && other[i]; ++i)\r
- if (locale_lower( array[sourcePos + i]) != locale_lower(other[i]))\r
+ for(i=0; array[sourcePos + i] && other[i]; ++i)\r
+ if (locale_lower(array[sourcePos + i]) != locale_lower(other[i]))\r
return false;\r
\r
return array[sourcePos + i] == 0 && other[i] == 0;\r
//! Compares the strings ignoring case.\r
/** \param other: Other string to compare.\r
\return True if this string is smaller ignoring case. */\r
- bool lower_ignore_case(const string<T,TAlloc>& other) const\r
+ bool lower_ignore_case(const string<T>& other) const\r
{\r
- for(u32 i=0; array[i] && other.array[i]; ++i)\r
+ const T* array = c_str();\r
+ for(u32 i=0; array[i] && other[i]; ++i)\r
{\r
- s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] );\r
+ s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other[i] );\r
if ( diff )\r
return diff < 0;\r
}\r
\r
- return used < other.used;\r
+ return size() < other.size();\r
}\r
\r
\r
/** \param other Other string to compare.\r
\param n Number of characters to compare\r
\return True if the n first characters of both strings are equal. */\r
- bool equalsn(const string<T,TAlloc>& other, u32 n) const\r
+ bool equalsn(const string<T>& other, u32 n) const\r
{\r
+ const T* array = c_str();\r
u32 i;\r
for(i=0; i < n && array[i] && other[i]; ++i)\r
if (array[i] != other[i])\r
\r
// if one (or both) of the strings was smaller then they\r
// are only equal if they have the same length\r
- return (i == n) || (used == other.used);\r
+ return (i == n) || (size() == other.size());\r
}\r
\r
\r
/** \param str Other string to compare.\r
\param n Number of characters to compare\r
\return True if the n first characters of both strings are equal. */\r
- bool equalsn(const T* const str, u32 n) const\r
+ bool equalsn(const T* const other, u32 n) const\r
{\r
- if (!str)\r
+ if (!other)\r
return false;\r
+ const T* array = c_str();\r
u32 i;\r
- for(i=0; i < n && array[i] && str[i]; ++i)\r
- if (array[i] != str[i])\r
+ for(i=0; i < n && array[i] && other[i]; ++i)\r
+ if (array[i] != other[i])\r
return false;\r
\r
// if one (or both) of the strings was smaller then they\r
// are only equal if they have the same length\r
- return (i == n) || (array[i] == 0 && str[i] == 0);\r
+ return (i == n) || (array[i] == 0 && other[i] == 0);\r
}\r
\r
\r
//! Appends a character to this string\r
/** \param character: Character to append. */\r
- string<T,TAlloc>& append(T character)\r
+ string<T>& append(T character)\r
{\r
- if (used + 1 > allocated)\r
- reallocate(used + 1);\r
-\r
- ++used;\r
-\r
- array[used-2] = character;\r
- array[used-1] = 0;\r
-\r
+ str.append(1, character);\r
return *this;\r
}\r
\r
//! Appends a char string to this string\r
/** \param other: Char string to append. */\r
/** \param length: The length of the string to append. */\r
- string<T,TAlloc>& append(const T* const other, u32 length=0xffffffff)\r
+ string<T>& append(const T* const other, u32 length=0xffffffff)\r
{\r
if (!other)\r
return *this;\r
\r
- u32 len = 0;\r
- const T* p = other;\r
- while(*p)\r
- {\r
- ++len;\r
- ++p;\r
- }\r
+ u32 len = calclen(other);\r
if (len > length)\r
len = length;\r
\r
- if (used + len > allocated)\r
- reallocate(used + len);\r
-\r
- --used;\r
- ++len;\r
-\r
- for (u32 l=0; l<len; ++l)\r
- array[l+used] = *(other+l);\r
-\r
- used += len;\r
- array[used-1] = 0;\r
-\r
+ str.append(other, len);\r
return *this;\r
}\r
\r
\r
//! Appends a string to this string\r
/** \param other: String to append. */\r
- string<T,TAlloc>& append(const string<T,TAlloc>& other)\r
+ string<T>& append(const string<T>& other)\r
{\r
- if (other.size() == 0)\r
- return *this;\r
-\r
- --used;\r
- const u32 len = other.size()+1;\r
-\r
- if (used + len > allocated)\r
- reallocate(used + len);\r
-\r
- for (u32 l=0; l<len; ++l)\r
- array[used+l] = other[l];\r
-\r
- used += len;\r
-\r
+ str.append(other.str);\r
return *this;\r
}\r
\r
//! Appends a string of the length l to this string.\r
/** \param other: other String to append to this string.\r
\param length: How much characters of the other string to add to this one. */\r
- string<T,TAlloc>& append(const string<T,TAlloc>& other, u32 length)\r
+ string<T>& append(const string<T>& other, u32 length)\r
{\r
- if (other.size() == 0)\r
- return *this;\r
-\r
if (other.size() < length)\r
- {\r
append(other);\r
- return *this;\r
- }\r
-\r
- if (used + length > allocated)\r
- reallocate(used + length);\r
-\r
- --used;\r
-\r
- for (u32 l=0; l<length; ++l)\r
- array[l+used] = other[l];\r
- used += length;\r
-\r
- // ensure proper termination\r
- array[used]=0;\r
- ++used;\r
-\r
+ else\r
+ str.append(other.c_str(), length);\r
return *this;\r
}\r
\r
//\param pos Insert the characters before this index\r
//\param s String to insert. Must be at least of size n\r
//\param n Number of characters from string s to use.\r
- string<T,TAlloc>& insert(u32 pos, const char* s, u32 n)\r
+ string<T>& insert(u32 pos, const T* s, u32 n)\r
{\r
- if ( pos < used )\r
+ if ( pos < size()+1 )\r
{\r
- reserve(used+n);\r
-\r
- // move stuff behind insert point\r
- const u32 end = used+n-1;\r
- for (u32 i=0; i<used-pos; ++i)\r
- {\r
- array[end-i] = array[end-(i+n)];\r
- }\r
- used += n;\r
-\r
- for (u32 i=0; i<n; ++i)\r
- {\r
- array[pos+i] = s[i];\r
- }\r
+ str.insert(pos, s, n);\r
}\r
\r
return *this;\r
}\r
\r
//! Reserves some memory.\r
- /** \param count: Amount of characters to reserve. */\r
+ /** \param count: Amount of characters to reserve, including\r
+ the trailing NUL. */\r
void reserve(u32 count)\r
{\r
- if (count < allocated)\r
+ if (count == 0)\r
return;\r
-\r
- reallocate(count);\r
+ str.reserve(count - 1);\r
}\r
\r
\r
or -1 if not found. */\r
s32 findFirst(T c) const\r
{\r
- for (u32 i=0; i<used-1; ++i)\r
- if (array[i] == c)\r
- return i;\r
-\r
- return -1;\r
+ auto r = str.find(c);\r
+ return pos_from_stl(r);\r
}\r
\r
//! finds first occurrence of a character of a list in string\r
if (!c || !count)\r
return -1;\r
\r
- for (u32 i=0; i<used-1; ++i)\r
- for (u32 j=0; j<count; ++j)\r
- if (array[i] == c[j])\r
- return i;\r
-\r
- return -1;\r
+ auto r = str.find_first_of(c, 0, count);\r
+ return pos_from_stl(r);\r
}\r
\r
\r
this should be strlen(c)\r
\return Position where the character has been found,\r
or -1 if not found. */\r
- template <class B>\r
- s32 findFirstCharNotInList(const B* const c, u32 count=1) const\r
+ s32 findFirstCharNotInList(const T* const c, u32 count=1) const\r
{\r
if (!c || !count)\r
return -1;\r
\r
- for (u32 i=0; i<used-1; ++i)\r
- {\r
- u32 j;\r
- for (j=0; j<count; ++j)\r
- if (array[i] == c[j])\r
- break;\r
-\r
- if (j==count)\r
- return i;\r
- }\r
-\r
- return -1;\r
+ auto r = str.find_first_not_of(c, 0, count);\r
+ return pos_from_stl(r);\r
}\r
\r
//! Finds last position of a character not in a given list.\r
this should be strlen(c)\r
\return Position where the character has been found,\r
or -1 if not found. */\r
- template <class B>\r
- s32 findLastCharNotInList(const B* const c, u32 count=1) const\r
+ s32 findLastCharNotInList(const T* const c, u32 count=1) const\r
{\r
if (!c || !count)\r
return -1;\r
\r
- for (s32 i=(s32)(used-2); i>=0; --i)\r
- {\r
- u32 j;\r
- for (j=0; j<count; ++j)\r
- if (array[i] == c[j])\r
- break;\r
-\r
- if (j==count)\r
- return i;\r
- }\r
-\r
- return -1;\r
+ auto r = str.find_last_not_of(c, npos, count);\r
+ return pos_from_stl(r);\r
}\r
\r
//! finds next occurrence of character in string\r
or -1 if not found. */\r
s32 findNext(T c, u32 startPos) const\r
{\r
- for (u32 i=startPos; i<used-1; ++i)\r
- if (array[i] == c)\r
- return i;\r
-\r
- return -1;\r
+ auto r = str.find(c, startPos);\r
+ return pos_from_stl(r);\r
}\r
\r
\r
or -1 if not found. */\r
s32 findLast(T c, s32 start = -1) const\r
{\r
- start = core::clamp ( start < 0 ? (s32)(used) - 2 : start, 0, (s32)(used) - 2 );\r
- for (s32 i=start; i>=0; --i)\r
- if (array[i] == c)\r
- return i;\r
-\r
- return -1;\r
+ auto r = str.rfind(c, pos_to_stl(start));\r
+ return pos_from_stl(r);\r
}\r
\r
//! finds last occurrence of a character of a list in string\r
if (!c || !count)\r
return -1;\r
\r
- for (s32 i=(s32)used-2; i>=0; --i)\r
- for (u32 j=0; j<count; ++j)\r
- if (array[i] == c[j])\r
- return i;\r
-\r
- return -1;\r
+ auto r = str.find_last_of(c, npos, count);\r
+ return pos_from_stl(r);\r
}\r
\r
\r
\param start: Start position of the search\r
\return Positions where the string has been found,\r
or -1 if not found. */\r
- template <class B>\r
- s32 find(const B* const str, const u32 start = 0) const\r
+ s32 find(const T* const other, const u32 start = 0) const\r
{\r
- if (str && *str)\r
+ if (other && *other)\r
{\r
- u32 len = 0;\r
-\r
- while (str[len])\r
- ++len;\r
-\r
- if (len > used-1)\r
- return -1;\r
-\r
- for (u32 i=start; i<used-len; ++i)\r
- {\r
- u32 j=0;\r
-\r
- while(str[j] && array[i+j] == str[j])\r
- ++j;\r
-\r
- if (!str[j])\r
- return i;\r
- }\r
+ auto r = str.find(other, start);\r
+ return pos_from_stl(r);\r
}\r
\r
return -1;\r
// or no proper substring length\r
if ((length <= 0) || (begin>=size()))\r
return string<T>("");\r
- // clamp length to maximal value\r
- if ((length+begin) > size())\r
- length = size()-begin;\r
-\r
- // accounting for null terminator.\r
- s32 substrAllocLength = length + 1;\r
- string<T> o;\r
- o.reserve(substrAllocLength);\r
-\r
- if ( !make_lower )\r
- {\r
- for (s32 i=0; i<length; ++i)\r
- o.array[i] = array[i+begin];\r
- }\r
- else\r
- {\r
- for (s32 i=0; i<length; ++i)\r
- o.array[i] = locale_lower ( array[i+begin] );\r
- }\r
-\r
- o.array[substrAllocLength - 1] = 0;\r
- o.used = length + 1;\r
\r
+ string<T> o = str.substr(begin, length);\r
+ if (make_lower)\r
+ o.make_lower();\r
return o;\r
}\r
\r
\r
//! Appends a character to this string\r
/** \param c Character to append. */\r
- string<T,TAlloc>& operator += (T c)\r
+ string<T>& operator += (T c)\r
{\r
append(c);\r
return *this;\r
\r
//! Appends a char string to this string\r
/** \param c Char string to append. */\r
- string<T,TAlloc>& operator += (const T* const c)\r
+ string<T>& operator += (const T* const c)\r
{\r
append(c);\r
return *this;\r
\r
//! Appends a string to this string\r
/** \param other String to append. */\r
- string<T,TAlloc>& operator += (const string<T,TAlloc>& other)\r
+ string<T>& operator += (const string<T>& other)\r
{\r
append(other);\r
return *this;\r
\r
//! Appends a string representation of a number to this string\r
/** \param i Number to append. */\r
- string<T,TAlloc>& operator += (const int i)\r
+ string<T>& operator += (const int i)\r
{\r
- append(string<T,TAlloc>(i));\r
+ append(string<T>(i));\r
return *this;\r
}\r
\r
\r
//! Appends a string representation of a number to this string\r
/** \param i Number to append. */\r
- string<T,TAlloc>& operator += (const unsigned int i)\r
+ string<T>& operator += (const unsigned int i)\r
{\r
- append(string<T,TAlloc>(i));\r
+ append(string<T>(i));\r
return *this;\r
}\r
\r
\r
//! Appends a string representation of a number to this string\r
/** \param i Number to append. */\r
- string<T,TAlloc>& operator += (const long i)\r
+ string<T>& operator += (const long i)\r
{\r
- append(string<T,TAlloc>(i));\r
+ append(string<T>(i));\r
return *this;\r
}\r
\r
\r
//! Appends a string representation of a number to this string\r
/** \param i Number to append. */\r
- string<T,TAlloc>& operator += (const unsigned long i)\r
+ string<T>& operator += (const unsigned long i)\r
{\r
- append(string<T,TAlloc>(i));\r
+ append(string<T>(i));\r
return *this;\r
}\r
\r
\r
//! Appends a string representation of a number to this string\r
/** \param i Number to append. */\r
- string<T,TAlloc>& operator += (const double i)\r
+ string<T>& operator += (const double i)\r
{\r
- append(string<T,TAlloc>(i));\r
+ append(string<T>(i));\r
return *this;\r
}\r
\r
\r
//! Appends a string representation of a number to this string\r
/** \param i Number to append. */\r
- string<T,TAlloc>& operator += (const float i)\r
+ string<T>& operator += (const float i)\r
{\r
- append(string<T,TAlloc>(i));\r
+ append(string<T>(i));\r
return *this;\r
}\r
\r
//! Replaces all characters of a special type with another one\r
/** \param toReplace Character to replace.\r
\param replaceWith Character replacing the old one. */\r
- string<T,TAlloc>& replace(T toReplace, T replaceWith)\r
+ string<T>& replace(T toReplace, T replaceWith)\r
{\r
- for (u32 i=0; i<used-1; ++i)\r
- if (array[i] == toReplace)\r
- array[i] = replaceWith;\r
+ std::replace(str.begin(), str.end(), toReplace, replaceWith);\r
return *this;\r
}\r
\r
//! Replaces all instances of a string with another one.\r
/** \param toReplace The string to replace.\r
\param replaceWith The string replacing the old one. */\r
- string<T,TAlloc>& replace(const string<T,TAlloc>& toReplace, const string<T,TAlloc>& replaceWith)\r
+ string<T>& replace(const string<T>& toReplace, const string<T>& replaceWith)\r
{\r
- if (toReplace.size() == 0)\r
- return *this;\r
-\r
- const T* other = toReplace.c_str();\r
- const T* replace = replaceWith.c_str();\r
- const u32 other_size = toReplace.size();\r
- const u32 replace_size = replaceWith.size();\r
-\r
- // Determine the delta. The algorithm will change depending on the delta.\r
- s32 delta = replace_size - other_size;\r
-\r
- // A character for character replace. The string will not shrink or grow.\r
- if (delta == 0)\r
- {\r
- s32 pos = 0;\r
- while ((pos = find(other, pos)) != -1)\r
- {\r
- for (u32 i = 0; i < replace_size; ++i)\r
- array[pos + i] = replace[i];\r
- ++pos;\r
- }\r
- return *this;\r
- }\r
-\r
- // We are going to be removing some characters. The string will shrink.\r
- if (delta < 0)\r
- {\r
- u32 i = 0;\r
- for (u32 pos = 0; pos < used; ++i, ++pos)\r
- {\r
- // Is this potentially a match?\r
- if (array[pos] == *other)\r
- {\r
- // Check to see if we have a match.\r
- u32 j;\r
- for (j = 0; j < other_size; ++j)\r
- {\r
- if (array[pos + j] != other[j])\r
- break;\r
- }\r
-\r
- // If we have a match, replace characters.\r
- if (j == other_size)\r
- {\r
- for (j = 0; j < replace_size; ++j)\r
- array[i + j] = replace[j];\r
- i += replace_size - 1;\r
- pos += other_size - 1;\r
- continue;\r
- }\r
- }\r
-\r
- // No match found, just copy characters.\r
- array[i] = array[pos];\r
- }\r
- array[i-1] = 0;\r
- used = i;\r
-\r
- return *this;\r
- }\r
-\r
- // We are going to be adding characters, so the string size will increase.\r
- // Count the number of times toReplace exists in the string so we can allocate the new size.\r
- u32 find_count = 0;\r
- s32 pos = 0;\r
- while ((pos = find(other, pos)) != -1)\r
- {\r
- ++find_count;\r
- ++pos;\r
- }\r
-\r
- // Re-allocate the string now, if needed.\r
- u32 len = delta * find_count;\r
- if (used + len > allocated)\r
- reallocate(used + len);\r
-\r
- // Start replacing.\r
- pos = 0;\r
- while ((pos = find(other, pos)) != -1)\r
- {\r
- T* start = array + pos + other_size - 1;\r
- T* ptr = array + used - 1;\r
- T* end = array + delta + used -1;\r
-\r
- // Shift characters to make room for the string.\r
- while (ptr != start)\r
- {\r
- *end = *ptr;\r
- --ptr;\r
- --end;\r
- }\r
-\r
- // Add the new string now.\r
- for (u32 i = 0; i < replace_size; ++i)\r
- array[pos + i] = replace[i];\r
-\r
- pos += replace_size;\r
- used += delta;\r
- }\r
+ size_type pos = 0;\r
+ while ((pos = str.find(toReplace.str, pos)) != npos) {\r
+ str.replace(pos, toReplace.size(), replaceWith.str);\r
+ pos += replaceWith.size();\r
+ }\r
\r
return *this;\r
}\r
\r
\r
- //! Removes characters from a string.\r
+ //! Removes a character from a string.\r
/** \param c: Character to remove. */\r
- string<T,TAlloc>& remove(T c)\r
+ string<T>& remove(T c)\r
{\r
- u32 pos = 0;\r
- u32 found = 0;\r
- for (u32 i=0; i<used-1; ++i)\r
- {\r
- if (array[i] == c)\r
- {\r
- ++found;\r
- continue;\r
- }\r
-\r
- array[pos++] = array[i];\r
- }\r
- used -= found;\r
- array[used-1] = 0;\r
+ str.erase(std::remove(str.begin(), str.end(), c), str.end());\r
return *this;\r
}\r
\r
\r
//! Removes a string from the string.\r
/** \param toRemove: String to remove. */\r
- string<T,TAlloc>& remove(const string<T,TAlloc>& toRemove)\r
+ string<T>& remove(const string<T>& toRemove)\r
{\r
u32 size = toRemove.size();\r
if ( size == 0 )\r
return *this;\r
u32 pos = 0;\r
u32 found = 0;\r
- for (u32 i=0; i<used-1; ++i)\r
+ for (u32 i=0; i<str.size(); ++i)\r
{\r
u32 j = 0;\r
while (j < size)\r
{\r
- if (array[i + j] != toRemove[j])\r
+ if (str[i + j] != toRemove[j])\r
break;\r
++j;\r
}\r
continue;\r
}\r
\r
- array[pos++] = array[i];\r
+ str[pos++] = str[i];\r
}\r
- used -= found;\r
- array[used-1] = 0;\r
+ str.resize(str.size() - found);\r
return *this;\r
}\r
\r
\r
//! Removes characters from a string.\r
/** \param characters: Characters to remove. */\r
- string<T,TAlloc>& removeChars(const string<T,TAlloc> & characters)\r
+ string<T>& removeChars(const string<T> & characters)\r
{\r
if (characters.size() == 0)\r
return *this;\r
\r
- u32 pos = 0;\r
- u32 found = 0;\r
- for (u32 i=0; i<used-1; ++i)\r
- {\r
- // Don't use characters.findFirst as it finds the \0,\r
- // causing used to become incorrect.\r
- bool docontinue = false;\r
- for (u32 j=0; j<characters.size(); ++j)\r
- {\r
- if (characters[j] == array[i])\r
- {\r
- ++found;\r
- docontinue = true;\r
- break;\r
- }\r
- }\r
- if (docontinue)\r
- continue;\r
-\r
- array[pos++] = array[i];\r
- }\r
- used -= found;\r
- array[used-1] = 0;\r
-\r
+ for (u32 i = 0; i < characters.size(); i++)\r
+ remove(characters[i]);\r
return *this;\r
}\r
\r
//! Trims the string.\r
/** Removes the specified characters (by default, Latin-1 whitespace)\r
from the beginning and the end of the string. */\r
- string<T,TAlloc>& trim(const string<T,TAlloc> & whitespace = " \t\n\r")\r
+ string<T>& trim(const string<T> & whitespace = " \t\n\r")\r
{\r
// find start and end of the substring without the specified characters\r
- const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);\r
+ const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.size());\r
if (begin == -1)\r
return (*this="");\r
\r
- const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);\r
+ const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.size());\r
\r
return (*this = subString(begin, (end +1) - begin));\r
}\r
\r
-#if 0\r
- //! Erase 0's at the end when a string ends with a floating point number\r
- /** After generating strings from floats we often end up with strings\r
- ending up with lots of zeros which don't add any value. Erase 'em all.\r
- Examples: "0.100000" becomes "0.1"\r
- "10.000000" becomes "10"\r
- "foo 3.140000" becomes "foo 3.14"\r
- "no_num.000" stays "no_num.000"\r
- "1." stays "1."\r
- */\r
- string<T,TAlloc>& eraseTrailingFloatZeros(char decimalPoint='.')\r
- {\r
- s32 i=findLastCharNotInList("0", 1);\r
- if ( i > 0 && (u32)i < used-2 ) // non 0 must be found and not last char (also used is at least 2 when i > 0)\r
- {\r
- u32 eraseStart=i+1;\r
- u32 dot=0;\r
- if( core::isdigit(array[i]) )\r
- {\r
- while( --i>0 && core::isdigit(array[i]) );\r
- if ( array[i] == decimalPoint )\r
- dot = i;\r
- }\r
- else if ( array[i] == decimalPoint )\r
- {\r
- dot = i;\r
- eraseStart = i;\r
- }\r
- if ( dot > 0 && core::isdigit(array[dot-1]) )\r
- {\r
- array[eraseStart] = 0;\r
- used = eraseStart+1;\r
- }\r
- }\r
- return *this;\r
- }\r
-#endif\r
-\r
//! Erases a character from the string.\r
/** May be slow, because all elements\r
following after the erased element have to be copied.\r
\param index: Index of element to be erased. */\r
- string<T,TAlloc>& erase(u32 index)\r
+ string<T>& erase(u32 index)\r
{\r
- _IRR_DEBUG_BREAK_IF(index>=used) // access violation\r
-\r
- for (u32 i=index+1; i<used; ++i)\r
- array[i-1] = array[i];\r
-\r
- --used;\r
+ str.erase(str.begin() + index);\r
return *this;\r
}\r
\r
//! verify the existing string.\r
- string<T,TAlloc>& validate()\r
+ string<T>& validate()\r
{\r
- // terminate on existing null\r
- for (u32 i=0; i<allocated; ++i)\r
- {\r
- if (array[i] == 0)\r
- {\r
- used = i + 1;\r
- return *this;\r
- }\r
- }\r
-\r
- // terminate\r
- if ( allocated > 0 )\r
- {\r
- used = allocated;\r
- array[used-1] = 0;\r
- }\r
- else\r
- {\r
- used = 0;\r
- }\r
+ // truncate to existing null\r
+ u32 len = calclen(c_str());\r
+ if (len != size())\r
+ str.resize(len);\r
\r
return *this;\r
}\r
//! gets the last char of a string or null\r
T lastChar() const\r
{\r
- return used > 1 ? array[used-2] : 0;\r
+ return !str.empty() ? str.back() : 0;\r
}\r
\r
//! Split string into parts (tokens).\r
const u32 oldSize=ret.size();\r
\r
u32 tokenStartIdx = 0;\r
- for (u32 i=0; i<used; ++i)\r
+ for (u32 i=0; i<size()+1; ++i)\r
{\r
for (u32 j=0; j<countDelimiters; ++j)\r
{\r
- if (array[i] == delimiter[j])\r
+ if (str[i] == delimiter[j])\r
{\r
if (i - tokenStartIdx > 0)\r
- ret.push_back(string<T,TAlloc>(&array[tokenStartIdx], i - tokenStartIdx));\r
+ ret.push_back(string<T>(&str[tokenStartIdx], i - tokenStartIdx));\r
else if ( !ignoreEmptyTokens )\r
- ret.push_back(string<T,TAlloc>());\r
+ ret.push_back(string<T>());\r
if ( keepSeparators )\r
{\r
- ret.push_back(string<T,TAlloc>(&array[i], 1));\r
+ ret.push_back(string<T>(&str[i], 1));\r
}\r
\r
tokenStartIdx = i+1;\r
}\r
}\r
}\r
- if ((used - 1) > tokenStartIdx)\r
- ret.push_back(string<T,TAlloc>(&array[tokenStartIdx], (used - 1) - tokenStartIdx));\r
- else if ( !ignoreEmptyTokens )\r
- ret.push_back(string<T,TAlloc>());\r
+ if (size() > tokenStartIdx)\r
+ ret.push_back(string<T>(&str[tokenStartIdx], size() - tokenStartIdx));\r
+ else if (!ignoreEmptyTokens)\r
+ ret.push_back(string<T>());\r
\r
return ret.size()-oldSize;\r
}\r
\r
private:\r
\r
- //! Reallocate the array, make it bigger or smaller\r
- void reallocate(u32 new_size)\r
- {\r
- T* old_array = array;\r
-\r
- array = allocator.allocate(new_size); //new T[new_size];\r
- allocated = new_size;\r
+ typedef std::basic_string<T> stl_type;\r
\r
- const u32 amount = used < new_size ? used : new_size;\r
- for (u32 i=0; i<amount; ++i)\r
- array[i] = old_array[i];\r
+ //! Private constructor\r
+ string(stl_type &&str) : str(str)\r
+ {}\r
\r
- if (allocated < used)\r
- used = allocated;\r
+ //! strlen wrapper\r
+ template <typename U>\r
+ static inline u32 calclen(const U* p) {\r
+ u32 len = 0;\r
+ while (*p++)\r
+ len++;\r
+ return len;\r
+ }\r
+ static inline u32 calclen(const char* p) {\r
+ return strlen(p);\r
+ }\r
+ static inline u32 calclen(const wchar_t* p) {\r
+ return wcslen(p);\r
+ }\r
\r
- allocator.deallocate(old_array); // delete [] old_array;\r
+ //! strcmp wrapper\r
+ template <typename U>\r
+ static inline int cmp(const U* p, const U* p2) {\r
+ while (*p && *p == *p2)\r
+ p++, p2++;\r
+ return (int)*p - (int)*p2;\r
+ }\r
+ static inline int cmp(const char* p, const char* p2) {\r
+ return strcmp(p, p2);\r
}\r
+ static inline int cmp(const wchar_t* p, const wchar_t* p2) {\r
+ return wcscmp(p, p2);\r
+ }\r
+\r
+ typedef typename stl_type::size_type size_type;\r
+ static const size_type npos = stl_type::npos;\r
\r
- //--- member variables\r
+ static inline s32 pos_from_stl(size_type pos) {\r
+ return pos == npos ? -1 : (s32)pos;\r
+ }\r
+ static inline size_type pos_to_stl(s32 pos) {\r
+ return pos == -1 ? npos : (size_type)pos;\r
+ }\r
\r
- T* array;\r
- u32 allocated;\r
- u32 used;\r
- TAlloc allocator;\r
+ stl_type str;\r
};\r
\r
\r
{\r
if ( sourceSize )\r
{\r
- destination.reserve(sourceSize+1);\r
+ destination.str.resize(sourceSize+1);\r
#if defined(_MSC_VER)\r
#pragma warning(push)\r
#pragma warning(disable: 4996) // 'mbstowcs': This function or variable may be unsafe. Consider using mbstowcs_s instead.\r
#endif\r
- const size_t written = mbstowcs(destination.array, source, (size_t)sourceSize);\r
+ const size_t written = mbstowcs(&destination[0], source, (size_t)sourceSize);\r
#if defined(_MSC_VER)\r
#pragma warning(pop)\r
#endif\r
if ( written != (size_t)-1 )\r
{\r
- destination.used = (u32)written+1;\r
- destination.array[destination.used-1] = 0;\r
+ destination.str.resize(written);\r
}\r
else\r
{\r
{\r
if ( sourceSize )\r
{\r
- destination.reserve(sizeof(wchar_t)*sourceSize+1);\r
+ destination.str.resize(sizeof(wchar_t)*sourceSize+1);\r
#if defined(_MSC_VER)\r
#pragma warning(push)\r
#pragma warning(disable: 4996) // 'wcstombs': This function or variable may be unsafe. Consider using wcstombs_s instead.\r
#endif\r
- const size_t written = wcstombs(destination.array, source, destination.allocated-1);\r
+ const size_t written = wcstombs(&destination[0], source, destination.size());\r
#if defined(_MSC_VER)\r
#pragma warning(pop)\r
#endif\r
if ( written != (size_t)-1 )\r
{\r
- destination.used = (u32)written+1;\r
- destination.array[destination.used-1] = 0;\r
+ destination.str.resize(written);\r
}\r
else\r
{\r