2009-01-27 05:23:36 -08:00
|
|
|
// Copyright (C) 2002-2009 Nikolaus Gebhardt
|
2007-05-20 11:03:49 -07:00
|
|
|
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
|
|
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
|
|
|
|
|
|
|
|
#ifndef __IRR_STRING_H_INCLUDED__
|
|
|
|
#define __IRR_STRING_H_INCLUDED__
|
|
|
|
|
|
|
|
#include "irrTypes.h"
|
|
|
|
#include "irrAllocator.h"
|
|
|
|
#include "irrMath.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
namespace irr
|
|
|
|
{
|
|
|
|
namespace core
|
|
|
|
{
|
|
|
|
|
2008-05-22 04:51:37 -07:00
|
|
|
//! Very simple string class with some useful features.
|
2008-11-27 15:52:13 -08:00
|
|
|
/** string<c8> and string<wchar_t> both accept Unicode AND ASCII/Latin-1,
|
|
|
|
so you can assign Unicode to string<c8> and ASCII/Latin-1 to string<wchar_t>
|
|
|
|
(and the other way round) if you want to.
|
|
|
|
|
|
|
|
However, note that the conversation between both is not done using any encoding.
|
|
|
|
This means that c8 strings are treated as ASCII/Latin-1, not UTF-8, and
|
|
|
|
are simply expanded to the equivalent wchar_t, while Unicode/wchar_t
|
|
|
|
characters are truncated to 8-bit ASCII/Latin-1 characters, discarding all
|
|
|
|
other information in the wchar_t.
|
2007-05-20 11:03:49 -07:00
|
|
|
*/
|
2009-05-04 17:09:53 -07:00
|
|
|
|
|
|
|
enum eLocaleID
|
|
|
|
{
|
|
|
|
IRR_LOCALE_ANSI = 0,
|
|
|
|
IRR_LOCALE_GERMAN = 1
|
|
|
|
};
|
|
|
|
|
|
|
|
static eLocaleID locale_current = IRR_LOCALE_ANSI;
|
|
|
|
static inline void locale_set ( eLocaleID id )
|
|
|
|
{
|
|
|
|
locale_current = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Returns a character converted to lower case
|
|
|
|
static inline u32 locale_lower ( u32 x )
|
|
|
|
{
|
|
|
|
switch ( locale_current )
|
|
|
|
{
|
|
|
|
case IRR_LOCALE_GERMAN:
|
|
|
|
case IRR_LOCALE_ANSI:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// ansi
|
|
|
|
return x >= 'A' && x <= 'Z' ? x + 0x20 : x;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Returns a character converted to upper case
|
|
|
|
static inline u32 locale_upper ( u32 x )
|
|
|
|
{
|
|
|
|
switch ( locale_current )
|
|
|
|
{
|
|
|
|
case IRR_LOCALE_GERMAN:
|
|
|
|
case IRR_LOCALE_ANSI:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ansi
|
|
|
|
return x >= 'a' && x <= 'z' ? x + ( 'A' - 'a' ) : x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
template <typename T, typename TAlloc = irrAllocator<T> >
|
|
|
|
class string
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
//! Default constructor
|
|
|
|
string()
|
|
|
|
: array(0), allocated(1), used(1)
|
|
|
|
{
|
|
|
|
array = allocator.allocate(1); // new T[1];
|
|
|
|
array[0] = 0x0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Constructor
|
|
|
|
string(const string<T>& other)
|
|
|
|
: array(0), allocated(0), used(0)
|
|
|
|
{
|
|
|
|
*this = other;
|
|
|
|
}
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Constructor from other string types
|
|
|
|
template <class B>
|
|
|
|
string(const string<B>& other)
|
|
|
|
: array(0), allocated(0), used(0)
|
|
|
|
{
|
|
|
|
*this = other;
|
|
|
|
}
|
2007-05-20 11:03:49 -07:00
|
|
|
|
|
|
|
|
|
|
|
//! Constructs a string from a float
|
2008-11-12 02:11:25 -08:00
|
|
|
explicit string(const double number)
|
2007-05-20 11:03:49 -07:00
|
|
|
: array(0), allocated(0), used(0)
|
|
|
|
{
|
|
|
|
c8 tmpbuf[255];
|
|
|
|
snprintf(tmpbuf, 255, "%0.6f", number);
|
|
|
|
*this = tmpbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Constructs a string from an int
|
2008-11-12 02:11:25 -08:00
|
|
|
explicit string(int number)
|
2007-05-20 11:03:49 -07:00
|
|
|
: array(0), allocated(0), used(0)
|
|
|
|
{
|
|
|
|
// store if negative and make positive
|
|
|
|
|
|
|
|
bool negative = false;
|
|
|
|
if (number < 0)
|
|
|
|
{
|
|
|
|
number *= -1;
|
|
|
|
negative = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// temporary buffer for 16 numbers
|
|
|
|
|
|
|
|
c8 tmpbuf[16];
|
|
|
|
tmpbuf[15] = 0;
|
|
|
|
u32 idx = 15;
|
|
|
|
|
|
|
|
// special case '0'
|
|
|
|
|
|
|
|
if (!number)
|
|
|
|
{
|
|
|
|
tmpbuf[14] = '0';
|
|
|
|
*this = &tmpbuf[14];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add numbers
|
|
|
|
|
|
|
|
while(number && idx)
|
|
|
|
{
|
|
|
|
--idx;
|
|
|
|
tmpbuf[idx] = (c8)('0' + (number % 10));
|
|
|
|
number /= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add sign
|
|
|
|
|
|
|
|
if (negative)
|
|
|
|
{
|
|
|
|
--idx;
|
|
|
|
tmpbuf[idx] = '-';
|
|
|
|
}
|
|
|
|
|
|
|
|
*this = &tmpbuf[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Constructs a string from an unsigned int
|
2008-11-12 02:11:25 -08:00
|
|
|
explicit string(unsigned int number)
|
2007-05-20 11:03:49 -07:00
|
|
|
: array(0), allocated(0), used(0)
|
|
|
|
{
|
|
|
|
// temporary buffer for 16 numbers
|
|
|
|
|
|
|
|
c8 tmpbuf[16];
|
|
|
|
tmpbuf[15] = 0;
|
|
|
|
u32 idx = 15;
|
|
|
|
|
|
|
|
// special case '0'
|
|
|
|
|
|
|
|
if (!number)
|
|
|
|
{
|
|
|
|
tmpbuf[14] = '0';
|
|
|
|
*this = &tmpbuf[14];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add numbers
|
|
|
|
|
|
|
|
while(number && idx)
|
|
|
|
{
|
|
|
|
--idx;
|
|
|
|
tmpbuf[idx] = (c8)('0' + (number % 10));
|
|
|
|
number /= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
*this = &tmpbuf[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Constructor for copying a string from a pointer with a given length
|
|
|
|
template <class B>
|
|
|
|
string(const B* const c, u32 length)
|
|
|
|
: array(0), allocated(0), used(0)
|
|
|
|
{
|
|
|
|
if (!c)
|
|
|
|
{
|
|
|
|
// correctly init the string to an empty one
|
|
|
|
*this="";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
allocated = used = length+1;
|
|
|
|
array = allocator.allocate(used); // new T[used];
|
|
|
|
|
|
|
|
for (u32 l = 0; l<length; ++l)
|
|
|
|
array[l] = (T)c[l];
|
|
|
|
|
|
|
|
array[length] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Constructor for unicode and ascii strings
|
|
|
|
template <class B>
|
|
|
|
string(const B* const c)
|
|
|
|
: array(0), allocated(0), used(0)
|
|
|
|
{
|
|
|
|
*this = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-27 05:23:36 -08:00
|
|
|
//! Destructor
|
2009-05-04 17:09:53 -07:00
|
|
|
virtual ~string()
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
allocator.deallocate(array); // delete [] array;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Assignment operator
|
|
|
|
string<T>& operator=(const string<T>& other)
|
|
|
|
{
|
|
|
|
if (this == &other)
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
allocator.deallocate(array); // delete [] array;
|
|
|
|
allocated = used = other.size()+1;
|
|
|
|
array = allocator.allocate(used); //new T[used];
|
|
|
|
|
|
|
|
const T* p = other.c_str();
|
|
|
|
for (u32 i=0; i<used; ++i, ++p)
|
|
|
|
array[i] = *p;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Assignment operator for other string types
|
|
|
|
template <class B>
|
|
|
|
string<T>& operator=(const string<B>& other)
|
|
|
|
{
|
|
|
|
*this = other.c_str();
|
|
|
|
return *this;
|
|
|
|
}
|
2007-05-20 11:03:49 -07:00
|
|
|
|
|
|
|
|
|
|
|
//! Assignment operator for strings, ascii and unicode
|
|
|
|
template <class B>
|
|
|
|
string<T>& operator=(const B* const c)
|
|
|
|
{
|
|
|
|
if (!c)
|
|
|
|
{
|
|
|
|
if (!array)
|
|
|
|
{
|
|
|
|
array = allocator.allocate(1); //new T[1];
|
|
|
|
allocated = 1;
|
|
|
|
}
|
|
|
|
used = 1;
|
|
|
|
array[0] = 0x0;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((void*)c == (void*)array)
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
u32 len = 0;
|
|
|
|
const B* p = c;
|
|
|
|
while(*p)
|
|
|
|
{
|
|
|
|
++len;
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we'll take the old string for a while, because the new
|
|
|
|
// string could be a part of the current string.
|
|
|
|
T* oldArray = array;
|
|
|
|
|
|
|
|
++len;
|
|
|
|
allocated = used = len;
|
|
|
|
array = allocator.allocate(used); //new T[used];
|
|
|
|
|
|
|
|
for (u32 l = 0; l<len; ++l)
|
|
|
|
array[l] = (T)c[l];
|
|
|
|
|
|
|
|
allocator.deallocate(oldArray); // delete [] oldArray;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
|
|
|
|
//! Append operator for other strings
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T> operator+(const string<T>& other) const
|
|
|
|
{
|
|
|
|
string<T> str(*this);
|
|
|
|
str.append(other);
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
|
|
|
|
//! Append operator for strings, ascii and unicode
|
2007-05-20 11:03:49 -07:00
|
|
|
template <class B>
|
|
|
|
string<T> operator+(const B* const c) const
|
|
|
|
{
|
|
|
|
string<T> str(*this);
|
|
|
|
str.append(c);
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Direct access operator
|
2007-09-17 09:09:50 -07:00
|
|
|
T& operator [](const u32 index)
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
_IRR_DEBUG_BREAK_IF(index>=used) // bad index
|
2007-09-17 09:09:50 -07:00
|
|
|
return array[index];
|
|
|
|
}
|
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
|
2007-09-17 09:09:50 -07:00
|
|
|
//! Direct access operator
|
|
|
|
const T& operator [](const u32 index) const
|
|
|
|
{
|
|
|
|
_IRR_DEBUG_BREAK_IF(index>=used) // bad index
|
2007-05-20 11:03:49 -07:00
|
|
|
return array[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Equality operator
|
2007-05-20 11:03:49 -07:00
|
|
|
bool operator ==(const T* const str) const
|
|
|
|
{
|
|
|
|
if (!str)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
u32 i;
|
|
|
|
for(i=0; array[i] && str[i]; ++i)
|
|
|
|
if (array[i] != str[i])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return !array[i] && !str[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Equality operator
|
2007-05-20 11:03:49 -07:00
|
|
|
bool operator ==(const string<T>& other) const
|
|
|
|
{
|
|
|
|
for(u32 i=0; array[i] && other.array[i]; ++i)
|
|
|
|
if (array[i] != other.array[i])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return used == other.used;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Is smaller comparator
|
2007-05-20 11:03:49 -07:00
|
|
|
bool operator <(const string<T>& other) const
|
|
|
|
{
|
|
|
|
for(u32 i=0; array[i] && other.array[i]; ++i)
|
|
|
|
{
|
|
|
|
s32 diff = array[i] - other.array[i];
|
|
|
|
if ( diff )
|
|
|
|
return diff < 0;
|
|
|
|
/*
|
|
|
|
if (array[i] != other.array[i])
|
|
|
|
return (array[i] < other.array[i]);
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
return used < other.used;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Inequality operator
|
2007-05-20 11:03:49 -07:00
|
|
|
bool operator !=(const T* const str) const
|
|
|
|
{
|
|
|
|
return !(*this == str);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Inequality operator
|
2007-05-20 11:03:49 -07:00
|
|
|
bool operator !=(const string<T>& other) const
|
|
|
|
{
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Returns length of string
|
2008-11-12 02:11:25 -08:00
|
|
|
/** \return Length of the string in characters. */
|
2007-05-20 11:03:49 -07:00
|
|
|
u32 size() const
|
|
|
|
{
|
|
|
|
return used-1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Returns character string
|
2008-11-12 02:11:25 -08:00
|
|
|
/** \return pointer to C-style zero terminated string. */
|
2007-05-20 11:03:49 -07:00
|
|
|
const T* c_str() const
|
|
|
|
{
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Makes the string lower case.
|
|
|
|
void make_lower()
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<used; ++i)
|
2009-05-04 17:09:53 -07:00
|
|
|
array[i] = locale_lower ( array[i] );
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Makes the string upper case.
|
|
|
|
void make_upper()
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<used; ++i)
|
2009-05-04 17:09:53 -07:00
|
|
|
array[i] = locale_upper ( array[i] );
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Compares the strings ignoring case.
|
2007-05-20 11:03:49 -07:00
|
|
|
/** \param other: Other string to compare.
|
2008-11-12 02:11:25 -08:00
|
|
|
\return True if the strings are equal ignoring case. */
|
2007-05-20 11:03:49 -07:00
|
|
|
bool equals_ignore_case(const string<T>& other) const
|
|
|
|
{
|
|
|
|
for(u32 i=0; array[i] && other[i]; ++i)
|
2009-05-04 17:09:53 -07:00
|
|
|
if (locale_lower( array[i]) != locale_lower(other[i]))
|
2007-05-20 11:03:49 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return used == other.used;
|
|
|
|
}
|
|
|
|
|
2009-05-04 17:09:53 -07:00
|
|
|
//! Compares the strings ignoring case.
|
|
|
|
/** \param other: Other string to compare.
|
|
|
|
\param sourcePos: where to start to compare in the string
|
|
|
|
\return True if the strings are equal ignoring case. */
|
|
|
|
bool equals_substring_ignore_case(const string<T>&other, const s32 sourcePos = 0 ) const
|
|
|
|
{
|
|
|
|
if ( (u32) sourcePos > used )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
u32 i;
|
|
|
|
for( i=0; array[sourcePos + i] && other[i]; ++i)
|
|
|
|
if (locale_lower( array[sourcePos + i]) != locale_lower(other[i]))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return array[sourcePos + i] == 0 && other[i] == 0;
|
|
|
|
}
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
|
|
|
|
//! Compares the strings ignoring case.
|
2007-05-20 11:03:49 -07:00
|
|
|
/** \param other: Other string to compare.
|
2008-11-12 02:11:25 -08:00
|
|
|
\return True if this string is smaller ignoring case. */
|
2007-05-20 11:03:49 -07:00
|
|
|
bool lower_ignore_case(const string<T>& other) const
|
|
|
|
{
|
|
|
|
for(u32 i=0; array[i] && other.array[i]; ++i)
|
|
|
|
{
|
2009-05-04 17:09:53 -07:00
|
|
|
s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] );
|
2007-05-20 11:03:49 -07:00
|
|
|
if ( diff )
|
|
|
|
return diff < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return used < other.used;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! compares the first n characters of the strings
|
2008-11-12 02:11:25 -08:00
|
|
|
/** \param other Other string to compare.
|
|
|
|
\param n Number of characters to compare
|
|
|
|
\return True if the n first characters of this string are smaller. */
|
2008-03-19 02:54:51 -07:00
|
|
|
bool equalsn(const string<T>& other, u32 n) const
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
u32 i;
|
2008-03-19 02:54:51 -07:00
|
|
|
for(i=0; array[i] && other[i] && i < n; ++i)
|
2007-05-20 11:03:49 -07:00
|
|
|
if (array[i] != other[i])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// if one (or both) of the strings was smaller then they
|
|
|
|
// are only equal if they have the same length
|
2008-03-19 02:54:51 -07:00
|
|
|
return (i == n) || (used == other.used);
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! compares the first n characters of the strings
|
2008-11-12 02:11:25 -08:00
|
|
|
/** \param str Other string to compare.
|
|
|
|
\param n Number of characters to compare
|
|
|
|
\return True if the n first characters of this string are smaller. */
|
2008-03-19 02:54:51 -07:00
|
|
|
bool equalsn(const T* const str, u32 n) const
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
if (!str)
|
|
|
|
return false;
|
2008-11-12 02:11:25 -08:00
|
|
|
u32 i;
|
2008-03-19 02:54:51 -07:00
|
|
|
for(i=0; array[i] && str[i] && i < n; ++i)
|
2007-05-20 11:03:49 -07:00
|
|
|
if (array[i] != str[i])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// if one (or both) of the strings was smaller then they
|
|
|
|
// are only equal if they have the same length
|
2008-03-19 02:54:51 -07:00
|
|
|
return (i == n) || (array[i] == 0 && str[i] == 0);
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Appends a character to this string
|
|
|
|
/** \param character: Character to append. */
|
|
|
|
void append(T character)
|
|
|
|
{
|
|
|
|
if (used + 1 > allocated)
|
|
|
|
reallocate(used + 1);
|
|
|
|
|
|
|
|
++used;
|
|
|
|
|
|
|
|
array[used-2] = character;
|
|
|
|
array[used-1] = 0;
|
|
|
|
}
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
//! Appends a char string to this string
|
|
|
|
/** \param other: Char string to append. */
|
|
|
|
void append(const T* const other)
|
|
|
|
{
|
|
|
|
if (!other)
|
|
|
|
return;
|
|
|
|
|
|
|
|
u32 len = 0;
|
|
|
|
const T* p = other;
|
|
|
|
while(*p)
|
|
|
|
{
|
|
|
|
++len;
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (used + len > allocated)
|
|
|
|
reallocate(used + len);
|
|
|
|
|
|
|
|
--used;
|
|
|
|
++len;
|
|
|
|
|
|
|
|
for (u32 l=0; l<len; ++l)
|
|
|
|
array[l+used] = *(other+l);
|
|
|
|
|
|
|
|
used += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Appends a string to this string
|
|
|
|
/** \param other: String to append. */
|
|
|
|
void append(const string<T>& other)
|
|
|
|
{
|
|
|
|
--used;
|
|
|
|
u32 len = other.size()+1;
|
|
|
|
|
|
|
|
if (used + len > allocated)
|
|
|
|
reallocate(used + len);
|
|
|
|
|
|
|
|
for (u32 l=0; l<len; ++l)
|
|
|
|
array[used+l] = other[l];
|
|
|
|
|
|
|
|
used += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Appends a string of the length l to this string.
|
|
|
|
/** \param other: other String to append to this string.
|
2008-05-22 04:51:37 -07:00
|
|
|
\param length: How much characters of the other string to add to this one. */
|
2007-05-20 11:03:49 -07:00
|
|
|
void append(const string<T>& other, u32 length)
|
|
|
|
{
|
|
|
|
if (other.size() < length)
|
|
|
|
{
|
|
|
|
append(other);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (used + length > allocated)
|
|
|
|
reallocate(used + length);
|
|
|
|
|
|
|
|
--used;
|
|
|
|
|
|
|
|
for (u32 l=0; l<length; ++l)
|
|
|
|
array[l+used] = other[l];
|
|
|
|
used += length;
|
|
|
|
|
|
|
|
// ensure proper termination
|
|
|
|
array[used]=0;
|
|
|
|
++used;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Reserves some memory.
|
|
|
|
/** \param count: Amount of characters to reserve. */
|
|
|
|
void reserve(u32 count)
|
|
|
|
{
|
|
|
|
if (count < allocated)
|
|
|
|
return;
|
|
|
|
|
|
|
|
reallocate(count);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! finds first occurrence of character in string
|
|
|
|
/** \param c: Character to search for.
|
2008-11-27 15:52:13 -08:00
|
|
|
\return Position where the character has been found,
|
2007-05-20 11:03:49 -07:00
|
|
|
or -1 if not found. */
|
|
|
|
s32 findFirst(T c) const
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<used; ++i)
|
|
|
|
if (array[i] == c)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! finds first occurrence of a character of a list in string
|
2008-03-02 06:28:48 -08:00
|
|
|
/** \param c: List of characters to find. For example if the method
|
2007-05-20 11:03:49 -07:00
|
|
|
should find the first occurrence of 'a' or 'b', this parameter should be "ab".
|
2008-03-02 06:28:48 -08:00
|
|
|
\param count: Amount of characters in the list. Usually,
|
|
|
|
this should be strlen(c)
|
2008-11-27 15:52:13 -08:00
|
|
|
\return Position where one of the characters has been found,
|
2007-05-20 11:03:49 -07:00
|
|
|
or -1 if not found. */
|
|
|
|
s32 findFirstChar(const T* const c, u32 count) const
|
|
|
|
{
|
|
|
|
if (!c)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (u32 i=0; i<used; ++i)
|
|
|
|
for (u32 j=0; j<count; ++j)
|
|
|
|
if (array[i] == c[j])
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Finds first position of a character not in a given list.
|
|
|
|
/** \param c: List of characters not to find. For example if the method
|
2008-05-22 04:51:37 -07:00
|
|
|
should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".
|
2008-03-02 06:28:48 -08:00
|
|
|
\param count: Amount of characters in the list. Usually,
|
|
|
|
this should be strlen(c)
|
2008-11-27 15:52:13 -08:00
|
|
|
\return Position where the character has been found,
|
2007-05-20 11:03:49 -07:00
|
|
|
or -1 if not found. */
|
|
|
|
template <class B>
|
|
|
|
s32 findFirstCharNotInList(const B* const c, u32 count) const
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<used-1; ++i)
|
|
|
|
{
|
|
|
|
u32 j;
|
|
|
|
for (j=0; j<count; ++j)
|
|
|
|
if (array[i] == c[j])
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (j==count)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Finds last position of a character not in a given list.
|
|
|
|
/** \param c: List of characters not to find. For example if the method
|
2008-05-22 04:51:37 -07:00
|
|
|
should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".
|
2008-03-02 06:28:48 -08:00
|
|
|
\param count: Amount of characters in the list. Usually,
|
|
|
|
this should be strlen(c)
|
2008-11-27 15:52:13 -08:00
|
|
|
\return Position where the character has been found,
|
2007-05-20 11:03:49 -07:00
|
|
|
or -1 if not found. */
|
|
|
|
template <class B>
|
|
|
|
s32 findLastCharNotInList(const B* const c, u32 count) const
|
|
|
|
{
|
|
|
|
for (s32 i=(s32)(used-2); i>=0; --i)
|
|
|
|
{
|
|
|
|
u32 j;
|
|
|
|
for (j=0; j<count; ++j)
|
|
|
|
if (array[i] == c[j])
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (j==count)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! finds next occurrence of character in string
|
|
|
|
/** \param c: Character to search for.
|
|
|
|
\param startPos: Position in string to start searching.
|
2008-11-27 15:52:13 -08:00
|
|
|
\return Position where the character has been found,
|
2007-05-20 11:03:49 -07:00
|
|
|
or -1 if not found. */
|
|
|
|
s32 findNext(T c, u32 startPos) const
|
|
|
|
{
|
|
|
|
for (u32 i=startPos; i<used; ++i)
|
|
|
|
if (array[i] == c)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! finds last occurrence of character in string
|
2008-11-27 15:52:13 -08:00
|
|
|
/** \param c: Character to search for.
|
|
|
|
\param start: start to search reverse ( default = -1, on end )
|
|
|
|
\return Position where the character has been found,
|
|
|
|
or -1 if not found. */
|
2007-05-20 11:03:49 -07:00
|
|
|
s32 findLast(T c, s32 start = -1) const
|
|
|
|
{
|
|
|
|
start = core::clamp ( start < 0 ? (s32)(used) - 1 : start, 0, (s32)(used) - 1 );
|
|
|
|
for (s32 i=start; i>=0; --i)
|
|
|
|
if (array[i] == c)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-03-02 06:28:48 -08:00
|
|
|
//! finds last occurrence of a character of a list in string
|
|
|
|
/** \param c: List of strings to find. For example if the method
|
|
|
|
should find the last occurrence of 'a' or 'b', this parameter should be "ab".
|
|
|
|
\param count: Amount of characters in the list. Usually,
|
|
|
|
this should be strlen(c)
|
2008-11-27 15:52:13 -08:00
|
|
|
\return Position where one of the characters has been found,
|
2008-03-02 06:28:48 -08:00
|
|
|
or -1 if not found. */
|
|
|
|
s32 findLastChar(const T* const c, u32 count) const
|
|
|
|
{
|
|
|
|
if (!c)
|
|
|
|
return -1;
|
|
|
|
|
2008-03-19 02:54:51 -07:00
|
|
|
for (s32 i=used-1; i>=0; --i)
|
2008-03-02 06:28:48 -08:00
|
|
|
for (u32 j=0; j<count; ++j)
|
|
|
|
if (array[i] == c[j])
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
//! finds another string in this string
|
2008-11-27 15:52:13 -08:00
|
|
|
/** \param str: Another string
|
|
|
|
\return Positions where the string has been found,
|
|
|
|
or -1 if not found. */
|
2007-05-20 11:03:49 -07:00
|
|
|
template <class B>
|
|
|
|
s32 find(const B* const str) const
|
|
|
|
{
|
|
|
|
if (str && *str)
|
|
|
|
{
|
|
|
|
u32 len = 0;
|
|
|
|
|
|
|
|
while (str[len])
|
|
|
|
++len;
|
|
|
|
|
|
|
|
if (len > used-1)
|
|
|
|
return -1;
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
for (u32 i=0; i<used-len; ++i)
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
u32 j=0;
|
|
|
|
|
|
|
|
while(str[j] && array[i+j] == str[j])
|
|
|
|
++j;
|
|
|
|
|
|
|
|
if (!str[j])
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Returns a substring
|
2008-11-27 15:52:13 -08:00
|
|
|
/** \param begin: Start of substring.
|
|
|
|
\param length: Length of substring. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T> subString(u32 begin, s32 length) const
|
|
|
|
{
|
2008-07-17 02:01:06 -07:00
|
|
|
// if start after string
|
|
|
|
// or no proper substring length
|
|
|
|
if ((length <= 0) || (begin>=size()))
|
|
|
|
return string<T>("");
|
|
|
|
// clamp length to maximal value
|
2007-05-20 11:03:49 -07:00
|
|
|
if ((length+begin) > size())
|
|
|
|
length = size()-begin;
|
|
|
|
|
|
|
|
string<T> o;
|
|
|
|
o.reserve(length+1);
|
|
|
|
|
|
|
|
for (s32 i=0; i<length; ++i)
|
|
|
|
o.array[i] = array[i+begin];
|
|
|
|
|
|
|
|
o.array[length] = 0;
|
|
|
|
o.used = o.allocated;
|
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Appends a character to this string
|
2009-01-27 05:23:36 -08:00
|
|
|
/** \param c Character to append. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T>& operator += (T c)
|
|
|
|
{
|
|
|
|
append(c);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Appends a char string to this string
|
2009-01-27 05:23:36 -08:00
|
|
|
/** \param c Char string to append. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T>& operator += (const T* const c)
|
|
|
|
{
|
|
|
|
append(c);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Appends a string to this string
|
2009-01-27 05:23:36 -08:00
|
|
|
/** \param other String to append. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T>& operator += (const string<T>& other)
|
|
|
|
{
|
|
|
|
append(other);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-27 05:23:36 -08:00
|
|
|
//! Appends a string representation of a number to this string
|
|
|
|
/** \param i Number to append. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T>& operator += (const int i)
|
|
|
|
{
|
|
|
|
append(string<T>(i));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-27 05:23:36 -08:00
|
|
|
//! Appends a string representation of a number to this string
|
|
|
|
/** \param i Number to append. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T>& operator += (const unsigned int i)
|
|
|
|
{
|
|
|
|
append(string<T>(i));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-27 05:23:36 -08:00
|
|
|
//! Appends a string representation of a number to this string
|
|
|
|
/** \param i Number to append. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T>& operator += (const long i)
|
|
|
|
{
|
|
|
|
append(string<T>(i));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-27 05:23:36 -08:00
|
|
|
//! Appends a string representation of a number to this string
|
|
|
|
/** \param i Number to append. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T>& operator += (const unsigned long& i)
|
|
|
|
{
|
|
|
|
append(string<T>(i));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-27 05:23:36 -08:00
|
|
|
//! Appends a string representation of a number to this string
|
|
|
|
/** \param i Number to append. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T>& operator += (const double i)
|
|
|
|
{
|
|
|
|
append(string<T>(i));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-27 05:23:36 -08:00
|
|
|
//! Appends a string representation of a number to this string
|
|
|
|
/** \param i Number to append. */
|
2007-05-20 11:03:49 -07:00
|
|
|
string<T>& operator += (const float i)
|
|
|
|
{
|
|
|
|
append(string<T>(i));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-27 05:23:36 -08:00
|
|
|
//! Replaces all characters of a special type with another one
|
|
|
|
/** \param toReplace Character to replace.
|
|
|
|
\param replaceWith Character replacing the old one. */
|
2007-05-20 11:03:49 -07:00
|
|
|
void replace(T toReplace, T replaceWith)
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<used; ++i)
|
|
|
|
if (array[i] == toReplace)
|
|
|
|
array[i] = replaceWith;
|
|
|
|
}
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
|
2009-01-27 05:23:36 -08:00
|
|
|
//! Trims the string.
|
2008-12-19 01:56:25 -08:00
|
|
|
/** Removes the specified characters (by default, Latin-1 whitespace)
|
|
|
|
from the begining and the end of the string. */
|
|
|
|
string<T>& trim(const string<T> & whitespace = " \t\n\r")
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
2008-12-19 01:56:25 -08:00
|
|
|
// find start and end of the substring without the specified characters
|
|
|
|
const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);
|
2007-05-20 11:03:49 -07:00
|
|
|
if (begin == -1)
|
2008-03-19 02:54:51 -07:00
|
|
|
return (*this="");
|
2007-05-20 11:03:49 -07:00
|
|
|
|
2008-12-19 01:56:25 -08:00
|
|
|
const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);
|
2007-05-20 11:03:49 -07:00
|
|
|
|
2008-03-19 02:54:51 -07:00
|
|
|
return (*this = subString(begin, (end +1) - begin));
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-12 02:11:25 -08:00
|
|
|
//! Erases a character from the string.
|
|
|
|
/** May be slow, because all elements
|
|
|
|
following after the erased element have to be copied.
|
|
|
|
\param index: Index of element to be erased. */
|
2007-05-20 11:03:49 -07:00
|
|
|
void erase(u32 index)
|
|
|
|
{
|
|
|
|
_IRR_DEBUG_BREAK_IF(index>=used) // access violation
|
|
|
|
|
|
|
|
for (u32 i=index+1; i<used; ++i)
|
|
|
|
array[i-1] = array[i];
|
|
|
|
|
|
|
|
--used;
|
|
|
|
}
|
|
|
|
|
2009-05-04 17:09:53 -07:00
|
|
|
//! verify the existing string.
|
|
|
|
void validate()
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
2009-05-04 17:09:53 -07:00
|
|
|
// terminate on existing null
|
|
|
|
for (u32 i=0; i<allocated; ++i)
|
|
|
|
{
|
|
|
|
if (array[i] == 0)
|
|
|
|
{
|
|
|
|
used = i + 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// terminate
|
|
|
|
if ( allocated > 0 )
|
|
|
|
{
|
|
|
|
used = allocated - 1;
|
|
|
|
array[used] = 0;
|
|
|
|
}
|
2007-05-20 11:03:49 -07:00
|
|
|
else
|
2009-05-04 17:09:53 -07:00
|
|
|
{
|
|
|
|
used = 0;
|
|
|
|
}
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
2009-05-04 17:09:53 -07:00
|
|
|
private:
|
2007-05-20 11:03:49 -07:00
|
|
|
|
|
|
|
//! Reallocate the array, make it bigger or smaller
|
|
|
|
void reallocate(u32 new_size)
|
|
|
|
{
|
|
|
|
T* old_array = array;
|
|
|
|
|
|
|
|
array = allocator.allocate(new_size); //new T[new_size];
|
|
|
|
allocated = new_size;
|
|
|
|
|
|
|
|
u32 amount = used < new_size ? used : new_size;
|
|
|
|
for (u32 i=0; i<amount; ++i)
|
|
|
|
array[i] = old_array[i];
|
|
|
|
|
|
|
|
if (allocated < used)
|
|
|
|
used = allocated;
|
|
|
|
|
|
|
|
allocator.deallocate(old_array); // delete [] old_array;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--- member variables
|
|
|
|
|
|
|
|
T* array;
|
2009-05-04 17:09:53 -07:00
|
|
|
TAlloc allocator;
|
2007-05-20 11:03:49 -07:00
|
|
|
u32 allocated;
|
|
|
|
u32 used;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//! Typedef for character strings
|
2007-09-19 07:08:28 -07:00
|
|
|
typedef string<c8> stringc;
|
2007-05-20 11:03:49 -07:00
|
|
|
|
|
|
|
//! Typedef for wide character strings
|
|
|
|
typedef string<wchar_t> stringw;
|
|
|
|
|
2009-05-04 17:09:53 -07:00
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
} // end namespace core
|
|
|
|
} // end namespace irr
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|