NazaraEngine/src/Nazara/Core/String.cpp

4372 lines
90 KiB
C++

// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
///TODO: Réécrire une bonne partie des algorithmes employés (Relu jusqu'à 3538)
#include <Nazara/Core/String.hpp>
#include <Nazara/Core/AbstractHash.hpp>
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Unicode.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <limits>
#include <sstream>
#include <Utfcpp/utf8.h>
#include <Nazara/Core/Debug.hpp>
// Cet algorithme est inspiré de la documentation de Qt
inline unsigned int nzGetNewSize(unsigned int newSize)
{
if (newSize < 20)
return newSize+4;
else
{
if (newSize < (1 << 12)-12)
return NzGetNearestPowerOfTwo(newSize << 1)-12;
else
return newSize + (1 << 11);
}
}
inline char nzToLower(char character)
{
if (character >= 'A' && character <= 'Z')
return character + ('a' - 'A');
else
return character;
}
inline char nzToUpper(char character)
{
if (character >= 'a' && character <= 'z')
return character + ('A' - 'a');
else
return character;
}
inline int nzStrcasecmp(const char* s1, const char* s2)
{
int ret = 0;
while (!(ret = static_cast<unsigned char>(nzToLower(*s1)) - static_cast<unsigned char>(nzToLower(*s2))) && *s2)
++s1, ++s2;
return ret != 0 ? (ret > 0 ? 1 : -1) : 0;
}
inline int nzUnicodecasecmp(const char* s1, const char* s2)
{
int ret = 0;
utf8::unchecked::iterator<const char*> it1(s1);
utf8::unchecked::iterator<const char*> it2(s2);
while (!(ret = NzUnicode::GetLowercase(*it1) - NzUnicode::GetLowercase(*it2)) && *it2)
++it1, ++it2;
return ret != 0 ? (ret > 0 ? 1 : -1) : 0;
}
NzString::NzString() :
m_sharedString(&emptyString)
{
}
NzString::NzString(char character)
{
if (character != '\0')
{
m_sharedString = new SharedString;
m_sharedString->capacity = 1;
m_sharedString->size = 1;
m_sharedString->string = new char[2];
m_sharedString->string[0] = character;
m_sharedString->string[1] = '\0';
}
else
m_sharedString = &emptyString;
}
NzString::NzString(unsigned int rep, char character)
{
if (rep > 0)
{
m_sharedString = new SharedString;
m_sharedString->capacity = rep;
m_sharedString->size = rep;
m_sharedString->string = new char[rep+1];
if (character != '\0')
std::memset(m_sharedString->string, character, rep);
m_sharedString->string[rep] = '\0';
}
else
m_sharedString = &emptyString;
}
NzString::NzString(unsigned int rep, const char* string) :
NzString(rep, string, (string) ? std::strlen(string) : 0)
{
}
NzString::NzString(unsigned int rep, const char* string, unsigned int length)
{
unsigned int totalSize = rep*length;
if (totalSize > 0)
{
m_sharedString = new SharedString;
m_sharedString->capacity = totalSize;
m_sharedString->size = totalSize;
m_sharedString->string = new char[totalSize+1];
for (unsigned int i = 0; i < rep; ++i)
std::memcpy(&m_sharedString->string[i*length], string, length);
m_sharedString->string[totalSize] = '\0';
}
else
m_sharedString = &emptyString;
}
NzString::NzString(unsigned int rep, const NzString& string) :
NzString(rep, string.m_sharedString->string, string.m_sharedString->size)
{
}
NzString::NzString(const char* string) :
NzString(string, (string) ? std::strlen(string) : 0)
{
}
NzString::NzString(const char* string, unsigned int length)
{
if (length > 0)
{
m_sharedString = new SharedString;
m_sharedString->capacity = length;
m_sharedString->size = length;
m_sharedString->string = new char[length+1];
std::memcpy(m_sharedString->string, string, length);
m_sharedString->string[length] = '\0';
}
else
m_sharedString = &emptyString;
}
NzString::NzString(const std::string& string)
{
if (string.size() > 0)
{
m_sharedString = new SharedString;
m_sharedString->capacity = string.capacity();
m_sharedString->size = string.size();
m_sharedString->string = new char[string.capacity()+1];
std::memcpy(m_sharedString->string, string.c_str(), string.size()+1);
}
else
m_sharedString = &emptyString;
}
NzString::NzString(const NzString& string) :
m_sharedString(string.m_sharedString)
{
if (m_sharedString != &emptyString)
m_sharedString->refCount++;
}
NzString::NzString(NzString&& string) noexcept :
m_sharedString(string.m_sharedString)
{
string.m_sharedString = &emptyString;
}
NzString::NzString(SharedString* sharedString) :
m_sharedString(sharedString)
{
}
NzString::~NzString()
{
ReleaseString();
}
NzString& NzString::Append(char character)
{
return Insert(m_sharedString->size, character);
}
NzString& NzString::Append(const char* string)
{
return Insert(m_sharedString->size, string);
}
NzString& NzString::Append(const char* string, unsigned int length)
{
return Insert(m_sharedString->size, string, length);
}
NzString& NzString::Append(const NzString& string)
{
return Insert(m_sharedString->size, string);
}
void NzString::Clear(bool keepBuffer)
{
if (keepBuffer)
{
EnsureOwnership(true);
m_sharedString->size = 0;
}
else
ReleaseString();
}
bool NzString::Contains(char character, int start, nzUInt32 flags) const
{
return Find(character, start, flags) != npos;
}
bool NzString::Contains(const char* string, int start, nzUInt32 flags) const
{
return Find(string, start, flags) != npos;
}
bool NzString::Contains(const NzString& string, int start, nzUInt32 flags) const
{
return Find(string, start, flags) != npos;
}
unsigned int NzString::Count(char character, int start, nzUInt32 flags) const
{
if (character == '\0' || m_sharedString->size == 0)
return 0;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return 0;
char* str = &m_sharedString->string[pos];
unsigned int count = 0;
if (flags & CaseInsensitive)
{
char character_lower = nzToLower(character);
char character_upper = nzToUpper(character);
do
{
if (*str == character_lower || *str == character_upper)
count++;
}
while (*++str);
}
else
{
while ((str = std::strchr(str, character)))
{
count++;
str++;
}
}
return count;
}
unsigned int NzString::Count(const char* string, int start, nzUInt32 flags) const
{
if (!string || !string[0] || m_sharedString->size == 0)
return 0;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return 0;
char* str = &m_sharedString->string[pos];
unsigned int count = 0;
if (flags & CaseInsensitive)
{
if (flags & HandleUtf8)
{
while (utf8::internal::is_trail(*str))
str++;
utf8::unchecked::iterator<const char*> it(str);
const char* t = string;
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (NzUnicode::GetLowercase(*it) == c)
{
++it;
utf8::unchecked::iterator<const char*> it2(t);
while (true)
{
if (*it2 == '\0')
{
count++;
break;
}
if (*it == '\0')
return count;
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
break;
++it;
++it2;
}
}
}
while (*++it);
}
else
{
char c = nzToLower(string[0]);
do
{
if (nzToLower(*str) == c)
{
str++;
const char* ptr = &string[1];
while (true)
{
if (*ptr == '\0')
{
count++;
break;
}
if (*str == '\0')
return count;
if (nzToLower(*str) != nzToLower(*ptr))
break;
ptr++;
str++;
}
}
}
while (*++str);
}
}
else
{
while ((str = std::strstr(str, string)))
{
count++;
str++;
}
}
return count;
}
unsigned int NzString::Count(const NzString& string, int start, nzUInt32 flags) const
{
return Count(string.m_sharedString->string, start, flags);
}
unsigned int NzString::CountAny(const char* string, int start, nzUInt32 flags) const
{
if (!string || !string[0] || m_sharedString->size == 0)
return 0;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return 0;
char* str = &m_sharedString->string[pos];
unsigned int count = 0;
if (flags & HandleUtf8)
{
while (utf8::internal::is_trail(*str))
str++;
utf8::unchecked::iterator<const char*> it(str);
if (flags & CaseInsensitive)
{
do
{
utf8::unchecked::iterator<const char*> it2(string);
do
{
if (NzUnicode::GetLowercase(*it) == NzUnicode::GetLowercase(*it2))
{
count++;
break;
}
}
while (*++it2);
}
while (*++str);
}
else
{
do
{
utf8::unchecked::iterator<const char*> it2(string);
do
{
if (*it == *it2)
{
count++;
break;
}
}
while (*++it2);
}
while (*++str);
}
}
else
{
if (flags & CaseInsensitive)
{
do
{
const char* c = string;
do
{
if (nzToLower(*str) == nzToLower(*c))
{
count++;
break;
}
}
while (*++c);
}
while (*++str);
}
else
{
while ((str = std::strpbrk(str, string)))
{
count++;
str++;
}
}
}
return count;
}
unsigned int NzString::CountAny(const NzString& string, int start, nzUInt32 flags) const
{
return CountAny(string.m_sharedString->string, start, flags);
}
bool NzString::EndsWith(char character, nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return 0;
if (flags & CaseInsensitive)
return nzToLower(m_sharedString->string[m_sharedString->size-1]) == nzToLower(character);
else
return m_sharedString->string[m_sharedString->size-1] == character; // character == '\0' sera toujours faux
}
bool NzString::EndsWith(const char* string, nzUInt32 flags) const
{
return EndsWith(string, std::strlen(string), flags);
}
bool NzString::EndsWith(const char* string, unsigned int length, nzUInt32 flags) const
{
if (!string || !string[0] || m_sharedString->size == 0 || length > m_sharedString->size)
return false;
if (flags & CaseInsensitive)
{
if (flags & HandleUtf8)
return nzUnicodecasecmp(&m_sharedString->string[m_sharedString->size - length], string) == 0;
else
return nzStrcasecmp(&m_sharedString->string[m_sharedString->size - length], string) == 0;
}
else
return std::strcmp(&m_sharedString->string[m_sharedString->size - length], string) == 0;
}
bool NzString::EndsWith(const NzString& string, nzUInt32 flags) const
{
return EndsWith(string.m_sharedString->string, string.m_sharedString->size, flags);
}
unsigned int NzString::Find(char character, int start, nzUInt32 flags) const
{
if (character == '\0' || m_sharedString->size == 0)
return npos;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
if (flags & CaseInsensitive)
{
char ch = nzToLower(character);
const char* str = m_sharedString->string;
do
{
if (nzToLower(*str) == ch)
return static_cast<unsigned int>(str - m_sharedString->string);
}
while (*++str);
return npos;
}
else
{
char* ch = std::strchr(&m_sharedString->string[pos], character);
if (ch)
return static_cast<unsigned int>(ch - m_sharedString->string);
else
return npos;
}
}
unsigned int NzString::Find(const char* string, int start, nzUInt32 flags) const
{
if (!string || !string[0] || m_sharedString->size == 0)
return npos;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
char* str = &m_sharedString->string[pos];
if (flags & CaseInsensitive)
{
if (flags & HandleUtf8)
{
while (utf8::internal::is_trail(*str))
str++;
utf8::unchecked::iterator<const char*> it(str);
const char* t = string;
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (NzUnicode::GetLowercase(*it) == c)
{
const char* ptrPos = it.base();
++it;
utf8::unchecked::iterator<const char*> it2(t);
while (true)
{
if (*it2 == '\0')
return static_cast<unsigned int>(ptrPos - m_sharedString->string);
if (*it == '\0')
return npos;
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
break;
++it;
++it2;
}
}
}
while (*++it);
}
else
{
char c = nzToLower(string[0]);
do
{
if (nzToLower(*str) == c)
{
char* ptrPos = str;
str++;
const char* ptr = &string[1];
while (true)
{
if (*ptr == '\0')
return static_cast<unsigned int>(ptrPos - m_sharedString->string);
if (*str == '\0')
return npos;
if (nzToLower(*str) != nzToLower(*ptr))
break;
ptr++;
str++;
}
}
}
while (*++str);
}
}
else
{
char* ch = std::strstr(&m_sharedString->string[pos], string);
if (ch)
return static_cast<unsigned int>(ch - m_sharedString->string);
}
return npos;
}
unsigned int NzString::Find(const NzString& string, int start, nzUInt32 flags) const
{
return Find(string.m_sharedString->string, start, flags);
}
unsigned int NzString::FindAny(const char* string, int start, nzUInt32 flags) const
{
if (m_sharedString->size == 0 || !string || !string[0])
return npos;
if (start < 0)
start = std::max(m_sharedString->size+start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
char* str = &m_sharedString->string[pos];
if (flags & HandleUtf8)
{
while (utf8::internal::is_trail(*str))
str++;
utf8::unchecked::iterator<const char*> it(str);
if (flags & CaseInsensitive)
{
do
{
utf8::unchecked::iterator<const char*> it2(string);
char32_t character = NzUnicode::GetLowercase(*it);
do
{
if (character == NzUnicode::GetLowercase(*it2))
return it.base() - m_sharedString->string;
}
while (*++it2);
}
while (*++it);
}
else
{
do
{
utf8::unchecked::iterator<const char*> it2(string);
do
{
if (*it == *it2)
return it.base() - m_sharedString->string;
}
while (*++it2);
}
while (*++it);
}
}
else
{
if (flags & CaseInsensitive)
{
do
{
const char* c = string;
char character = nzToLower(*str);
do
{
if (character == nzToLower(*c))
return str - m_sharedString->string;
}
while (*++c);
}
while (*++str);
}
else
{
str = std::strpbrk(str, string);
if (str)
return str - m_sharedString->string;
}
}
return npos;
}
unsigned int NzString::FindAny(const NzString& string, int start, nzUInt32 flags) const
{
return FindAny(string.m_sharedString->string, start, flags);
}
unsigned int NzString::FindLast(char character, int start, nzUInt32 flags) const
{
if (character == '\0' || m_sharedString->size == 0)
return npos;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
char* ptr = &m_sharedString->string[m_sharedString->size-1];
if (flags & CaseInsensitive)
{
character = nzToLower(character);
do
{
if (nzToLower(*ptr) == character)
return static_cast<unsigned int>(ptr - m_sharedString->string);
}
while (ptr-- != m_sharedString->string);
}
else
{
do
{
if (*ptr == character)
return static_cast<unsigned int>(ptr - m_sharedString->string);
}
while (ptr-- != m_sharedString->string);
}
return npos;
}
unsigned int NzString::FindLast(const char* string, int start, nzUInt32 flags) const
{
if (!string || !string[0] || m_sharedString->size == 0)
return npos;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
///Algo 1.FindLast#3 (Taille du pattern inconnue)
const char* ptr = &m_sharedString->string[pos];
if (flags & CaseInsensitive)
{
if (flags & HandleUtf8)
{
if (utf8::internal::is_trail(*ptr))
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
utf8::unchecked::iterator<const char*> it(ptr);
const char* t = string;
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (NzUnicode::GetLowercase(*it) == c)
{
utf8::unchecked::iterator<const char*> it2(t);
utf8::unchecked::iterator<const char*> tIt(it);
++tIt;
while (true)
{
if (*it2 == '\0')
return it.base() - m_sharedString->string;
if (tIt.base() > &m_sharedString->string[pos])
break;
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*it2))
break;
++it2;
++tIt;
}
}
}
while (it--.base() != m_sharedString->string);
}
else
{
char c = nzToLower(string[0]);
do
{
if (nzToLower(*ptr) == c)
{
const char* p = &string[1];
const char* tPtr = ptr+1;
while (true)
{
if (*p == '\0')
return ptr - m_sharedString->string;
if (tPtr > &m_sharedString->string[pos])
break;
if (nzToLower(*tPtr) != nzToLower(*p))
break;
p++;
tPtr++;
}
}
}
while (ptr-- != m_sharedString->string);
}
}
else
{
do
{
if (*ptr == string[0])
{
const char* p = &string[1];
const char* tPtr = ptr+1;
while (true)
{
if (*p == '\0')
return ptr - m_sharedString->string;
if (tPtr > &m_sharedString->string[pos])
break;
if (*tPtr != *p)
break;
p++;
tPtr++;
}
}
}
while (ptr-- != m_sharedString->string);
}
return npos;
}
unsigned int NzString::FindLast(const NzString& string, int start, nzUInt32 flags) const
{
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
return npos;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size || string.m_sharedString->size > m_sharedString->size)
return npos;
const char* ptr = &m_sharedString->string[pos];
const char* limit = &m_sharedString->string[string.m_sharedString->size-1];
if (flags & CaseInsensitive)
{
if (flags & HandleUtf8)
{
///Algo 1.FindLast#3 (Itérateur non-adapté)
if (utf8::internal::is_trail(*ptr))
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
utf8::unchecked::iterator<const char*> it(ptr);
const char* t = string.m_sharedString->string;
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (NzUnicode::GetLowercase(*it) == c)
{
utf8::unchecked::iterator<const char*> it2(t);
utf8::unchecked::iterator<const char*> tIt(it);
++tIt;
while (true)
{
if (*it2 == '\0')
return it.base() - m_sharedString->string;
if (tIt.base() > &m_sharedString->string[pos])
break;
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*it2))
break;
++it2;
++tIt;
}
}
}
while (it--.base() != limit);
}
else
{
///Algo 1.FindLast#4 (Taille du pattern connue)
char c = nzToLower(string.m_sharedString->string[string.m_sharedString->size-1]);
while (true)
{
if (nzToLower(*ptr) == c)
{
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
{
if (nzToLower(*ptr) != nzToLower(*p))
break;
if (p == &string.m_sharedString->string[0])
return ptr-m_sharedString->string;
if (ptr == m_sharedString->string)
return npos;
}
}
else if (ptr-- <= limit)
break;
}
}
}
else
{
///Algo 1.FindLast#4 (Taille du pattern connue)
while (true)
{
if (*ptr == string.m_sharedString->string[string.m_sharedString->size-1])
{
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
{
if (*ptr != *p)
break;
if (p == &string.m_sharedString->string[0])
return ptr-m_sharedString->string;
if (ptr == m_sharedString->string)
return npos;
}
}
else if (ptr-- <= limit)
break;
}
}
return npos;
}
unsigned int NzString::FindLastAny(const char* string, int start, nzUInt32 flags) const
{
if (!string || !string[0] || m_sharedString->size == 0)
return npos;
if (start < 0)
start = std::max(m_sharedString->size+start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
char* str = &m_sharedString->string[pos];
if (flags & HandleUtf8)
{
while (utf8::internal::is_trail(*str))
str++;
utf8::unchecked::iterator<const char*> it(str);
if (flags & CaseInsensitive)
{
do
{
utf8::unchecked::iterator<const char*> it2(string);
char32_t character = NzUnicode::GetLowercase(*it);
do
{
if (character == NzUnicode::GetLowercase(*it2))
return it.base() - m_sharedString->string;
}
while (*++it2);
}
while (it--.base() != m_sharedString->string);
}
else
{
do
{
utf8::unchecked::iterator<const char*> it2(string);
do
{
if (*it == *it2)
return it.base() - m_sharedString->string;
}
while (*++it2);
}
while (it--.base() != m_sharedString->string);
}
}
else
{
if (flags & CaseInsensitive)
{
do
{
const char* c = string;
char character = nzToLower(*str);
do
{
if (character == nzToLower(*c))
return str - m_sharedString->string;
}
while (*++c);
}
while (str-- != m_sharedString->string);
}
else
{
do
{
const char* c = string;
do
{
if (*str == *c)
return str - m_sharedString->string;
}
while (*++c);
}
while (str-- != m_sharedString->string);
}
}
return npos;
}
unsigned int NzString::FindLastAny(const NzString& string, int start, nzUInt32 flags) const
{
return FindLastAny(string.m_sharedString->string, start, flags);
}
unsigned int NzString::FindLastWord(const char* string, int start, nzUInt32 flags) const
{
if (!string || !string[0] || m_sharedString->size == 0)
return npos;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
///Algo 2.FindLastWord#1 (Taille du pattern inconnue)
const char* ptr = &m_sharedString->string[pos];
if (flags & HandleUtf8)
{
if (utf8::internal::is_trail(*ptr))
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
utf8::unchecked::iterator<const char*> it(ptr);
if (flags & CaseInsensitive)
{
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (NzUnicode::GetLowercase(*it) == c)
{
if (it.base() != m_sharedString->string)
{
it--;
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
continue;
}
utf8::unchecked::iterator<const char*> p(t);
utf8::unchecked::iterator<const char*> tIt = it;
++tIt;
while (true)
{
if (*p == '\0')
{
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
return it.base() - m_sharedString->string;
else
break;
}
if (tIt.base() > &m_sharedString->string[pos])
break;
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
break;
++p;
++tIt;
}
}
}
while (it--.base() != m_sharedString->string);
}
else
{
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
nzUInt32 c = utf8::unchecked::next(t);
do
{
if (*it == c)
{
if (it.base() != m_sharedString->string)
{
it--;
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
continue;
}
utf8::unchecked::iterator<const char*> p(t);
utf8::unchecked::iterator<const char*> tIt = it;
++tIt;
while (true)
{
if (*p == '\0')
{
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
return it.base() - m_sharedString->string;
else
break;
}
if (tIt.base() > &m_sharedString->string[pos])
break;
if (*tIt != *p)
break;
++p;
++tIt;
}
}
}
while (it--.base() != m_sharedString->string);
}
}
else
{
if (flags & CaseInsensitive)
{
char c = nzToLower(string[0]);
do
{
if (nzToLower(*ptr) == c)
{
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
continue;
const char* p = &string[1];
const char* tPtr = ptr+1;
while (true)
{
if (*p == '\0')
{
if (*tPtr == '\0' || std::isspace(*tPtr))
return ptr-m_sharedString->string;
else
break;
}
if (tPtr > &m_sharedString->string[pos])
break;
if (nzToLower(*tPtr) != nzToLower(*p))
break;
p++;
tPtr++;
}
}
}
while (ptr-- != m_sharedString->string);
}
else
{
do
{
if (*ptr == string[0])
{
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
continue;
const char* p = &string[1];
const char* tPtr = ptr+1;
while (true)
{
if (*p == '\0')
{
if (*tPtr == '\0' || std::isspace(*tPtr))
return ptr-m_sharedString->string;
else
break;
}
if (tPtr > &m_sharedString->string[pos])
break;
if (*tPtr != *p)
break;
p++;
tPtr++;
}
}
}
while (ptr-- != m_sharedString->string);
}
}
return npos;
}
unsigned int NzString::FindLastWord(const NzString& string, int start, nzUInt32 flags) const
{
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
return npos;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
const char* ptr = &m_sharedString->string[pos];
const char* limit = &m_sharedString->string[string.m_sharedString->size-1];
if (flags & HandleUtf8)
{
if (utf8::internal::is_trail(*ptr))
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
utf8::unchecked::iterator<const char*> it(ptr);
if (flags & CaseInsensitive)
{
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (NzUnicode::GetLowercase(*it) == c)
{
if (it.base() != m_sharedString->string)
{
it--;
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
continue;
}
utf8::unchecked::iterator<const char*> p(t);
utf8::unchecked::iterator<const char*> tIt = it;
++tIt;
while (true)
{
if (*p == '\0')
{
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
return it.base() - m_sharedString->string;
else
break;
}
if (tIt.base() > &m_sharedString->string[pos])
break;
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
break;
++p;
++tIt;
}
}
}
while (it--.base() != m_sharedString->string);
}
else
{
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
nzUInt32 c = utf8::unchecked::next(t);
do
{
if (*it == c)
{
if (it.base() != m_sharedString->string)
{
it--;
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
continue;
}
utf8::unchecked::iterator<const char*> p(t);
utf8::unchecked::iterator<const char*> tIt = it;
++tIt;
while (true)
{
if (*p == '\0')
{
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
return it.base() - m_sharedString->string;
else
break;
}
if (tIt.base() > &m_sharedString->string[pos])
break;
if (*tIt != *p)
break;
++p;
++tIt;
}
}
}
while (it--.base() != m_sharedString->string);
}
}
else
{
///Algo 2.FindLastWord#2 (Taille du pattern connue)
if (flags & CaseInsensitive)
{
char c = nzToLower(string.m_sharedString->string[string.m_sharedString->size-1]);
do
{
if (nzToLower(*ptr) == c)
{
if (*(ptr+1) != '\0' && !std::isspace(*(ptr+1)))
continue;
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
{
if (nzToLower(*ptr) != nzToLower(*p))
break;
if (p == &string.m_sharedString->string[0])
{
if (ptr == m_sharedString->string || std::isspace(*(ptr-1)))
return ptr-m_sharedString->string;
else
break;
}
if (ptr == m_sharedString->string)
return npos;
}
}
}
while (ptr-- > limit);
}
else
{
do
{
if (*ptr == string.m_sharedString->string[string.m_sharedString->size-1])
{
if (*(ptr+1) != '\0' && !std::isspace(*(ptr+1)))
continue;
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
{
if (*ptr != *p)
break;
if (p == &string.m_sharedString->string[0])
{
if (ptr == m_sharedString->string || std::isspace(*(ptr-1)))
return ptr-m_sharedString->string;
else
break;
}
if (ptr == m_sharedString->string)
return npos;
}
}
}
while (ptr-- > limit);
}
}
return npos;
}
unsigned int NzString::FindWord(const char* string, int start, nzUInt32 flags) const
{
if (!string || !string[0] || m_sharedString->size == 0)
return npos;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
///Algo 3.FindWord#3 (Taille du pattern inconnue)
const char* ptr = m_sharedString->string;
if (flags & HandleUtf8)
{
if (utf8::internal::is_trail(*ptr))
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
utf8::unchecked::iterator<const char*> it(ptr);
if (flags & CaseInsensitive)
{
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (*it == c)
{
if (it.base() != m_sharedString->string)
{
it--;
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
continue;
}
utf8::unchecked::iterator<const char*> p(t);
utf8::unchecked::iterator<const char*> tIt = it;
++tIt;
while (true)
{
if (*p == '\0')
{
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
return it.base() - m_sharedString->string;
else
break;
}
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
break;
p++;
tIt++;
}
}
}
while (*++ptr);
}
else
{
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (*it == c)
{
if (it.base() != m_sharedString->string)
{
it--;
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
continue;
}
utf8::unchecked::iterator<const char*> p(t);
utf8::unchecked::iterator<const char*> tIt = it;
++tIt;
while (true)
{
if (*p == '\0')
{
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
return it.base() - m_sharedString->string;
else
break;
}
if (*tIt != *p)
break;
p++;
tIt++;
}
}
}
while (*++ptr);
}
}
else
{
if (flags & CaseInsensitive)
{
char c = nzToLower(string[0]);
do
{
if (nzToLower(*ptr) == c)
{
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
continue;
const char* p = &string[1];
const char* tPtr = ptr+1;
while (true)
{
if (*p == '\0')
{
if (*tPtr == '\0' || std::isspace(*tPtr))
return ptr - m_sharedString->string;
else
break;
}
if (nzToLower(*tPtr) != nzToLower(*p))
break;
p++;
tPtr++;
}
}
}
while (*++ptr);
}
else
{
do
{
if (*ptr == string[0])
{
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
continue;
const char* p = &string[1];
const char* tPtr = ptr+1;
while (true)
{
if (*p == '\0')
{
if (*tPtr == '\0' || std::isspace(*tPtr))
return ptr - m_sharedString->string;
else
break;
}
if (*tPtr != *p)
break;
p++;
tPtr++;
}
}
}
while (*++ptr);
}
}
return npos;
}
unsigned int NzString::FindWord(const NzString& string, int start, nzUInt32 flags) const
{
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
return npos;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
char* ptr = m_sharedString->string;
if (flags & HandleUtf8)
{
///Algo 3.FindWord#3 (Itérateur trop lent pour #2)
if (utf8::internal::is_trail(*ptr))
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
utf8::unchecked::iterator<const char*> it(ptr);
if (flags & CaseInsensitive)
{
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (*it == c)
{
if (it.base() != m_sharedString->string)
{
it--;
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
continue;
}
utf8::unchecked::iterator<const char*> p(t);
utf8::unchecked::iterator<const char*> tIt = it;
++tIt;
while (true)
{
if (*p == '\0')
{
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
return it.base() - m_sharedString->string;
else
break;
}
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
break;
p++;
tIt++;
}
}
}
while (*++ptr);
}
else
{
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
do
{
if (*it == c)
{
if (it.base() != m_sharedString->string)
{
it--;
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
continue;
}
utf8::unchecked::iterator<const char*> p(t);
utf8::unchecked::iterator<const char*> tIt = it;
++tIt;
while (true)
{
if (*p == '\0')
{
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
return it.base() - m_sharedString->string;
else
break;
}
if (*tIt != *p)
break;
p++;
tIt++;
}
}
}
while (*++ptr);
}
}
else
{
///Algo 3.FindWord#2 (Taille du pattern connue)
if (flags & CaseInsensitive)
{
char c = nzToLower(string.m_sharedString->string[0]);
do
{
if (nzToLower(*ptr) == c)
{
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
continue;
const char* p = &string.m_sharedString->string[1];
const char* tPtr = ptr+1;
while (true)
{
if (*p == '\0')
{
if (*tPtr == '\0' || std::isspace(*tPtr))
return ptr - m_sharedString->string;
else
break;
}
if (nzToLower(*tPtr) != nzToLower(*p))
break;
p++;
tPtr++;
}
}
}
while (*++ptr);
}
else
{
while ((ptr = std::strstr(ptr, string.m_sharedString->string)))
{
// Si le mot est bien isolé
if ((ptr == m_sharedString->string || std::isspace(*(ptr-1))) && (*(ptr+m_sharedString->size) == '\0' || std::isspace(*(ptr+m_sharedString->size))))
return ptr - m_sharedString->string;
ptr++;
}
}
}
return npos;
}
char* NzString::GetBuffer()
{
EnsureOwnership();
return m_sharedString->string;
}
unsigned int NzString::GetCapacity() const
{
return m_sharedString->capacity;
}
const char* NzString::GetConstBuffer() const
{
return m_sharedString->string;
}
unsigned int NzString::GetLength() const
{
return utf8::distance(m_sharedString->string, &m_sharedString->string[m_sharedString->size]);
}
unsigned int NzString::GetSize() const
{
return m_sharedString->size;
}
std::string NzString::GetUtf8String() const
{
return std::string(m_sharedString->string, m_sharedString->size);
}
std::u16string NzString::GetUtf16String() const
{
if (m_sharedString->size == 0)
return std::u16string();
std::u16string str;
str.reserve(m_sharedString->size);
utf8::utf8to16(begin(), end(), std::back_inserter(str));
return str;
}
std::u32string NzString::GetUtf32String() const
{
if (m_sharedString->size == 0)
return std::u32string();
std::u32string str;
str.reserve(m_sharedString->size);
utf8::utf8to32(begin(), end(), std::back_inserter(str));
return str;
}
std::wstring NzString::GetWideString() const
{
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "wchar_t size is not supported");
if (m_sharedString->size == 0)
return std::wstring();
std::wstring str;
str.reserve(m_sharedString->size);
if (sizeof(wchar_t) == 4) // Je veux du static_if :(
utf8::utf8to32(begin(), end(), std::back_inserter(str));
else
{
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
do
{
char32_t cp = *it;
if (cp <= 0xFFFF && (cp < 0xD800 || cp > 0xDFFF)) // @Laurent Gomila
str.push_back(static_cast<wchar_t>(cp));
else
str.push_back(L'?');
}
while (*it++);
}
return str;
}
NzString NzString::GetWord(unsigned int index, nzUInt32 flags) const
{
unsigned int startPos = GetWordPosition(index, flags);
if (startPos == npos)
return NzString();
int endPos = -1;
const char* ptr = &m_sharedString->string[startPos];
if (flags & HandleUtf8)
{
utf8::unchecked::iterator<const char*> it(ptr);
do
{
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
{
endPos = static_cast<int>(it.base() - m_sharedString->string - 1);
break;
}
}
while (*++it);
}
else
{
do
{
if (std::isspace(*ptr))
{
endPos = static_cast<int>(ptr - m_sharedString->string - 1);
break;
}
}
while (*++ptr);
}
return SubString(startPos, endPos);
}
unsigned int NzString::GetWordPosition(unsigned int index, nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return npos;
unsigned int currentWord = 0;
bool inWord = false;
const char* ptr = m_sharedString->string;
if (flags & HandleUtf8)
{
utf8::unchecked::iterator<const char*> it(ptr);
do
{
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
inWord = false;
else
{
if (!inWord)
{
inWord = true;
if (++currentWord > index)
return static_cast<unsigned int>(it.base() - m_sharedString->string);
}
}
}
while (*++it);
}
else
{
do
{
if (std::isspace(*ptr))
inWord = false;
else
{
if (!inWord)
{
inWord = true;
if (++currentWord > index)
return ptr - m_sharedString->string;
}
}
}
while (*++ptr);
}
return npos;
}
NzString& NzString::Insert(int pos, char character)
{
return Insert(pos, &character, 1);
}
NzString& NzString::Insert(int pos, const char* string)
{
return Insert(pos, string, std::strlen(string));
}
NzString& NzString::Insert(int pos, const char* string, unsigned int length)
{
if (length == 0)
return *this;
if (pos < 0)
pos = std::max(m_sharedString->size + pos, 0U);
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedString->size);
// Si le buffer est déjà suffisamment grand
if (m_sharedString->capacity >= m_sharedString->size + length)
{
EnsureOwnership();
std::memmove(&m_sharedString->string[start+length], &m_sharedString->string[start], m_sharedString->size - start);
std::memcpy(&m_sharedString->string[start], string, length);
m_sharedString->size += length;
m_sharedString->string[m_sharedString->size] = '\0';
}
else
{
unsigned int newSize = m_sharedString->size + length;
char* newString = new char[newSize+1];
char* ptr = newString;
if (start > 0)
{
std::memcpy(ptr, m_sharedString->string, start*sizeof(char));
ptr += start;
}
std::memcpy(ptr, string, length*sizeof(char));
ptr += length;
if (m_sharedString->size > start)
std::memcpy(ptr, &m_sharedString->string[start], m_sharedString->size - start + 1);
else
*ptr = '\0';
ReleaseString();
m_sharedString = new SharedString;
m_sharedString->capacity = newSize;
m_sharedString->size = newSize;
m_sharedString->string = newString;
}
return *this;
}
NzString& NzString::Insert(int pos, const NzString& string)
{
return Insert(pos, string.m_sharedString->string, string.m_sharedString->size);
}
bool NzString::IsEmpty() const
{
return m_sharedString->size == 0;
}
bool NzString::IsNull() const
{
return m_sharedString == &emptyString;
}
bool NzString::IsNumber(nzUInt8 base, nzUInt32 flags) const
{
#if NAZARA_CORE_SAFE
if (base < 2 || base > 36)
{
NazaraError("Base must be between 2 and 36");
return false;
}
#endif
if (m_sharedString->size == 0)
return false;
NzString check = Simplified();
if (check.m_sharedString->size == 0)
return false;
char* ptr = (check.m_sharedString->string[0] == '-') ? &check.m_sharedString->string[1] : check.m_sharedString->string;
if (base > 10)
{
if (flags & CaseInsensitive)
{
char limitLower = 'a' + base-10 - 1;
char limitUpper = 'A' + base-10 - 1;
do
{
char c = *ptr;
if (c != ' ' && (c < '0' || (c > '9' && c < 'A') || (c > limitUpper && c < 'a') || c > limitLower))
return false;
}
while (*++ptr);
}
else
{
char limit = 'a' + base-10 - 1;
do
{
char c = *ptr;
if (c != ' ' && (c < '0' || (c > '9' && c < 'a') || c > limit))
return false;
}
while (*++ptr);
}
}
else
{
char limit = '0' + base - 1;
do
{
char c = *ptr;
if (c != ' ' && (c < '0' || c > limit))
return false;
}
while (*++ptr);
}
return true;
}
bool NzString::Match(const char* pattern) const
{
if (m_sharedString->size == 0 || !pattern)
return false;
// Par Jack Handy - akkhandy@hotmail.com
// From : http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing
const char* str = m_sharedString->string;
while (*str && *pattern != '*')
{
if (*pattern != *str && *pattern != '?')
return false;
pattern++;
str++;
}
const char* cp = nullptr;
const char* mp = nullptr;
while (*str)
{
if (*pattern == '*')
{
if (!*++pattern)
return true;
mp = pattern;
cp = str+1;
}
else if (*pattern == *str || *pattern == '?')
{
pattern++;
str++;
}
else
{
pattern = mp;
str = cp++;
}
}
while (*pattern == '*')
pattern++;
return !*pattern;
}
bool NzString::Match(const NzString& pattern) const
{
return Match(pattern.m_sharedString->string);
}
NzString& NzString::Prepend(char character)
{
return Insert(0, character);
}
NzString& NzString::Prepend(const char* string)
{
return Insert(0, string);
}
NzString& NzString::Prepend(const char* string, unsigned int length)
{
return Insert(0, string, length);
}
NzString& NzString::Prepend(const NzString& string)
{
return Insert(0, string);
}
unsigned int NzString::Replace(char oldCharacter, char newCharacter, int start, nzUInt32 flags)
{
if (oldCharacter == '\0' || oldCharacter == newCharacter)
return 0;
if (newCharacter == '\0') // Dans ce cas, il faut passer par un algorithme plus complexe
return Replace(NzString(oldCharacter), NzString(), start);
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
unsigned int count = 0;
char* ptr = &m_sharedString->string[pos];
bool found = false;
if (flags & CaseInsensitive)
{
char character_lower = nzToLower(oldCharacter);
char character_upper = nzToUpper(oldCharacter);
do
{
if (*ptr == character_lower || *ptr == character_upper)
{
if (!found)
{
unsigned int offset = ptr-m_sharedString->string;
EnsureOwnership();
ptr = &m_sharedString->string[offset];
found = true;
}
*ptr = newCharacter;
++count;
}
}
while (*++ptr);
}
else
{
while ((ptr = std::strchr(ptr, oldCharacter)))
{
if (!found)
{
unsigned int offset = ptr-m_sharedString->string;
EnsureOwnership();
ptr = &m_sharedString->string[offset];
found = true;
}
*ptr = newCharacter;
++count;
}
}
return count;
}
unsigned int NzString::Replace(const char* oldString, const char* replaceString, int start, nzUInt32 flags)
{
return Replace(oldString, std::strlen(oldString), replaceString, std::strlen(replaceString), start, flags);
}
unsigned int NzString::Replace(const char* oldString, unsigned int oldLength, const char* replaceString, unsigned int replaceLength, int start, nzUInt32 flags)
{
if (oldLength == 0)
return 0;
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return 0;
unsigned int count = 0;
if (oldLength == replaceLength)
{
bool found = false;
// Si aucun changement de taille n'est nécessaire, nous pouvons alors utiliser un algorithme bien plus rapide
while ((pos = Find(oldString, pos, flags)) != npos)
{
if (!found)
{
EnsureOwnership();
found = true;
}
std::memcpy(&m_sharedString->string[pos], replaceString, oldLength);
pos += oldLength;
++count;
}
}
else ///TODO: Algorithme de remplacement sans changement de buffer (si replaceLength < oldLength)
{
unsigned int newSize = m_sharedString->size + Count(oldString)*(replaceLength - oldLength);
if (newSize == m_sharedString->size) // Alors c'est que Count(oldString) == 0
return 0;
char* newString = new char[newSize+1];
///Algo 4.Replace#2
char* ptr = newString;
const char* p = m_sharedString->string;
while ((pos = Find(oldString, pos, flags)) != npos)
{
const char* r = &m_sharedString->string[pos];
std::memcpy(ptr, p, r-p);
ptr += r-p;
std::memcpy(ptr, replaceString, replaceLength);
ptr += replaceLength;
p = r+oldLength;
pos += oldLength;
count++;
}
std::strcpy(ptr, p); // Ajoute le caractère de fin par la même occasion
ReleaseString();
m_sharedString = new SharedString;
m_sharedString->capacity = newSize;
m_sharedString->size = newSize;
m_sharedString->string = newString;
}
return count;
}
unsigned int NzString::Replace(const NzString& oldString, const NzString& replaceString, int start, nzUInt32 flags)
{
return Replace(oldString.m_sharedString->string, oldString.m_sharedString->size, replaceString.m_sharedString->string, replaceString.m_sharedString->size, start, flags);
}
unsigned int NzString::ReplaceAny(const char* oldCharacters, char replaceCharacter, int start, nzUInt32 flags)
{
///FIXME: Ne gère pas l'UTF-8
if (!oldCharacters || !oldCharacters[0])
return 0;
/*if (replaceCharacter == '\0') // Dans ce cas, il faut passer par un algorithme plus complexe
return ReplaceAny(NzString(oldCharacters), NzString(), start);*/
if (start < 0)
start = std::max(m_sharedString->size + start, 0U);
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size)
return npos;
unsigned int count = 0;
char* ptr = &m_sharedString->string[pos];
if (flags & CaseInsensitive)
{
do
{
const char* c = oldCharacters;
char character = nzToLower(*ptr);
bool found = false;
do
{
if (character == nzToLower(*c))
{
if (!found)
{
unsigned int offset = ptr-m_sharedString->string;
EnsureOwnership();
ptr = &m_sharedString->string[offset];
found = true;
}
*ptr = replaceCharacter;
++count;
break;
}
}
while (*++c);
}
while (*++ptr);
}
else
{
bool found = false;
while ((ptr = std::strpbrk(ptr, oldCharacters)))
{
if (!found)
{
unsigned int offset = ptr-m_sharedString->string;
EnsureOwnership();
ptr = &m_sharedString->string[offset];
found = true;
}
*ptr++ = replaceCharacter;
++count;
}
}
return count;
}
/*
unsigned int NzString::ReplaceAny(const char* oldCharacters, const char* replaceString, int start, nzUInt32 flags)
{
if (start < 0)
{
start = m_sharedString->size+start;
if (start < 0)
start = 0;
}
unsigned int pos = static_cast<unsigned int>(start);
unsigned int oSize = (oldCharacters) ? std::strlen(oldCharacters) : 0;
unsigned int rSize = (replaceString) ? std::strlen(replaceString) : 0;
if (pos >= m_sharedString->size || m_sharedString->size == 0 || oSize == 0)
return 0;
unsigned int count = 0;
if (rSize == 1) // On utilise un algorithme optimisé
{
EnsureOwnership();
f or (; pos < m_sharedString->size; ++pos)
{
for (unsigned int i = 0; i < oSize; ++i)
{
if (m_sharedString->string[pos] == oldCharacters[i])
{
m_sharedString->string[pos] = replaceString[0];
++count;
break;
}
}
}
}
else
{
unsigned int newSize;
{
unsigned int count = CountAny(oldCharacters);
newSize = m_sharedString->size - count + count*rSize;
}
char* newString = new char[newSize+1];
unsigned int j = 0;
for (unsigned int i = 0; i < m_sharedString->size; ++i)
{
if (i < pos) // Avant la position où on est censé commencer à remplacer, on ne fait que recopier
newString[j++] = m_sharedString->string[i];
else
{
bool found = false;
for (unsigned int l = 0; l < oSize; ++l)
{
if (m_sharedString->string[i] == oldCharacters[l])
{
for (unsigned int k = 0; k < rSize; ++k)
newString[j++] = replaceString[k];
++count;
found = true;
break; // Simple façon d'éviter la ligne après la boucle
}
}
if (!found)
newString[j++] = m_sharedString->string[i];
}
}
newString[newSize] = '\0';
ReleaseString();
m_sharedString->size = newSize;
m_sharedString->string = newString;
}
return count;
}
unsigned int NzString::ReplaceAny(const NzString& oldCharacters, const NzString& replaceString, int start, nzUInt32 flags)
{
if (start < 0)
{
start = m_sharedString->size+start;
if (start < 0)
start = 0;
}
unsigned int pos = static_cast<unsigned int>(start);
if (pos >= m_sharedString->size || m_sharedString->size == 0 || oldCharacters.m_sharedString->size == 0)
return 0;
unsigned int count = 0;
if (replaceString.m_sharedString->size == 1) // On utilise un algorithme optimisé
{
EnsureOwnership();
char character = replaceString[0];
for (; pos < m_sharedString->size; ++pos)
{
for (unsigned int i = 0; i < oldCharacters.m_sharedString->size; ++i)
{
if (m_sharedString->string[pos] == oldCharacters[i])
{
m_sharedString->string[pos] = character;
++count;
break;
}
}
}
}
else
{
unsigned int newSize;
{
unsigned int count = CountAny(oldCharacters);
newSize = m_sharedString->size - count + count*replaceString.m_sharedString->size;
}
char* newString = new char[newSize+1];
unsigned int j = 0;
for (unsigned int i = 0; i < m_sharedString->size; ++i)
{
if (i < pos) // Avant la position où on est censé commencer à remplacer, on ne fait que recopier
newString[j++] = m_sharedString->string[i];
else
{
bool found = false;
for (unsigned int l = 0; l < oldCharacters.m_sharedString->size; ++l)
{
if (m_sharedString->string[i] == oldCharacters[l])
{
for (unsigned int k = 0; k < replaceString.m_sharedString->size; ++k)
newString[j++] = replaceString[k];
++count;
found = true;
break; // Simple façon d'éviter la ligne après la boucle
}
}
if (!found)
newString[j++] = m_sharedString->string[i];
}
}
newString[newSize] = '\0';
ReleaseString();
m_sharedString->size = newSize;
m_sharedString->string = newString;
}
return count;
}
*/
void NzString::Reserve(unsigned int bufferSize)
{
if (m_sharedString->capacity >= bufferSize)
return;
char* ptr = new char[bufferSize+1];
if (m_sharedString->size > 0)
std::memcpy(ptr, m_sharedString->string, m_sharedString->size+1);
unsigned int size = m_sharedString->size;
ReleaseString();
m_sharedString = new SharedString;
m_sharedString->capacity = bufferSize;
m_sharedString->size = size;
m_sharedString->string = ptr;
}
NzString& NzString::Resize(int size, char character)
{
if (size == 0)
{
Clear(true);
return *this;
}
if (size < 0)
size = std::max(m_sharedString->size + size, 0U);
unsigned int newSize = static_cast<unsigned int>(size);
if (m_sharedString->capacity >= newSize)
{
EnsureOwnership();
// Nous avons déjà la place requise, contentons-nous de remplir le buffer
if (character != '\0' && newSize > m_sharedString->size)
std::memset(&m_sharedString->string[m_sharedString->size], character, newSize-m_sharedString->size);
m_sharedString->size = newSize;
}
else // On veut forcément agrandir la chaine
{
char* newString = new char[newSize+1];
std::memcpy(newString, m_sharedString->string, m_sharedString->size);
if (character != '\0')
std::memset(&newString[m_sharedString->size], character, newSize-m_sharedString->size);
ReleaseString();
m_sharedString = new SharedString;
m_sharedString->capacity = newSize;
m_sharedString->size = newSize;
m_sharedString->string = newString;
}
// On rajoute le caractère de fin
m_sharedString->string[newSize] = '\0';
return *this;
}
NzString NzString::Resized(int size, char character) const
{
if (size < 0)
size = m_sharedString->size + size;
if (size <= 0)
return NzString();
unsigned int newSize = static_cast<unsigned int>(size);
if (newSize == m_sharedString->size)
return *this;
char* str = new char[newSize+1];
if (newSize > m_sharedString->size)
{
std::memcpy(str, m_sharedString->string, m_sharedString->size);
if (character != '\0')
std::memset(&str[m_sharedString->size], character, newSize-m_sharedString->size);
}
else
std::memcpy(str, m_sharedString->string, newSize);
str[newSize] = '\0';
return NzString(new SharedString(1, newSize, newSize, str));
}
NzString& NzString::Reverse()
{
if (m_sharedString->size != 0)
{
unsigned int i = 0;
unsigned int j = m_sharedString->size-1;
while (i < j)
std::swap(m_sharedString->string[i++], m_sharedString->string[j--]);
}
return *this;
}
NzString NzString::Reversed() const
{
if (m_sharedString->size == 0)
return NzString();
char* str = new char[m_sharedString->size+1];
char* ptr = &str[m_sharedString->size-1];
char* p = m_sharedString->string;
do
*ptr-- = *p;
while (*(++p));
str[m_sharedString->size] = '\0';
return NzString(new SharedString(1, m_sharedString->size, m_sharedString->size, str));
}
NzString& NzString::Set(char character)
{
if (character != '\0')
{
if (m_sharedString->capacity >= 1)
EnsureOwnership(true);
else
{
ReleaseString();
m_sharedString = new SharedString;
m_sharedString->capacity = 1;
m_sharedString->string = new char[2];
}
m_sharedString->size = 1;
m_sharedString->string[0] = character;
m_sharedString->string[1] = '\0';
}
else
ReleaseString();
return *this;
}
NzString& NzString::Set(unsigned int rep, char character)
{
if (rep > 0)
{
if (m_sharedString->capacity >= rep)
EnsureOwnership(true);
else
{
ReleaseString();
m_sharedString = new SharedString;
m_sharedString->capacity = rep;
m_sharedString->string = new char[rep+1];
}
m_sharedString->size = rep;
if (character != '\0')
std::memset(m_sharedString->string, character, rep);
m_sharedString->string[rep] = '\0';
}
else
ReleaseString();
return *this;
}
NzString& NzString::Set(unsigned int rep, const char* string)
{
return Set(rep, string, (string) ? std::strlen(string) : 0);
}
NzString& NzString::Set(unsigned int rep, const char* string, unsigned int length)
{
unsigned int totalSize = rep*length;
if (totalSize > 0)
{
if (m_sharedString->capacity >= totalSize)
EnsureOwnership(true);
else
{
ReleaseString();
m_sharedString = new SharedString;
m_sharedString->capacity = totalSize;
m_sharedString->string = new char[totalSize+1];
}
m_sharedString->size = totalSize;
for (unsigned int i = 0; i < rep; ++i)
std::memcpy(&m_sharedString->string[i*length], string, length);
m_sharedString->string[totalSize] = '\0';
}
else
ReleaseString();
return *this;
}
NzString& NzString::Set(unsigned int rep, const NzString& string)
{
return Set(rep, string.m_sharedString->string, string.m_sharedString->size);
}
NzString& NzString::Set(const char* string)
{
return Set(string, (string) ? std::strlen(string) : 0);
}
NzString& NzString::Set(const char* string, unsigned int length)
{
if (length > 0)
{
if (m_sharedString->capacity >= length)
EnsureOwnership(true);
else
{
ReleaseString();
m_sharedString = new SharedString;
m_sharedString->capacity = length;
m_sharedString->string = new char[length+1];
}
m_sharedString->size = length;
std::memcpy(m_sharedString->string, string, length);
m_sharedString->string[length] = '\0';
}
else
ReleaseString();
return *this;
}
NzString& NzString::Set(const std::string& string)
{
return Set(string.data(), string.size());
}
NzString& NzString::Set(const NzString& string)
{
if (this != &string)
{
ReleaseString();
m_sharedString = string.m_sharedString;
if (m_sharedString != &emptyString)
m_sharedString->refCount++;
}
return *this;
}
NzString& NzString::Set(NzString&& string) noexcept
{
std::swap(m_sharedString, string.m_sharedString);
return *this;
}
NzString& NzString::Set(SharedString* sharedString)
{
ReleaseString();
m_sharedString = sharedString;
return *this;
}
NzString NzString::Simplified(nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return NzString();
char* str = new char[m_sharedString->size+1];
char* p = str;
const char* ptr = m_sharedString->string;
bool inword = false;
if (flags & HandleUtf8)
{
utf8::unchecked::iterator<const char*> it(ptr);
do
{
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
{
if (inword)
{
*p++ = ' ';
inword = false;
}
}
else
{
p = utf8::append(*it, p);
inword = true;
}
}
while (*++it);
}
else
{
const char* limit = &m_sharedString->string[m_sharedString->size];
do
{
if (std::isspace(*ptr))
{
if (inword)
{
*p++ = ' ';
inword = false;
}
}
else
{
*p++ = *ptr;
inword = true;
}
}
while (++ptr != limit);
}
if (!inword && p != str)
p--;
*p = '\0';
return NzString(new SharedString(1, m_sharedString->size, p-str, str));
}
NzString& NzString::Simplify(nzUInt32 flags)
{
return Set(Simplified(flags));
}
unsigned int NzString::Split(std::vector<NzString>& result, char separation, int start, nzUInt32 flags) const
{
if (separation == '\0' || m_sharedString->size == 0)
return 0;
unsigned int lastSep = Find(separation, start, flags);
if (lastSep == npos)
{
result.push_back(*this);
return 1;
}
else if (lastSep != 0)
result.push_back(SubString(0, lastSep-1));
while (true)
{
unsigned int sep = Find(separation, lastSep+1, flags);
if (sep == npos)
break;
if (sep-lastSep > 1)
result.push_back(SubString(lastSep+1, sep-1));
lastSep = sep;
}
if (lastSep != m_sharedString->size-1)
result.push_back(SubString(lastSep+1));
return result.size();
}
unsigned int NzString::Split(std::vector<NzString>& result, const char* separation, int start, nzUInt32 flags) const
{
return Split(result, separation, std::strlen(separation), start, flags);
}
unsigned int NzString::Split(std::vector<NzString>& result, const char* separation, unsigned int length, int start, nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return 0;
else if (length == 0)
{
result.reserve(m_sharedString->size);
for (unsigned int i = 0; i < m_sharedString->size; ++i)
result.push_back(NzString(m_sharedString->string[i]));
return m_sharedString->size;
}
else if (length > m_sharedString->size)
{
result.push_back(*this);
return 1;
}
unsigned int lastSep = Find(separation, start, flags);
unsigned int oldSize = result.size();
if (lastSep == npos)
{
result.push_back(*this);
return 1;
}
else if (lastSep != 0)
result.push_back(SubString(0, lastSep-1));
unsigned int sep;
while ((sep = Find(separation, lastSep + length, flags)) != npos)
{
if (sep-lastSep > length)
result.push_back(SubString(lastSep + length, sep-1));
lastSep = sep;
}
if (lastSep != m_sharedString->size - length)
result.push_back(SubString(lastSep + length));
return result.size()-oldSize;
}
unsigned int NzString::Split(std::vector<NzString>& result, const NzString& separation, int start, nzUInt32 flags) const
{
return Split(result, separation.m_sharedString->string, separation.m_sharedString->size, start, flags);
}
unsigned int NzString::SplitAny(std::vector<NzString>& result, const char* separations, int start, nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return 0;
unsigned int oldSize = result.size();
unsigned int lastSep = FindAny(separations, start, flags);
if (lastSep == npos)
{
result.push_back(*this);
return 1;
}
else if (lastSep != 0)
result.push_back(SubString(0, lastSep-1));
unsigned int sep;
while ((sep = FindAny(separations, lastSep+1, flags)) != npos)
{
if (sep-lastSep > 1)
result.push_back(SubString(lastSep+1, sep-1));
lastSep = sep;
}
if (lastSep != m_sharedString->size-1)
result.push_back(SubString(lastSep+1));
return result.size()-oldSize;
}
unsigned int NzString::SplitAny(std::vector<NzString>& result, const NzString& separations, int start, nzUInt32 flags) const
{
return SplitAny(result, separations.m_sharedString->string, start, flags);
}
bool NzString::StartsWith(char character, nzUInt32 flags) const
{
if (character == '\0' || m_sharedString->size == 0)
return false;
if (flags & CaseInsensitive)
return nzToLower(m_sharedString->string[0]) == nzToLower(character);
else
return m_sharedString->string[0] == character;
}
bool NzString::StartsWith(const char* string, nzUInt32 flags) const
{
if (!string || !string[0] || m_sharedString->size == 0)
return false;
if (flags & CaseInsensitive)
{
if (flags & HandleUtf8)
{
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
utf8::unchecked::iterator<const char*> it2(string);
do
{
if (*it2 == '\0')
return true;
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
return false;
++it2;
}
while (*it++);
}
else
{
char* ptr = m_sharedString->string;
const char* s = string;
do
{
if (*s == '\0')
return true;
if (nzToLower(*ptr) != nzToLower(*s))
return false;
s++;
}
while (*ptr++);
}
}
else
{
char* ptr = m_sharedString->string;
const char* s = string;
do
{
if (*s == '\0')
return true;
if (*ptr != *s)
return false;
s++;
}
while (*ptr++);
}
return false;
}
bool NzString::StartsWith(const NzString& string, nzUInt32 flags) const
{
if (string.m_sharedString->size == 0)
return false;
if (m_sharedString->size < string.m_sharedString->size)
return false;
if (flags & CaseInsensitive)
{
if (flags & HandleUtf8)
{
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
utf8::unchecked::iterator<const char*> it2(string.m_sharedString->string);
do
{
if (*it2 == '\0')
return true;
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
return false;
++it2;
}
while (*it++);
}
else
{
char* ptr = m_sharedString->string;
const char* s = string.m_sharedString->string;
do
{
if (*s == '\0')
return true;
if (nzToLower(*ptr) != nzToLower(*s))
return false;
s++;
}
while (*ptr++);
}
}
else
return std::memcmp(m_sharedString->string, string.m_sharedString->string, string.m_sharedString->size) == 0;
return false;
}
NzString NzString::SubString(int startPos, int endPos) const
{
if (startPos < 0)
startPos = std::max(m_sharedString->size+startPos, 0U);
unsigned int start = static_cast<unsigned int>(startPos);
if (endPos < 0)
{
endPos = m_sharedString->size+endPos;
if (endPos < 0)
return NzString();
}
unsigned int minEnd = std::min(static_cast<unsigned int>(endPos), m_sharedString->size-1);
if (start > minEnd || start >= m_sharedString->size)
return NzString();
unsigned int size = minEnd-start+1;
char* str = new char[size+1];
std::memcpy(str, &m_sharedString->string[start], size);
str[size] = '\0';
return NzString(new SharedString(1, size, size, str));
}
NzString NzString::SubStringFrom(char character, int startPos, bool fromLast, bool include, nzUInt32 flags) const
{
if (character == '\0')
return *this;
unsigned int pos;
if (fromLast)
pos = FindLast(character, startPos, flags);
else
pos = Find(character, startPos, flags);
if (pos == 0 && include)
return *this;
else if (pos == npos)
return NzString();
return SubString(pos + ((include) ? 0 : 1));
}
NzString NzString::SubStringFrom(const char* string, int startPos, bool fromLast, bool include, nzUInt32 flags) const
{
return SubStringFrom(string, std::strlen(string), startPos, fromLast, include, flags);
}
NzString NzString::SubStringFrom(const char* string, unsigned int length, int startPos, bool fromLast, bool include, nzUInt32 flags) const
{
unsigned int pos;
if (fromLast)
pos = FindLast(string, startPos, flags);
else
pos = Find(string, startPos, flags);
if (pos == 0 && include)
return *this;
else if (pos == npos)
return NzString();
return SubString(pos + ((include) ? 0 : length));
}
NzString NzString::SubStringFrom(const NzString& string, int startPos, bool fromLast, bool include, nzUInt32 flags) const
{
return SubStringFrom(string.m_sharedString->string, string.m_sharedString->size, startPos, fromLast, include, flags);
}
NzString NzString::SubStringTo(char character, int startPos, bool toLast, bool include, nzUInt32 flags) const
{
if (character == '\0')
return *this;
unsigned int pos;
if (toLast)
pos = FindLast(character, startPos);
else
pos = Find(character, startPos, flags);
if (pos == 0)
return (include) ? NzString(character) : NzString();
else if (pos == npos)
return *this;
return SubString(0, pos+((include) ? 1 : 0)-1);
}
NzString NzString::SubStringTo(const char* string, int startPos, bool toLast, bool include, nzUInt32 flags) const
{
return SubStringTo(string, std::strlen(string), startPos, toLast, include, flags);
}
NzString NzString::SubStringTo(const char* string, unsigned int length, int startPos, bool toLast, bool include, nzUInt32 flags) const
{
unsigned int pos;
if (toLast)
pos = FindLast(string, startPos, flags);
else
pos = Find(string, startPos, flags);
if (pos == 0)
return (include) ? string : NzString();
else if (pos == npos)
return *this;
return SubString(0, pos+((include) ? length : 0)-1);
}
NzString NzString::SubStringTo(const NzString& string, int startPos, bool toLast, bool include, nzUInt32 flags) const
{
return SubStringTo(string.m_sharedString->string, string.m_sharedString->size, startPos, toLast, include, flags);
}
void NzString::Swap(NzString& str)
{
std::swap(m_sharedString, str.m_sharedString);
}
bool NzString::ToBool(bool* value, nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return false;
NzString word = GetWord(0);
if (word[0] == '1')
{
if (value)
*value = true;
}
else if (word[0] == '0')
{
if (value)
*value = false;
}
else
{
if (flags & CaseInsensitive)
word = word.ToLower(); // Les mots identifiés sont en ASCII, inutile de passer le flag unicode
if (word == "true")
{
if (value)
*value = true;
}
else if (word == "false")
{
if (value)
*value = false;
}
else
return false;
}
return true;
}
bool NzString::ToDouble(double* value) const
{
if (m_sharedString->size == 0)
return false;
if (value)
*value = std::atof(m_sharedString->string);
return true;
}
bool NzString::ToInteger(long long* value, nzUInt8 base) const
{
if (value)
{
bool ok;
*value = NzStringToNumber(*this, base, &ok);
return ok;
}
else
return IsNumber(base);
}
NzString NzString::ToLower(nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return *this;
if (flags & HandleUtf8)
{
NzString lower;
lower.Reserve(m_sharedString->size);
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
do
utf8::append(NzUnicode::GetLowercase(*it), std::back_inserter(lower));
while (*++it);
return lower;
}
else
{
char* str = new char[m_sharedString->size+1];
char* ptr = m_sharedString->string;
char* s = str;
do
*s++ = nzToLower(*ptr);
while (*++ptr);
*s = '\0';
return NzString(new SharedString(1, m_sharedString->size, m_sharedString->size, str));
}
}
NzString NzString::ToUpper(nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return *this;
if (flags & HandleUtf8)
{
NzString upper;
upper.Reserve(m_sharedString->size);
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
do
utf8::append(NzUnicode::GetUppercase(*it), std::back_inserter(upper));
while (*++it);
return upper;
}
else
{
char* str = new char[m_sharedString->size+1];
char* ptr = m_sharedString->string;
char* s = str;
do
*s++ = nzToUpper(*ptr);
while (*++ptr);
*s = '\0';
return NzString(new SharedString(1, m_sharedString->size, m_sharedString->size, str));
}
}
NzString& NzString::Trim(nzUInt32 flags)
{
return Set(Trimmed(flags));
}
NzString& NzString::Trim(char character, nzUInt32 flags)
{
return Set(Trimmed(character, flags));
}
NzString NzString::Trimmed(nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return *this;
unsigned int startPos;
unsigned int endPos;
if (flags & HandleUtf8)
{
if ((flags & TrimOnlyRight) == 0)
{
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
do
{
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
break;
}
while (*++it);
startPos = it.base() - m_sharedString->string;
}
else
startPos = 0;
if ((flags & TrimOnlyLeft) == 0)
{
utf8::unchecked::iterator<const char*> it(&m_sharedString->string[m_sharedString->size]);
while ((it--).base() != m_sharedString->string)
{
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
break;
}
endPos = it.base() - m_sharedString->string;
}
else
endPos = m_sharedString->size-1;
}
else
{
startPos = 0;
if ((flags & TrimOnlyRight) == 0)
{
for (; startPos < m_sharedString->size; ++startPos)
{
if (!std::isspace(m_sharedString->string[startPos]))
break;
}
}
endPos = m_sharedString->size-1;
if ((flags & TrimOnlyLeft) == 0)
{
for (; endPos > 0; --endPos)
{
if (!std::isspace(m_sharedString->string[endPos]))
break;
}
}
}
return SubString(startPos, endPos);
}
NzString NzString::Trimmed(char character, nzUInt32 flags) const
{
if (m_sharedString->size == 0)
return *this;
unsigned int startPos = 0;
unsigned int endPos = m_sharedString->size-1;
if (flags & CaseInsensitive)
{
char ch = nzToLower(character);
if ((flags & TrimOnlyRight) == 0)
{
for (; startPos < m_sharedString->size; ++startPos)
{
if (nzToLower(m_sharedString->string[startPos]) != ch)
break;
}
}
if ((flags & TrimOnlyLeft) == 0)
{
for (; endPos > 0; --endPos)
{
if (nzToLower(m_sharedString->string[endPos]) != ch)
break;
}
}
}
else
{
if ((flags & TrimOnlyRight) == 0)
{
for (; startPos < m_sharedString->size; ++startPos)
{
if (m_sharedString->string[startPos] != character)
break;
}
}
if ((flags & TrimOnlyLeft) == 0)
{
for (; endPos > 0; --endPos)
{
if (m_sharedString->string[endPos] != character)
break;
}
}
}
return SubString(startPos, endPos);
}
char* NzString::begin()
{
return m_sharedString->string;
}
const char* NzString::begin() const
{
return m_sharedString->string;
}
char* NzString::end()
{
return &m_sharedString->string[m_sharedString->size];
}
const char* NzString::end() const
{
return &m_sharedString->string[m_sharedString->size];
}
void NzString::push_front(char c)
{
Prepend(c);
}
void NzString::push_back(char c)
{
Append(c);
}
/*
char* NzString::rbegin()
{
return &m_sharedString->string[m_sharedString->size-1];
}
const char* NzString::rbegin() const
{
return &m_sharedString->string[m_sharedString->size-1];
}
char* NzString::rend()
{
return &m_sharedString->string[-1];
}
const char* NzString::rend() const
{
return &m_sharedString->string[-1];
}
*/
NzString::operator std::string() const
{
return std::string(m_sharedString->string, m_sharedString->size);
}
char& NzString::operator[](unsigned int pos)
{
EnsureOwnership();
if (pos >= m_sharedString->size)
Resize(pos+1);
return m_sharedString->string[pos];
}
char NzString::operator[](unsigned int pos) const
{
#if NAZARA_CORE_SAFE
if (pos >= m_sharedString->size)
{
NazaraError("Index out of range (" + Number(pos) + " >= " + Number(m_sharedString->size) + ')');
return 0;
}
#endif
return m_sharedString->string[pos];
}
NzString& NzString::operator=(char character)
{
return Set(character);
}
NzString& NzString::operator=(const char* string)
{
return Set(string);
}
NzString& NzString::operator=(const std::string& string)
{
return Set(string);
}
NzString& NzString::operator=(const NzString& string)
{
return Set(string);
}
NzString& NzString::operator=(NzString&& string) noexcept
{
return Set(string);
}
NzString NzString::operator+(char character) const
{
if (character == '\0')
return *this;
unsigned int totalSize = m_sharedString->size+1;
char* str = new char[totalSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size);
str[m_sharedString->size] = character;
str[totalSize] = '\0';
return NzString(new SharedString(1, totalSize, totalSize, str));
}
NzString NzString::operator+(const char* string) const
{
if (!string || !string[0])
return *this;
if (m_sharedString->size == 0)
return string;
unsigned int length = std::strlen(string);
if (length == 0)
return *this;
unsigned int totalSize = m_sharedString->size + length;
char* str = new char[totalSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::memcpy(&str[m_sharedString->size], string, length+1);
return NzString(new SharedString(1, totalSize, totalSize, str));
}
NzString NzString::operator+(const std::string& string) const
{
if (string.empty())
return *this;
if (m_sharedString->size == 0)
return string;
unsigned int totalSize = m_sharedString->size + string.size();
char* str = new char[totalSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::memcpy(&str[m_sharedString->size], string.c_str(), string.size()+1);
return NzString(new SharedString(1, totalSize, totalSize, str));
}
NzString NzString::operator+(const NzString& string) const
{
if (string.m_sharedString->size == 0)
return *this;
if (m_sharedString->size == 0)
return string;
unsigned int totalSize = m_sharedString->size + string.m_sharedString->size;
char* str = new char[totalSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::memcpy(&str[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
return NzString(new SharedString(1, totalSize, totalSize, str));
}
NzString& NzString::operator+=(char character)
{
return Insert(m_sharedString->size, character);
}
NzString& NzString::operator+=(const char* string)
{
return Insert(m_sharedString->size, string);
}
NzString& NzString::operator+=(const std::string& string)
{
return Insert(m_sharedString->size, string.c_str(), string.size());
}
NzString& NzString::operator+=(const NzString& string)
{
return Insert(m_sharedString->size, string);
}
bool NzString::operator==(char character) const
{
if (m_sharedString->size == 0)
return character == '\0';
if (m_sharedString->size > 1)
return false;
return m_sharedString->string[0] == character;
}
bool NzString::operator==(const char* string) const
{
if (m_sharedString->size == 0)
return !string || !string[0];
if (!string || !string[0])
return false;
return std::strcmp(m_sharedString->string, string) == 0;
}
bool NzString::operator==(const std::string& string) const
{
if (m_sharedString->size == 0 || string.empty())
return m_sharedString->size == string.size();
if (m_sharedString->size != string.size())
return false;
return std::strcmp(m_sharedString->string, string.c_str()) == 0;
}
bool NzString::operator!=(char character) const
{
if (m_sharedString->size == 0)
return character != '\0';
if (character == '\0' || m_sharedString->size != 1)
return true;
if (m_sharedString->size != 1)
return true;
return m_sharedString->string[0] != character;
}
bool NzString::operator!=(const char* string) const
{
if (m_sharedString->size == 0)
return string && string[0];
if (!string || !string[0])
return true;
return std::strcmp(m_sharedString->string, string) != 0;
}
bool NzString::operator!=(const std::string& string) const
{
if (m_sharedString->size == 0 || string.empty())
return m_sharedString->size == string.size();
if (m_sharedString->size != string.size())
return false;
return std::strcmp(m_sharedString->string, string.c_str()) != 0;
}
bool NzString::operator<(char character) const
{
if (character == '\0')
return false;
if (m_sharedString->size == 0)
return true;
return m_sharedString->string[0] < character;
}
bool NzString::operator<(const char* string) const
{
if (!string || !string[0])
return false;
if (m_sharedString->size == 0)
return true;
return std::strcmp(m_sharedString->string, string) < 0;
}
bool NzString::operator<(const std::string& string) const
{
if (string.empty())
return false;
if (m_sharedString->size == 0)
return true;
return std::strcmp(m_sharedString->string, string.c_str()) < 0;
}
bool NzString::operator<=(char character) const
{
if (m_sharedString->size == 0)
return true;
if (character == '\0')
return false;
return m_sharedString->string[0] < character || (m_sharedString->string[0] == character && m_sharedString->size == 1);
}
bool NzString::operator<=(const char* string) const
{
if (m_sharedString->size == 0)
return true;
if (!string || !string[0])
return false;
return std::strcmp(m_sharedString->string, string) <= 0;
}
bool NzString::operator<=(const std::string& string) const
{
if (m_sharedString->size == 0)
return true;
if (string.empty())
return false;
return std::strcmp(m_sharedString->string, string.c_str()) <= 0;
}
bool NzString::operator>(char character) const
{
if (m_sharedString->size == 0)
return false;
if (character == '\0')
return true;
return m_sharedString->string[0] > character;
}
bool NzString::operator>(const char* string) const
{
if (m_sharedString->size == 0)
return false;
if (!string || !string[0])
return true;
return std::strcmp(m_sharedString->string, string) > 0;
}
bool NzString::operator>(const std::string& string) const
{
if (m_sharedString->size == 0)
return false;
if (string.empty())
return true;
return std::strcmp(m_sharedString->string, string.c_str()) > 0;
}
bool NzString::operator>=(char character) const
{
if (character == '\0')
return true;
if (m_sharedString->size == 0)
return false;
return m_sharedString->string[0] > character || (m_sharedString->string[0] == character && m_sharedString->size == 1);
}
bool NzString::operator>=(const char* string) const
{
if (!string || !string[0])
return true;
if (m_sharedString->size == 0)
return false;
return std::strcmp(m_sharedString->string, string) >= 0;
}
bool NzString::operator>=(const std::string& string) const
{
if (string.empty())
return true;
if (m_sharedString->size == 0)
return false;
return std::strcmp(m_sharedString->string, string.c_str()) >= 0;
}
NzString NzString::Boolean(bool boolean)
{
unsigned int size = (boolean) ? 4 : 5;
char* str = new char[size+1];
std::memcpy(str, (boolean) ? "true" : "false", size+1);
return NzString(new SharedString(1, size, size, str));
}
int NzString::Compare(const NzString& first, const NzString& second)
{
if (first.m_sharedString->size == 0)
return (second.m_sharedString->size == 0) ? 0 : -1;
if (second.m_sharedString->size == 0)
return 1;
return std::strcmp(first.m_sharedString->string, second.m_sharedString->string);
}
NzString NzString::Number(float number)
{
std::ostringstream oss;
oss.precision(NAZARA_CORE_DECIMAL_DIGITS);
oss << number;
return NzString(oss.str());
}
NzString NzString::Number(double number)
{
std::ostringstream oss;
oss.precision(NAZARA_CORE_DECIMAL_DIGITS);
oss << number;
return NzString(oss.str());
}
NzString NzString::Number(long double number)
{
std::ostringstream oss;
oss.precision(NAZARA_CORE_DECIMAL_DIGITS);
oss << number;
return NzString(oss.str());
}
NzString NzString::Number(signed char number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Number(unsigned char number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Number(short number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Number(unsigned short number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Number(int number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Number(unsigned int number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Number(long number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Number(unsigned long number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Number(long long number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Number(unsigned long long number, nzUInt8 radix)
{
return NzNumberToString(number, radix);
}
NzString NzString::Pointer(const void* ptr)
{
const unsigned int size = sizeof(void*)*2 + 2;
char* str = new char[size+1];
std::sprintf(str, "0x%p", ptr);
return NzString(new SharedString(1, size, size, str));
}
NzString NzString::Unicode(char32_t character)
{
if (character == '\0')
return NzString();
unsigned int count = 0;
if (character < 0x80)
count = 1;
else if (character < 0x800)
count = 2;
else if (character < 0x10000)
count = 3;
else
count = 4;
char* str = new char[count+1];
utf8::append(character, str);
str[count] = '\0';
return NzString(new SharedString(1, count, count, str));
}
NzString NzString::Unicode(const char* u8String)
{
return NzString(u8String);
}
NzString NzString::Unicode(const char16_t* u16String)
{
if (!u16String || !u16String[0])
return NzString();
const char16_t* ptr = u16String;
unsigned int count = 0;
do
count++;
while (*++ptr);
count *= 2; // On s'assure d'avoir la place suffisante
char* str = new char[count+1];
char* r = utf8::utf16to8(u16String, ptr, str);
*r = '\0';
return NzString(new SharedString(1, count, r-str, str));
}
NzString NzString::Unicode(const char32_t* u32String)
{
if (!u32String || !u32String[0])
return NzString();
const char32_t* ptr = u32String;
unsigned int count = 0;
do
{
char32_t cp = *ptr;
if (cp < 0x80)
count += 1;
else if (cp < 0x800)
count += 2;
else if (cp < 0x10000)
count += 3;
else
count += 4;
}
while (*++ptr);
char* str = new char[count+1];
char* r = utf8::utf32to8(u32String, ptr, str);
*r = '\0';
return NzString(new SharedString(1, count, count, str));
}
NzString NzString::Unicode(const wchar_t* wString)
{
if (!wString || !wString[0])
return NzString();
const wchar_t* ptr = wString;
unsigned int count = 0;
do
{
char32_t cp = *ptr;
if (cp < 0x80)
count += 1;
else if (cp < 0x800)
count += 2;
else if (cp < 0x10000)
count += 3;
else
count += 4;
}
while (*++ptr);
char* str = new char[count+1];
char* r = utf8::utf32to8(wString, ptr, str);
*r = '\0';
return NzString(new SharedString(1, count, count, str));
}
std::istream& operator>>(std::istream& is, NzString& str)
{
str.Clear();
char c;
do
{
is.get(c);
if (c == '\0')
break;
else if (std::isspace(c))
{
if (str.IsNull())
continue;
else
break;
}
else
str += c;
}
while (true);
return is;
}
std::ostream& operator<<(std::ostream& os, const NzString& str)
{
if (str.IsEmpty())
return os;
return operator<<(os, str.m_sharedString->string);
}
NzString operator+(char character, const NzString& string)
{
if (character == '\0')
return string;
if (string.IsEmpty())
return NzString(character);
unsigned int totalSize = string.m_sharedString->size+1;
char* str = new char[totalSize+1];
str[0] = character;
std::memcpy(&str[1], string.m_sharedString->string, string.m_sharedString->size+1);
return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
}
NzString operator+(const char* string, const NzString& nstring)
{
if (!string || !string[0])
return nstring;
if (nstring.IsEmpty())
return string;
unsigned int size = std::strlen(string);
unsigned int totalSize = size + nstring.m_sharedString->size;
char* str = new char[totalSize+1];
std::memcpy(str, string, size);
std::memcpy(&str[size], nstring.m_sharedString->string, nstring.m_sharedString->size+1);
return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
}
NzString operator+(const std::string& string, const NzString& nstring)
{
if (string.empty())
return nstring;
if (nstring.m_sharedString->size == 0)
return string;
unsigned int totalSize = string.size() + nstring.m_sharedString->size;
char* str = new char[totalSize+1];
std::memcpy(str, string.c_str(), string.size());
std::memcpy(&str[string.size()], nstring.m_sharedString->string, nstring.m_sharedString->size+1);
return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
}
bool operator==(const NzString& first, const NzString& second)
{
if (first.m_sharedString->size == 0 || second.m_sharedString->size == 0)
return first.m_sharedString->size == second.m_sharedString->size;
if (first.m_sharedString->size != second.m_sharedString->size)
return false;
if (first.m_sharedString == second.m_sharedString)
return true;
return std::strcmp(first.m_sharedString->string, second.m_sharedString->string) == 0;
}
bool operator!=(const NzString& first, const NzString& second)
{
return !operator==(first, second);
}
bool operator<(const NzString& first, const NzString& second)
{
if (second.m_sharedString->size == 0)
return false;
if (first.m_sharedString->size == 0)
return true;
return std::strcmp(first.m_sharedString->string, second.m_sharedString->string) < 0;
}
bool operator<=(const NzString& first, const NzString& second)
{
return !operator<(second, first);
}
bool operator>(const NzString& first, const NzString& second)
{
return second < first;
}
bool operator>=(const NzString& first, const NzString& second)
{
return !operator<(first, second);
}
bool operator==(char character, const NzString& nstring)
{
return nstring == character;
}
bool operator==(const char* string, const NzString& nstring)
{
return nstring == string;
}
bool operator==(const std::string& string, const NzString& nstring)
{
return nstring == string;
}
bool operator!=(char character, const NzString& nstring)
{
return !operator==(character, nstring);
}
bool operator!=(const char* string, const NzString& nstring)
{
return !operator==(string, nstring);
}
bool operator!=(const std::string& string, const NzString& nstring)
{
return !operator==(string, nstring);
}
bool operator<(char character, const NzString& nstring)
{
return nstring > character;
}
bool operator<(const char* string, const NzString& nstring)
{
return nstring > string;
}
bool operator<(const std::string& string, const NzString& nstring)
{
return nstring > string;
}
bool operator<=(char character, const NzString& nstring)
{
return !operator<(nstring, NzString(character));
}
bool operator<=(const char* string, const NzString& nstring)
{
return !operator<(nstring, string);
}
bool operator<=(const std::string& string, const NzString& nstring)
{
return !operator<(nstring, string);
}
bool operator>(char character, const NzString& nstring)
{
return nstring < character;
}
bool operator>(const char* string, const NzString& nstring)
{
return nstring < string;
}
bool operator>(const std::string& string, const NzString& nstring)
{
return nstring < string;
}
bool operator>=(char character, const NzString& nstring)
{
return !operator<(character, nstring);
}
bool operator>=(const char* string, const NzString& nstring)
{
return !operator<(string, nstring);
}
bool operator>=(const std::string& string, const NzString& nstring)
{
return !operator<(string, nstring);
}
void NzString::EnsureOwnership(bool discardContent)
{
if (m_sharedString == &emptyString)
return;
if (m_sharedString->refCount > 1)
{
m_sharedString->refCount--;
char* string = new char[m_sharedString->capacity+1];
if (!discardContent)
std::memcpy(string, m_sharedString->string, m_sharedString->size+1);
m_sharedString = new SharedString(1, m_sharedString->capacity, m_sharedString->size, string);
}
}
bool NzString::FillHash(NzAbstractHash* hash) const
{
hash->Append(reinterpret_cast<const nzUInt8*>(m_sharedString->string), m_sharedString->size);
return true;
}
void NzString::ReleaseString()
{
if (m_sharedString == &emptyString)
return;
if (--m_sharedString->refCount == 0)
{
delete[] m_sharedString->string;
delete m_sharedString;
}
m_sharedString = &emptyString;
}
NzString::SharedString NzString::emptyString(0, 0, 0, nullptr);
const unsigned int NzString::npos(std::numeric_limits<unsigned int>::max());
namespace std
{
istream& getline(istream& is, NzString& str)
{
str.Clear();
char c;
do
{
is.get(c);
if (c != '\n' && c != '\0')
str += c;
else
break;
}
while (true);
return is;
}
istream& getline(istream& is, NzString& str, char delim)
{
str.Clear();
char c;
do
{
is.get(c);
if (c != delim && c != '\0')
str += c;
else
break;
}
while (true);
return is;
}
void swap(NzString& lhs, NzString& rhs)
{
lhs.Swap(rhs);
}
}