// 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: Rewrite most of used algorithms (Reread to to line 4638)

#include <Nazara/Core/String.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Unicode.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <limits>
#include <sstream>
#include <Utfcpp/utf8.h>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	namespace Detail
	{
		// This algorithm is inspired by the documentation of Qt
		inline std::size_t GetNewSize(std::size_t newSize)
		{
			if (newSize < 20)
				return newSize+4;
			else
			{
				if (newSize < (1 << 12)-12)
					return GetNearestPowerOfTwo(newSize << 1)-12;
				else
					return newSize + (1 << 11);
			}
		}

		inline char ToLower(char character)
		{
			if (character >= 'A' && character <= 'Z')
				return character + ('a' - 'A');
			else
				return character;
		}

		inline char ToUpper(char character)
		{
			if (character >= 'a' && character <= 'z')
				return character + ('A' - 'a');
			else
				return character;
		}

		inline int Strcasecmp(const char* s1, const char* s2)
		{
			int ret = 0;

			while (((ret = static_cast<unsigned char>(Detail::ToLower(*s1)) - static_cast<unsigned char>(Detail::ToLower(*s2))) != 0) && *s2)
				++s1, ++s2;

			return ret != 0 ? (ret > 0 ? 1 : -1) : 0;
		}

		inline int Unicodecasecmp(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 = Unicode::GetLowercase(*it1) - Unicode::GetLowercase(*it2)) != 0) && *it2)
				++it1, ++it2;

			return ret != 0 ? (ret > 0 ? 1 : -1) : 0;
		}
	}

	/*!
	* \ingroup core
	* \class Nz::String
	* \brief Core class that represents a string
	*/

	/*!
	* \brief Constructs a String object by default
	*/

	String::String() :
	m_sharedString(GetEmptyString())
	{
	}

	/*!
	* \brief Constructs a String object with a character
	*
	* \param character Single character
	*/

	String::String(char character)
	{
		if (character != '\0')
		{
			m_sharedString = std::make_shared<SharedString>(1);
			m_sharedString->string[0] = character;
		}
		else
			m_sharedString = GetEmptyString();
	}

	/*!
	* \brief Constructs a String object with multiple times the same character
	*
	* \param rep Number of repetitions of the character
	* \param character Single character
	*/

	String::String(std::size_t rep, char character)
	{
		if (rep > 0)
		{
			m_sharedString = std::make_shared<SharedString>(rep);

			if (character != '\0')
				std::memset(m_sharedString->string.get(), character, rep);
		}
		else
			m_sharedString = GetEmptyString();
	}

	/*!
	* \brief Constructs a String object with multiple times the same string
	*
	* \param rep Number of repetitions of the string
	* \param string String to multiply
	*/

	String::String(std::size_t rep, const char* string) :
	String(rep, string, (string) ? std::strlen(string) : 0)
	{
	}

	/*!
	* \brief Constructs a String object with multiple times the same string
	*
	* \param rep Number of repetitions of the string
	* \param string String to multiply
	* \param length Length of the string
	*/

	String::String(std::size_t rep, const char* string, std::size_t length)
	{
		std::size_t totalSize = rep*length;

		if (totalSize > 0)
		{
			m_sharedString = std::make_shared<SharedString>(totalSize);

			for (std::size_t i = 0; i < rep; ++i)
				std::memcpy(&m_sharedString->string[i*length], string, length);
		}
		else
			m_sharedString = GetEmptyString();
	}

	/*!
	* \brief Constructs a String object with multiple times the same string
	*
	* \param rep Number of repetitions of the string
	* \param string String to multiply
	*/

	String::String(std::size_t rep, const String& string) :
	String(rep, string.GetConstBuffer(), string.GetSize())
	{
	}

	/*!
	* \brief Constructs a String object with a "C string"
	*
	* \param string String to represent
	*/

	String::String(const char* string) :
	String(string, (string) ? std::strlen(string) : 0)
	{
	}

	/*!
	* \brief Constructs a String object with a "C string"
	*
	* \param string String to represent
	* \param length Length of the string
	*/

	String::String(const char* string, std::size_t length)
	{
		if (length > 0)
		{
			m_sharedString = std::make_shared<SharedString>(length);
			std::memcpy(m_sharedString->string.get(), string, length);
		}
		else
			m_sharedString = GetEmptyString();
	}

	/*!
	* \brief Constructs a String object which is a copy of another
	*
	* \param string String to copy
	*/

	String::String(const std::string& string) :
	String(string.c_str(), string.size())
	{
	}

	/*!
	* \brief Appends the character to the string
	* \return A reference to this
	*
	* \param character Single character
	*
	* \see Insert
	*/

	String& String::Append(char character)
	{
		return Insert(m_sharedString->size, character);
	}

	/*!
	* \brief Appends the "C string" to the string
	* \return A reference to this
	*
	* \param string String to add
	*
	* \see Insert
	*/

	String& String::Append(const char* string)
	{
		return Insert(m_sharedString->size, string);
	}

	/*!
	* \brief Appends the "C string" to the string
	* \return A reference to this
	*
	* \param string String to add
	* \param length Size of the string
	*
	* \see Insert
	*/

	String& String::Append(const char* string, std::size_t length)
	{
		return Insert(m_sharedString->size, string, length);
	}

	/*!
	* \brief Appends the string to the string
	* \return A reference to this
	*
	* \param string String to add
	*
	* \see Insert
	*/

	String& String::Append(const String& string)
	{
		return Insert(m_sharedString->size, string);
	}

	/*!
	* \brief Clears the content of the string
	*
	* \param keepBuffer Should the buffer be kept
	*/

	void String::Clear(bool keepBuffer)
	{
		if (keepBuffer)
		{
			EnsureOwnership(true);
			m_sharedString->size = 0;
		}
		else
			ReleaseString();
	}

	/*!
	* \Brief Checks whether the string contains the character
	* \return true if found in the string
	*
	* \param character Single character
	* \param start Index to begin the research
	* \param flags Flag for the look up
	*
	* \see Find
	*/

	bool String::Contains(char character, std::intmax_t start, UInt32 flags) const
	{
		return Find(character, start, flags) != npos;
	}

	/*!
	* \Brief Checks whether the string contains the "C string"
	* \return true if found in the string
	*
	* \param string String to search
	* \param start Index to begin the research
	* \param flags Flag for the look up
	*
	* \see Find
	*/

	bool String::Contains(const char* string, std::intmax_t start, UInt32 flags) const
	{
		return Find(string, start, flags) != npos;
	}

	/*!
	* \Brief Checks whether the string contains the string
	* \return true if found in the string
	*
	* \param string String to search
	* \param start Index to begin the research
	* \param flags Flag for the look up
	*
	* \see Find
	*/

	bool String::Contains(const String& string, std::intmax_t start, UInt32 flags) const
	{
		return Find(string, start, flags) != npos;
	}

	/*!
	* \brief Counts the number of occurrences in the string
	* \return Number of occurrences
	*
	* \param character Single character
	* \param start Index to begin the research
	* \param flags Flag for the look up
	*/

	unsigned int String::Count(char character, std::intmax_t start, UInt32 flags) const
	{
		if (character == '\0' || m_sharedString->size == 0)
			return 0;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(start);
		if (pos >= m_sharedString->size)
			return 0;

		char* str = &m_sharedString->string[pos];
		unsigned int count = 0;
		if (flags & CaseInsensitive)
		{
			char character_lower = Detail::ToLower(character);
			char character_upper = Detail::ToUpper(character);
			do
			{
				if (*str == character_lower || *str == character_upper)
					count++;
			}
			while (*++str);
		}
		else
		{
			while ((str = std::strchr(str, character)) != nullptr)
			{
				count++;
				str++;
			}
		}

		return count;
	}

	/*!
	* \brief Counts the number of occurrences in the string
	* \return Number of occurrences
	*
	* \param string String to count
	* \param start Index to begin the research
	* \param flags Flag for the look up
	*/

	unsigned int String::Count(const char* string, std::intmax_t start, UInt32 flags) const
	{
		if (!string || !string[0] || m_sharedString->size == 0)
			return 0;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(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 = Unicode::GetLowercase(utf8::unchecked::next(t));
				do
				{
					if (Unicode::GetLowercase(*it) == c)
					{
						++it;

						utf8::unchecked::iterator<const char*> it2(t);
						for (;;)
						{
							if (*it2 == '\0')
							{
								count++;
								break;
							}

							if (*it == '\0')
								return count;

							if (Unicode::GetLowercase(*it) != Unicode::GetLowercase(*it2))
								break;

							++it;
							++it2;
						}
					}
				}
				while (*++it);
			}
			else
			{
				char c = Detail::ToLower(string[0]);
				do
				{
					if (Detail::ToLower(*str) == c)
					{
						str++;

						const char* ptr = &string[1];
						for (;;)
						{
							if (*ptr == '\0')
							{
								count++;
								break;
							}

							if (*str == '\0')
								return count;

							if (Detail::ToLower(*str) != Detail::ToLower(*ptr))
								break;

							ptr++;
							str++;
						}
					}
				}
				while (*++str);
			}
		}
		else
		{
			while ((str = std::strstr(str, string)) != nullptr)
			{
				count++;
				str++;
			}
		}

		return count;
	}

	/*!
	* \brief Counts the number of occurrences in the string
	* \return Number of occurrences
	*
	* \param string String to count
	* \param start Index to begin the research
	* \param flags Flag for the look up
	*/

	unsigned int String::Count(const String& string, std::intmax_t start, UInt32 flags) const
	{
		return Count(string.GetConstBuffer(), start, flags);
	}

	/*!
	* \brief Counts the number of occurrences of any characters in the list in the string
	* \return Number of occurrences
	*
	* \param string String to match
	* \param start Index to begin the research
	* \param flags Flag for the look up
	*/

	unsigned int String::CountAny(const char* string, std::intmax_t start, UInt32 flags) const
	{
		if (!string || !string[0] || m_sharedString->size == 0)
			return 0;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(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 (Unicode::GetLowercase(*it) == Unicode::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 (Detail::ToLower(*str) == Detail::ToLower(*c))
						{
							count++;
							break;
						}
					}
					while (*++c);
				}
				while (*++str);
			}
			else
			{
				while ((str = std::strpbrk(str, string)) != nullptr)
				{
					count++;
					str++;
				}
			}
		}

		return count;
	}

	/*!
	* \brief Counts the number of occurrences of any characters in the list in the string
	* \return Number of occurrences
	*
	* \param string String to match
	* \param start Index to begin the research
	* \param flags Flag for the look up
	*/

	unsigned int String::CountAny(const String& string, std::intmax_t start, UInt32 flags) const
	{
		return CountAny(string.GetConstBuffer(), start, flags);
	}

	/*!
	* \brief Checks whether the string ends with the character
	* \return true if it the case
	*
	* \param character Single character
	* \param flags Flag for the look up
	*
	* \see StartsWith
	*/

	bool String::EndsWith(char character, UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return 0;

		if (flags & CaseInsensitive)
			return Detail::ToLower(m_sharedString->string[m_sharedString->size-1]) == Detail::ToLower(character);
		else
			return m_sharedString->string[m_sharedString->size-1] == character; // character == '\0' will always be false
	}

	/*!
	* \brief Checks whether the string ends with the "C string"
	* \return true if it the case
	*
	* \param string String to match
	* \param flags Flag for the look up
	*
	* \see StartsWith
	*/

	bool String::EndsWith(const char* string, UInt32 flags) const
	{
		return EndsWith(string, std::strlen(string), flags);
	}

	/*!
	* \brief Checks whether the string ends with the "C string"
	* \return true if it the case
	*
	* \param string String to match
	* \param length Size of the string
	* \param flags Flag for the look up
	*
	* \see StartsWith
	*/

	bool String::EndsWith(const char* string, std::size_t length, UInt32 flags) const
	{
		if (!string || !string[0] || m_sharedString->size == 0 || length > m_sharedString->size)
			return false;

		if (flags & CaseInsensitive)
		{
			if (flags & HandleUtf8)
				return Detail::Unicodecasecmp(&m_sharedString->string[m_sharedString->size - length], string) == 0;
			else
				return Detail::Strcasecmp(&m_sharedString->string[m_sharedString->size - length], string) == 0;
		}
		else
			return std::strcmp(&m_sharedString->string[m_sharedString->size - length], string) == 0;
	}

	/*!
	* \brief Checks whether the string ends with the string
	* \return true if it the case
	*
	* \param string String to match
	* \param flags Flag for the look up
	*
	* \see StartsWith
	*/

	bool String::EndsWith(const String& string, UInt32 flags) const
	{
		return EndsWith(string.GetConstBuffer(), string.m_sharedString->size, flags);
	}

	/*!
	* \brief Finds the first index of the character in the string
	* \return Index in the string
	*
	* \param character Single character
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::Find(char character, std::intmax_t start, UInt32 flags) const
	{
		if (character == '\0' || m_sharedString->size == 0)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(start);
		if (pos >= m_sharedString->size)
			return npos;

		if (flags & CaseInsensitive)
		{
			char ch = Detail::ToLower(character);
			const char* str = m_sharedString->string.get();
			do
			{
				if (Detail::ToLower(*str) == ch)
					return str - m_sharedString->string.get();
			}
			while (*++str);

			return npos;
		}
		else
		{
			char* ch = std::strchr(&m_sharedString->string[pos], character);
			if (ch)
				return ch - m_sharedString->string.get();
			else
				return npos;
		}
	}

	/*!
	* \brief Finds the first index of the "C string" in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::Find(const char* string, std::intmax_t start, UInt32 flags) const
	{
		if (!string || !string[0] || m_sharedString->size == 0)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(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 = Unicode::GetLowercase(utf8::unchecked::next(t));
				do
				{
					if (Unicode::GetLowercase(*it) == c)
					{
						const char* ptrPos = it.base();
						++it;

						utf8::unchecked::iterator<const char*> it2(t);
						for (;;)
						{
							if (*it2 == '\0')
								return ptrPos - m_sharedString->string.get();

							if (*it == '\0')
								return npos;

							if (Unicode::GetLowercase(*it) != Unicode::GetLowercase(*it2))
								break;

							++it;
							++it2;
						}
					}
				}
				while (*++it);
			}
			else
			{
				char c = Detail::ToLower(string[0]);
				do
				{
					if (Detail::ToLower(*str) == c)
					{
						char* ptrPos = str;
						str++;

						const char* ptr = &string[1];
						for (;;)
						{
							if (*ptr == '\0')
								return ptrPos - m_sharedString->string.get();

							if (*str == '\0')
								return npos;

							if (Detail::ToLower(*str) != Detail::ToLower(*ptr))
								break;

							ptr++;
							str++;
						}
					}
				}
				while (*++str);
			}
		}
		else
		{
			char* ch = std::strstr(&m_sharedString->string[pos], string);
			if (ch)
				return ch - m_sharedString->string.get();
		}

		return npos;
	}

	/*!
	* \brief Finds the first index of the string in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::Find(const String& string, std::intmax_t start, UInt32 flags) const
	{
		return Find(string.GetConstBuffer(), start, flags);
	}

	/*!
	* \brief Finds the first index of any characters in the list in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindAny(const char* string, std::intmax_t start, UInt32 flags) const
	{
		if (m_sharedString->size == 0 || !string || !string[0])
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(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 = Unicode::GetLowercase(*it);
					do
					{
						if (character == Unicode::GetLowercase(*it2))
							return it.base() - m_sharedString->string.get();
					}
					while (*++it2);
				}
				while (*++it);
			}
			else
			{
				do
				{
					utf8::unchecked::iterator<const char*> it2(string);
					do
					{
						if (*it == *it2)
							return it.base() - m_sharedString->string.get();
					}
					while (*++it2);
				}
				while (*++it);
			}
		}
		else
		{
			if (flags & CaseInsensitive)
			{
				do
				{
					const char* c = string;
					char character = Detail::ToLower(*str);
					do
					{
						if (character == Detail::ToLower(*c))
							return str - m_sharedString->string.get();
					}
					while (*++c);
				}
				while (*++str);
			}
			else
			{
				str = std::strpbrk(str, string);
				if (str)
					return str - m_sharedString->string.get();
			}
		}

		return npos;
	}

	/*!
	* \brief Finds the first index of any characters in the list in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindAny(const String& string, std::intmax_t start, UInt32 flags) const
	{
		return FindAny(string.GetConstBuffer(), start, flags);
	}

	/*!
	* \brief Finds the last index of the character in the string
	* \return Index in the string
	*
	* \param character Single character
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindLast(char character, std::intmax_t start, UInt32 flags) const
	{
		if (character == '\0' || m_sharedString->size == 0)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(start);
		if (pos >= m_sharedString->size)
			return npos;

		char* ptr = &m_sharedString->string[m_sharedString->size-1];

		if (flags & CaseInsensitive)
		{
			character = Detail::ToLower(character);
			do
			{
				if (Detail::ToLower(*ptr) == character)
					return ptr - m_sharedString->string.get();
			}
			while (ptr-- != m_sharedString->string.get());
		}
		else
		{
			do
			{
				if (*ptr == character)
					return ptr - m_sharedString->string.get();
			}
			while (ptr-- != m_sharedString->string.get());
		}

		return npos;
	}

	/*!
	* \brief Finds the last index of the "C string" in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindLast(const char* string, std::intmax_t start, UInt32 flags) const
	{
		if (!string || !string[0] || m_sharedString->size == 0)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(start);
		if (pos >= m_sharedString->size)
			return npos;

		///Algo 1.FindLast#3 (Size of the pattern unknown)
		const char* ptr = &m_sharedString->string[pos];
		if (flags & CaseInsensitive)
		{
			if (flags & HandleUtf8)
			{
				if (utf8::internal::is_trail(*ptr))
					utf8::unchecked::prior(ptr); // We ensure to have one pointer pointing to the begin of the character

				utf8::unchecked::iterator<const char*> it(ptr);
				const char* t = string;
				char32_t c = Unicode::GetLowercase(utf8::unchecked::next(t));
				do
				{
					if (Unicode::GetLowercase(*it) == c)
					{
						utf8::unchecked::iterator<const char*> it2(t);
						utf8::unchecked::iterator<const char*> tIt(it);
						++tIt;

						for (;;)
						{
							if (*it2 == '\0')
								return it.base() - m_sharedString->string.get();

							if (tIt.base() > &m_sharedString->string[pos])
								break;

							if (Unicode::GetLowercase(*tIt) != Unicode::GetLowercase(*it2))
								break;

							++it2;
							++tIt;
						}
					}
				}
				while (it--.base() != m_sharedString->string.get());
			}
			else
			{
				char c = Detail::ToLower(string[0]);
				do
				{
					if (Detail::ToLower(*ptr) == c)
					{
						const char* p = &string[1];
						const char* tPtr = ptr+1;
						for (;;)
						{
							if (*p == '\0')
								return ptr - m_sharedString->string.get();

							if (tPtr > &m_sharedString->string[pos])
								break;

							if (Detail::ToLower(*tPtr) != Detail::ToLower(*p))
								break;

							p++;
							tPtr++;
						}
					}
				}
				while (ptr-- != m_sharedString->string.get());
			}
		}
		else
		{
			do
			{
				if (*ptr == string[0])
				{
					const char* p = &string[1];
					const char* tPtr = ptr+1;
					for (;;)
					{
						if (*p == '\0')
							return ptr - m_sharedString->string.get();

						if (tPtr > &m_sharedString->string[pos])
							break;

						if (*tPtr != *p)
							break;

						p++;
						tPtr++;
					}
				}
			}
			while (ptr-- != m_sharedString->string.get());
		}

		return npos;
	}

	/*!
	* \brief Finds the last index of the string in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindLast(const String& string, std::intmax_t start, UInt32 flags) const
	{
		if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(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 (Iterator non-adapted)
				if (utf8::internal::is_trail(*ptr))
					utf8::unchecked::prior(ptr); // We ensure to have one pointer pointing to the begin of the character

				utf8::unchecked::iterator<const char*> it(ptr);
				const char* t = string.GetConstBuffer();
				char32_t c = Unicode::GetLowercase(utf8::unchecked::next(t));
				do
				{
					if (Unicode::GetLowercase(*it) == c)
					{
						utf8::unchecked::iterator<const char*> it2(t);
						utf8::unchecked::iterator<const char*> tIt(it);
						++tIt;

						for (;;)
						{
							if (*it2 == '\0')
								return it.base() - m_sharedString->string.get();

							if (tIt.base() > &m_sharedString->string[pos])
								break;

							if (Unicode::GetLowercase(*tIt) != Unicode::GetLowercase(*it2))
								break;

							++it2;
							++tIt;
						}
					}
				}
				while (it--.base() != limit);
			}
			else
			{
				///Algo 1.FindLast#4 (Size of the pattern unknown)
				char c = Detail::ToLower(string.m_sharedString->string[string.m_sharedString->size-1]);
				for (;;)
				{
					if (Detail::ToLower(*ptr) == c)
					{
						const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
						for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
						{
							if (Detail::ToLower(*ptr) != Detail::ToLower(*p))
								break;

							if (p == &string.m_sharedString->string[0])
								return ptr-m_sharedString->string.get();

							if (ptr == m_sharedString->string.get())
								return npos;
						}
					}
					else if (ptr-- <= limit)
						break;
				}
			}
		}
		else
		{
			///Algo 1.FindLast#4 (Size of the pattern known)
			for (;;)
			{
				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.get();

						if (ptr == m_sharedString->string.get())
							return npos;
					}
				}
				else if (ptr-- <= limit)
					break;
			}
		}

		return npos;
	}

	/*!
	* \brief Finds the last index of any characters in the list in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindLastAny(const char* string, std::intmax_t start, UInt32 flags) const
	{
		if (!string || !string[0] || m_sharedString->size == 0)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(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 = Unicode::GetLowercase(*it);
					do
					{
						if (character == Unicode::GetLowercase(*it2))
							return it.base() - m_sharedString->string.get();
					}
					while (*++it2);
				}
				while (it--.base() != m_sharedString->string.get());
			}
			else
			{
				do
				{
					utf8::unchecked::iterator<const char*> it2(string);
					do
					{
						if (*it == *it2)
							return it.base() - m_sharedString->string.get();
					}
					while (*++it2);
				}
				while (it--.base() != m_sharedString->string.get());
			}
		}
		else
		{
			if (flags & CaseInsensitive)
			{
				do
				{
					const char* c = string;
					char character = Detail::ToLower(*str);
					do
					{
						if (character == Detail::ToLower(*c))
							return str - m_sharedString->string.get();
					}
					while (*++c);
				}
				while (str-- != m_sharedString->string.get());
			}
			else
			{
				do
				{
					const char* c = string;
					do
					{
						if (*str == *c)
							return str - m_sharedString->string.get();
					}
					while (*++c);
				}
				while (str-- != m_sharedString->string.get());
			}
		}

		return npos;
	}

	/*!
	* \brief Finds the last index of any characters in the list in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindLastAny(const String& string, std::intmax_t start, UInt32 flags) const
	{
		return FindLastAny(string.GetConstBuffer(), start, flags);
	}

	/*!
	* \brief Finds the last word in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindLastWord(const char* string, std::intmax_t start, UInt32 flags) const
	{
		if (!string || !string[0] || m_sharedString->size == 0)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(start);
		if (pos >= m_sharedString->size)
			return npos;

		///Algo 2.FindLastWord#1 (Size of the pattern unknown)
		const char* ptr = &m_sharedString->string[pos];

		if (flags & HandleUtf8)
		{
			if (utf8::internal::is_trail(*ptr))
				utf8::unchecked::prior(ptr); // We ensure to have a pointer pointing to the beginning of the string

			utf8::unchecked::iterator<const char*> it(ptr);

			if (flags & CaseInsensitive)
			{
				const char* t = string; // utf8(::unchecked)::next affects the iterator on argument
				UInt32 c = Unicode::GetLowercase(utf8::unchecked::next(t));
				do
				{
					if (Unicode::GetLowercase(*it) == c)
					{
						if (it.base() != m_sharedString->string.get())
						{
							--it;
							if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
								continue;
						}

						utf8::unchecked::iterator<const char*> p(t);
						utf8::unchecked::iterator<const char*> tIt = it;
						++tIt;

						for (;;)
						{
							if (*p == '\0')
							{
								if (*tIt == '\0' || Unicode::GetCategory(*tIt) & Unicode::Category_Separator)
									return it.base() - m_sharedString->string.get();
								else
									break;
							}

							if (tIt.base() > &m_sharedString->string[pos])
								break;

							if (Unicode::GetLowercase(*tIt) != Unicode::GetLowercase(*p))
								break;

							++p;
							++tIt;
						}
					}
				}
				while (it--.base() != m_sharedString->string.get());
			}
			else
			{
				const char* t = string; // utf8(::unchecked)::next affects the iterator on argument
				UInt32 c = utf8::unchecked::next(t);
				do
				{
					if (*it == c)
					{
						if (it.base() != m_sharedString->string.get())
						{
							--it;
							if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
								continue;
						}

						utf8::unchecked::iterator<const char*> p(t);
						utf8::unchecked::iterator<const char*> tIt = it;
						++tIt;

						for (;;)
						{
							if (*p == '\0')
							{
								if (*tIt == '\0' || Unicode::GetCategory(*tIt) & Unicode::Category_Separator)
									return it.base() - m_sharedString->string.get();
								else
									break;
							}

							if (tIt.base() > &m_sharedString->string[pos])
								break;

							if (*tIt != *p)
								break;

							++p;
							++tIt;
						}
					}
				}
				while (it--.base() != m_sharedString->string.get());
			}
		}
		else
		{
			if (flags & CaseInsensitive)
			{
				char c = Detail::ToLower(string[0]);
				do
				{
					if (Detail::ToLower(*ptr) == c)
					{
						if (ptr != m_sharedString->string.get())
						{
							--ptr;
							if (!(Unicode::GetCategory(*ptr++) & Unicode::Category_Separator))
								continue;
						}

						const char* p = &string[1];
						const char* tPtr = ptr+1;
						for (;;)
						{
							if (*p == '\0')
							{
								if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator)
									return ptr-m_sharedString->string.get();
								else
									break;
							}

							if (tPtr > &m_sharedString->string[pos])
								break;

							if (Detail::ToLower(*tPtr) != Detail::ToLower(*p))
								break;

							p++;
							tPtr++;
						}
					}
				}
				while (ptr-- != m_sharedString->string.get());
			}
			else
			{
				do
				{
					if (*ptr == string[0])
					{
						if (ptr != m_sharedString->string.get())
						{
							--ptr;
							if (!(Unicode::GetCategory(*ptr++) & Unicode::Category_Separator))
								continue;
						}

						const char* p = &string[1];
						const char* tPtr = ptr+1;
						for (;;)
						{
							if (*p == '\0')
							{
								if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator)
									return ptr-m_sharedString->string.get();
								else
									break;
							}

							if (tPtr > &m_sharedString->string[pos])
								break;

							if (*tPtr != *p)
								break;

							p++;
							tPtr++;
						}
					}
				}
				while (ptr-- != m_sharedString->string.get());
			}
		}

		return npos;
	}

	/*!
	* \brief Finds the last word in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindLastWord(const String& string, std::intmax_t start, UInt32 flags) const
	{
		if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(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); // We ensure to have a pointer pointing to the beginning of the string

			utf8::unchecked::iterator<const char*> it(ptr);

			if (flags & CaseInsensitive)
			{
				const char* t = string.GetConstBuffer(); // utf8(::unchecked)::next affects the iterator on argument
				UInt32 c = Unicode::GetLowercase(utf8::unchecked::next(t));
				do
				{
					if (Unicode::GetLowercase(*it) == c)
					{
						if (it.base() != m_sharedString->string.get())
						{
							--it;
							if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
								continue;
						}

						utf8::unchecked::iterator<const char*> p(t);
						utf8::unchecked::iterator<const char*> tIt = it;
						++tIt;

						for (;;)
						{
							if (*p == '\0')
							{
								if (*tIt == '\0' || Unicode::GetCategory(*tIt) & Unicode::Category_Separator)
									return it.base() - m_sharedString->string.get();
								else
									break;
							}

							if (tIt.base() > &m_sharedString->string[pos])
								break;

							if (Unicode::GetLowercase(*tIt) != Unicode::GetLowercase(*p))
								break;

							++p;
							++tIt;
						}
					}
				}
				while (it--.base() != m_sharedString->string.get());
			}
			else
			{
				const char* t = string.GetConstBuffer(); // utf8(::unchecked)::next affects the iterator on argument
				UInt32 c = utf8::unchecked::next(t);
				do
				{
					if (*it == c)
					{
						if (it.base() != m_sharedString->string.get())
						{
							--it;
							if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
								continue;
						}

						utf8::unchecked::iterator<const char*> p(t);
						utf8::unchecked::iterator<const char*> tIt = it;
						++tIt;

						for (;;)
						{
							if (*p == '\0')
							{
								if (*tIt == '\0' || Unicode::GetCategory(*tIt) & Unicode::Category_Separator)
									return it.base() - m_sharedString->string.get();
								else
									break;
							}

							if (tIt.base() > &m_sharedString->string[pos])
								break;

							if (*tIt != *p)
								break;

							++p;
							++tIt;
						}
					}
				}
				while (it--.base() != m_sharedString->string.get());
			}
		}
		else
		{
			///Algo 2.FindLastWord#2 (Size of the pattern known)
			if (flags & CaseInsensitive)
			{
				char c = Detail::ToLower(string.m_sharedString->string[string.m_sharedString->size-1]);
				do
				{
					if (Detail::ToLower(*ptr) == c)
					{
						char nextC = *(ptr + 1);
						if (nextC != '\0' && (Unicode::GetCategory(nextC) & Unicode::Category_Separator_Space) == 0)
							continue;

						const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
						for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
						{
							if (Detail::ToLower(*ptr) != Detail::ToLower(*p))
								break;

							if (p == &string.m_sharedString->string[0])
							{
								if (ptr == m_sharedString->string.get() || Unicode::GetCategory(*(ptr-1)) & Unicode::Category_Separator_Space)
									return ptr-m_sharedString->string.get();
								else
									break;
							}

							if (ptr == m_sharedString->string.get())
								return npos;
						}
					}
				}
				while (ptr-- > limit);
			}
			else
			{
				do
				{
					if (*ptr == string.m_sharedString->string[string.m_sharedString->size-1])
					{
						char nextC = *(ptr + 1);
						if (nextC != '\0' && (Unicode::GetCategory(nextC) & Unicode::Category_Separator_Space) == 0)
							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.get() || Unicode::GetCategory(*(ptr - 1)) & Unicode::Category_Separator_Space)
									return ptr-m_sharedString->string.get();
								else
									break;
							}

							if (ptr == m_sharedString->string.get())
								return npos;
						}
					}
				}
				while (ptr-- > limit);
			}
		}

		return npos;
	}

	/*!
	* \brief Finds the first word in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindWord(const char* string, std::intmax_t start, UInt32 flags) const
	{
		if (!string || !string[0] || m_sharedString->size == 0)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(start);
		if (pos >= m_sharedString->size)
			return npos;

		///Algo 3.FindWord#3 (Size of the pattern unknown)
		const char* ptr = m_sharedString->string.get();
		if (flags & HandleUtf8)
		{
			if (utf8::internal::is_trail(*ptr))
				utf8::unchecked::prior(ptr); // We ensure to have one pointer pointing to the begin of the character

			utf8::unchecked::iterator<const char*> it(ptr);

			if (flags & CaseInsensitive)
			{
				const char* t = string; // utf8(::unchecked)::next affects the iterator on argument
				UInt32 c = Unicode::GetLowercase(utf8::unchecked::next(t));

				do
				{
					if (*it == c)
					{
						if (it.base() != m_sharedString->string.get())
						{
							--it;
							if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
								continue;
						}

						utf8::unchecked::iterator<const char*> p(t);
						utf8::unchecked::iterator<const char*> tIt = it;
						++tIt;

						for (;;)
						{
							if (*p == '\0')
							{
								if (*tIt == '\0' || Unicode::GetCategory(*it++) & Unicode::Category_Separator)
									return it.base() - m_sharedString->string.get();
								else
									break;
							}

							if (Unicode::GetLowercase(*tIt) != Unicode::GetLowercase(*p))
								break;

							++p;
							++tIt;
						}
					}
				}
				while (*++ptr);
			}
			else
			{
				const char* t = string; // utf8(::unchecked)::next affects the iterator on argument
				UInt32 c = Unicode::GetLowercase(utf8::unchecked::next(t));

				do
				{
					if (*it == c)
					{
						if (it.base() != m_sharedString->string.get())
						{
							--it;
							if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
								continue;
						}

						utf8::unchecked::iterator<const char*> p(t);
						utf8::unchecked::iterator<const char*> tIt = it;
						++tIt;

						for (;;)
						{
							if (*p == '\0')
							{
								if (*tIt == '\0' || Unicode::GetCategory(*it++) & Unicode::Category_Separator)
									return it.base() - m_sharedString->string.get();
								else
									break;
							}

							if (*tIt != *p)
								break;

							++p;
							++tIt;
						}
					}
				}
				while (*++ptr);
			}
		}
		else
		{
			if (flags & CaseInsensitive)
			{
				char c = Detail::ToLower(string[0]);
				do
				{
					if (Detail::ToLower(*ptr) == c)
					{
						if (ptr != m_sharedString->string.get() && (Unicode::GetCategory(*(ptr - 1)) & Unicode::Category_Separator) == 0)
							continue;

						const char* p = &string[1];
						const char* tPtr = ptr+1;
						for (;;)
						{
							if (*p == '\0')
							{
								if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator)
									return ptr - m_sharedString->string.get();
								else
									break;
							}

							if (Detail::ToLower(*tPtr) != Detail::ToLower(*p))
								break;

							p++;
							tPtr++;
						}
					}
				}
				while (*++ptr);
			}
			else
			{
				do
				{
					if (*ptr == string[0])
					{
						if (ptr != m_sharedString->string.get() && (Unicode::GetCategory(*(ptr-1)) & Unicode::Category_Separator) == 0)
							continue;

						const char* p = &string[1];
						const char* tPtr = ptr+1;
						for (;;)
						{
							if (*p == '\0')
							{
								if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator)
									return ptr - m_sharedString->string.get();
								else
									break;
							}

							if (*tPtr != *p)
								break;

							p++;
							tPtr++;
						}
					}
				}
				while (*++ptr);
			}
		}

		return npos;
	}

	/*!
	* \brief Finds the first word in the string
	* \return Index in the string
	*
	* \param string String to match
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::FindWord(const String& string, std::intmax_t start, UInt32 flags) const
	{
		if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
			return npos;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(start);
		if (pos >= m_sharedString->size)
			return npos;

		char* ptr = m_sharedString->string.get();
		if (flags & HandleUtf8)
		{
			///Algo 3.FindWord#3 (Iterator too slow for #2)
			if (utf8::internal::is_trail(*ptr))
				utf8::unchecked::prior(ptr); // We ensure to have one pointer pointing to the begin of the character

			utf8::unchecked::iterator<const char*> it(ptr);

			if (flags & CaseInsensitive)
			{
				const char* t = string.GetConstBuffer(); // utf8(::unchecked)::next affects the iterator on argument
				UInt32 c = Unicode::GetLowercase(utf8::unchecked::next(t));

				do
				{
					if (*it == c)
					{
						if (it.base() != m_sharedString->string.get())
						{
							--it;
							if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
								continue;
						}

						utf8::unchecked::iterator<const char*> p(t);
						utf8::unchecked::iterator<const char*> tIt = it;
						++tIt;

						for (;;)
						{
							if (*p == '\0')
							{
								if (*tIt == '\0' || Unicode::GetCategory(*it++) & Unicode::Category_Separator)
									return it.base() - m_sharedString->string.get();
								else
									break;
							}

							if (Unicode::GetLowercase(*tIt) != Unicode::GetLowercase(*p))
								break;

							++p;
							++tIt;
						}
					}
				}
				while (*++ptr);
			}
			else
			{
				const char* t = string.GetConstBuffer(); // utf8(::unchecked)::next affects the iterator on argument
				UInt32 c = Unicode::GetLowercase(utf8::unchecked::next(t));

				do
				{
					if (*it == c)
					{
						if (it.base() != m_sharedString->string.get())
						{
							--it;
							if (!(Unicode::GetCategory(*it++) & Unicode::Category_Separator))
								continue;
						}

						utf8::unchecked::iterator<const char*> p(t);
						utf8::unchecked::iterator<const char*> tIt = it;
						++tIt;

						for (;;)
						{
							if (*p == '\0')
							{
								if (*tIt == '\0' || Unicode::GetCategory(*it++) & Unicode::Category_Separator)
									return it.base() - m_sharedString->string.get();
								else
									break;
							}

							if (*tIt != *p)
								break;

							++p;
							++tIt;
						}
					}
				}
				while (*++ptr);
			}
		}
		else
		{
			///Algo 3.FindWord#2 (Size of the pattern known)
			if (flags & CaseInsensitive)
			{
				char c = Detail::ToLower(string.m_sharedString->string[0]);
				do
				{
					if (Detail::ToLower(*ptr) == c)
					{
						if (ptr != m_sharedString->string.get() && (Unicode::GetCategory(*(ptr-1)) & Unicode::Category_Separator_Space) == 0)
							continue;

						const char* p = &string.m_sharedString->string[1];
						const char* tPtr = ptr+1;
						for (;;)
						{
							if (*p == '\0')
							{
								if (*tPtr == '\0' || Unicode::GetCategory(*tPtr) & Unicode::Category_Separator_Space)
									return ptr - m_sharedString->string.get();
								else
									break;
							}

							if (Detail::ToLower(*tPtr) != Detail::ToLower(*p))
								break;

							p++;
							tPtr++;
						}
					}
				}
				while (*++ptr);
			}
			else
			{
				while ((ptr = std::strstr(ptr, string.GetConstBuffer())) != nullptr)
				{
					// If the word is really alone
					if ((ptr == m_sharedString->string.get() || Unicode::GetCategory(*(ptr-1)) & Unicode::Category_Separator_Space) && (*(ptr+m_sharedString->size) == '\0' || Unicode::GetCategory(*(ptr+m_sharedString->size)) & Unicode::Category_Separator_Space))
						return ptr - m_sharedString->string.get();

					ptr++;
				}
			}
		}

		return npos;
	}

	/*!
	* \brief Gets the raw buffer
	* \return Raw buffer
	*/

	char* String::GetBuffer()
	{
		EnsureOwnership();

		return m_sharedString->string.get();
	}

	/*!
	* \brief Gets the capacity of the string
	* \return Capacity of the string
	*/

	std::size_t String::GetCapacity() const
	{
		return m_sharedString->capacity;
	}

	/*!
	* \brief Gets the raw buffer
	* \return Raw buffer
	*/

	const char* String::GetConstBuffer() const
	{
		return m_sharedString->string.get();
	}

	/*!
	* \brief Gets the length of the string
	* \return Length of the string with UTF-8 awareness
	*/

	std::size_t String::GetLength() const
	{
		return utf8::distance(m_sharedString->string.get(), &m_sharedString->string[m_sharedString->size]);
	}

	/*!
	* \brief Gets the size of the string
	* \return Size of the string without UTF-8 awareness
	*/

	std::size_t String::GetSize() const
	{
		return m_sharedString->size;
	}

	/*!
	* \brief Gets the std::string corresponding
	* \return String in UTF-8
	*/

	std::string String::GetUtf8String() const
	{
		return std::string(m_sharedString->string.get(), m_sharedString->size);
	}

	/*!
	* \brief Gets the std::string corresponding
	* \return String in UTF-16
	*/

	std::u16string String::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;
	}

	/*!
	* \brief Gets the std::string corresponding
	* \return String in UTF-32
	*/

	std::u32string String::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;
	}

	/*!
	* \brief Gets the std::wstring corresponding
	* \return String in Wide
	*/

	std::wstring String::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) // I want a static_if :(
			utf8::utf8to32(begin(), end(), std::back_inserter(str));
		else
		{
			utf8::unchecked::iterator<const char*> it(m_sharedString->string.get());
			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;
	}

	/*!
	* \brief Gets the word until next separator
	* \return Word string
	*
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	String String::GetWord(unsigned int index, UInt32 flags) const
	{
		std::size_t startPos = GetWordPosition(index, flags);
		if (startPos == npos)
			return String();

		std::intmax_t endPos = -1;
		const char* ptr = &m_sharedString->string[startPos];
		if (flags & HandleUtf8)
		{
			utf8::unchecked::iterator<const char*> it(ptr);
			do
			{
				if (Unicode::GetCategory(*it) & Unicode::Category_Separator)
				{
					endPos = static_cast<std::intmax_t>(it.base() - m_sharedString->string.get() - 1);
					break;
				}
			}
			while (*++it);
		}
		else
		{
			do
			{
				if (Unicode::GetCategory(*ptr) & Unicode::Category_Separator)
				{
					endPos = static_cast<std::intmax_t>(ptr - m_sharedString->string.get() - 1);
					break;
				}
			}
			while (*++ptr);
		}

		return SubString(startPos, endPos);
	}

	/*!
	* \brief Gets the word position
	* \return Position of the beginning of the word
	*
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	std::size_t String::GetWordPosition(unsigned int index, UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return npos;

		unsigned int currentWord = 0;
		bool inWord = false;

		const char* ptr = m_sharedString->string.get();
		if (flags & HandleUtf8)
		{
			utf8::unchecked::iterator<const char*> it(ptr);
			do
			{
				if (Unicode::GetCategory(*it) & Unicode::Category_Separator)
					inWord = false;
				else
				{
					if (!inWord)
					{
						inWord = true;
						if (++currentWord > index)
							return it.base() - m_sharedString->string.get();
					}
				}
			}
			while (*++it);
		}
		else
		{
			do
			{
				if (Unicode::GetCategory(*ptr) & Unicode::Category_Separator)
					inWord = false;
				else
				{
					if (!inWord)
					{
						inWord = true;
						if (++currentWord > index)
							return ptr - m_sharedString->string.get();
					}
				}
			}
			while (*++ptr);
		}

		return npos;
	}

	/*!
	* \brief Inserts the character into the string
	* \return A reference to this
	*
	* \param pos Position in the string
	* \param character Single character
	*/

	String& String::Insert(std::intmax_t pos, char character)
	{
		return Insert(pos, &character, 1);
	}

	/*!
	* \brief Inserts the "C string" into the string
	* \return A reference to this
	*
	* \param pos Position in the string
	* \param string String to add
	*/

	String& String::Insert(std::intmax_t pos, const char* string)
	{
		return Insert(pos, string, std::strlen(string));
	}

	/*!
	* \brief Inserts the "C string" into the string
	* \return A reference to this
	*
	* \param pos Position in the string
	* \param string String to add
	* \param length Size of the string
	*/

	String& String::Insert(std::intmax_t pos, const char* string, std::size_t length)
	{
		if (length == 0)
			return *this;

		if (pos < 0)
			pos = std::max<std::size_t>(m_sharedString->size + pos, 0);

		std::size_t start = std::min<std::size_t>(pos, m_sharedString->size);

		// If buffer is already big enough
		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
		{
			auto newString = std::make_shared<SharedString>(m_sharedString->size + length);

			char* ptr = newString->string.get();

			if (start > 0)
			{
				std::memcpy(ptr, m_sharedString->string.get(), 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);

			m_sharedString = std::move(newString);
		}

		return *this;
	}

	/*!
	* \brief Inserts the string into the string
	* \return A reference to this
	*
	* \param pos Position in the string
	* \param string String to add
	*/

	String& String::Insert(std::intmax_t pos, const String& string)
	{
		return Insert(pos, string.GetConstBuffer(), string.m_sharedString->size);
	}

	/*!
	* \brief Checks whether the string is empty
	* \return true if string is empty
	*/

	bool String::IsEmpty() const
	{
		return m_sharedString->size == 0;
	}

	/*!
	* \brief Checks whether the string is null
	* \return true if string is null
	*/

	bool String::IsNull() const
	{
		return m_sharedString.get() == GetEmptyString().get();
	}

	/*!
	* \brief Checks whether the string is a number
	* \return true if string is a number
	*
	* \param base Base of the number
	* \param flags Flag for the look up
	*
	* \remark Produces a NazaraError if base is not in [2, 36( with NAZARA_CORE_SAFE defined
	*/

	bool String::IsNumber(UInt8 base, UInt32 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;

		String 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.get();

		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;
	}

	/*!
	* \brief Checks whether the string matches the pattern
	* \return true if string matches
	*
	* \param pattern Pattern to search
	*/

	bool String::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.get();
		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;
	}

	/*!
	* \brief Checks whether the string matches the pattern
	* \return true if string matches
	*
	* \param pattern Pattern to search
	*/

	bool String::Match(const String& pattern) const
	{
		return Match(pattern.m_sharedString->string.get());
	}

	/*!
	* \brief Prepends the character to the string
	* \return A reference to this
	*
	* \param character Single character
	*
	* \see Insert
	*/

	String& String::Prepend(char character)
	{
		return Insert(0, character);
	}

	/*!
	* \brief Prepends the "C string" to the string
	* \return A reference to this
	*
	* \param string String to add
	*
	* \see Insert
	*/

	String& String::Prepend(const char* string)
	{
		return Insert(0, string);
	}

	/*!
	* \brief Prepends the "C string" to the string
	* \return A reference to this
	*
	* \param string String to add
	* \param length Size of the string
	*
	* \see Insert
	*/

	String& String::Prepend(const char* string, std::size_t length)
	{
		return Insert(0, string, length);
	}

	/*!
	* \brief Prepends the string to the string
	* \return A reference to this
	*
	* \param string String to add
	*
	* \see Insert
	*/

	String& String::Prepend(const String& string)
	{
		return Insert(0, string);
	}

	/*!
	* \brief Replaces the old character by the new one
	* \return Number of changes
	*
	* \param oldCharacter Pattern to find
	* \param newCharacter Pattern to change for
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	unsigned int String::Replace(char oldCharacter, char newCharacter, std::intmax_t start, UInt32 flags)
	{
		if (oldCharacter == '\0' || oldCharacter == newCharacter)
			return 0;

		if (newCharacter == '\0') // In this case, we must use a more advanced algorithm
			return Replace(String(oldCharacter), String(), start);

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(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 = Detail::ToLower(oldCharacter);
			char character_upper = Detail::ToUpper(oldCharacter);
			do
			{
				if (*ptr == character_lower || *ptr == character_upper)
				{
					if (!found)
					{
						std::ptrdiff_t offset = ptr - m_sharedString->string.get();

						EnsureOwnership();

						ptr = &m_sharedString->string[offset];
						found = true;
					}

					*ptr = newCharacter;
					++count;
				}
			}
			while (*++ptr);
		}
		else
		{
			while ((ptr = std::strchr(ptr, oldCharacter)) != nullptr)
			{
				if (!found)
				{
					std::ptrdiff_t offset = ptr-m_sharedString->string.get();

					EnsureOwnership();

					ptr = &m_sharedString->string[offset];
					found = true;
				}

				*ptr = newCharacter;
				++count;
			}
		}

		return count;
	}

	/*!
	* \brief Replaces the old "C string" by the new one
	* \return Number of changes
	*
	* \param oldCharacter Pattern to find
	* \param newCharacter Pattern to change for
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	unsigned int String::Replace(const char* oldString, const char* replaceString, std::intmax_t start, UInt32 flags)
	{
		return Replace(oldString, std::strlen(oldString), replaceString, std::strlen(replaceString), start, flags);
	}

	/*!
	* \brief Replaces the old "C string" by the new one
	* \return Number of changes
	*
	* \param oldCharacter Pattern to find
	* \param oldLength Length of the old string
	* \param newCharacter Pattern to change for
	* \param Length of the new string
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	unsigned int String::Replace(const char* oldString, std::size_t oldLength, const char* replaceString, std::size_t replaceLength, std::intmax_t start, UInt32 flags)
	{
		if (oldLength == 0)
			return 0;

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(start);
		if (pos >= m_sharedString->size)
			return 0;

		unsigned int count = 0;
		if (oldLength == replaceLength)
		{
			bool found = false;

			// If no size change is necessary, we can thus use a quicker algorithm
			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: Replacement algorithm without changing the buffer (if replaceLength < oldLength)
		{
			std::size_t newSize = m_sharedString->size + Count(oldString)*(replaceLength - oldLength);
			if (newSize == m_sharedString->size) // Then it's the fact that Count(oldString) == 0
				return 0;

			auto newString = std::make_shared<SharedString>(newSize);

			///Algo 4.Replace#2
			char* ptr = newString->string.get();
			const char* p = m_sharedString->string.get();

			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);

			m_sharedString = std::move(newString);
		}

		return count;
	}

	/*!
	* \brief Replaces the old string by the new one
	* \return Number of changes
	*
	* \param oldCharacter Pattern to find
	* \param newCharacter Pattern to change for
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*/

	unsigned int String::Replace(const String& oldString, const String& replaceString, std::intmax_t start, UInt32 flags)
	{
		return Replace(oldString.GetConstBuffer(), oldString.m_sharedString->size, replaceString.GetConstBuffer(), replaceString.m_sharedString->size, start, flags);
	}

	/*!
	* \brief Replaces the old characters in the list by the new one
	* \return Number of changes
	*
	* \param oldCharacters Pattern to find
	* \param newCharacter Pattern to change for
	* \param start Index to begin the search
	* \param flags Flag for the look up
	*
	* \remark Does not handle UTF-8 currently
	*/

	unsigned int String::ReplaceAny(const char* oldCharacters, char replaceCharacter, std::intmax_t start, UInt32 flags)
	{
		///FIXME: Does not handle UTF-8
		if (!oldCharacters || !oldCharacters[0])
			return 0;

		/*if (replaceCharacter == '\0') // In this case, we must use a more advance algorithm
			return ReplaceAny(String(oldCharacters), String(), start);*/

		if (start < 0)
			start = std::max<std::size_t>(m_sharedString->size + start, 0);

		std::size_t pos = static_cast<std::size_t>(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 = Detail::ToLower(*ptr);
				bool found = false;
				do
				{
					if (character == Detail::ToLower(*c))
					{
						if (!found)
						{
							std::ptrdiff_t offset = ptr - m_sharedString->string.get();

							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)) != nullptr)
			{
				if (!found)
				{
					std::ptrdiff_t offset = ptr - m_sharedString->string.get();

					EnsureOwnership();

					ptr = &m_sharedString->string[offset];
					found = true;
				}

				*ptr++ = replaceCharacter;
				++count;
			}
		}

		return count;
	}
	/*
		unsigned int String::ReplaceAny(const char* oldCharacters, const char* replaceString, std::intmax_t start, UInt32 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 String::ReplaceAny(const String& oldCharacters, const String& replaceString, std::intmax_t start, UInt32 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;
		}
	*/

	/*!
	* \brief Reserves enough memory for the buffer size
	*
	* \param bufferSize Size of the buffer to allocate
	*
	* \remark If bufferSize is smaller than the old one, nothing is done
	*/

	void String::Reserve(std::size_t bufferSize)
	{
		if (m_sharedString->capacity > bufferSize)
			return;

		auto newString = std::make_shared<SharedString>(bufferSize);
		newString->size = m_sharedString->size;

		if (m_sharedString->size > 0)
			std::memcpy(newString->string.get(), m_sharedString->string.get(), m_sharedString->size);

		m_sharedString = std::move(newString);
	}

	/*!
	* \brief Resizes the string
	* \return A reference to this
	*
	* \param size Target size
	* \param flags Flag for the look up
	*/

	String& String::Resize(std::intmax_t size, UInt32 flags)
	{
		if (size == 0)
		{
			Clear(true);
			return *this;
		}

		if (size < 0)
			size = std::max<std::intmax_t>(m_sharedString->size + size, 0);

		std::size_t newSize = static_cast<std::size_t>(size);

		if (flags & HandleUtf8 && newSize < m_sharedString->size)
		{
			std::size_t characterToRemove = m_sharedString->size - newSize;

			char* ptr = &m_sharedString->string[m_sharedString->size];
			for (std::size_t i = 0; i < characterToRemove; ++i)
				utf8::prior(ptr, m_sharedString->string.get());

			newSize = ptr - m_sharedString->string.get();
		}

		if (m_sharedString->capacity >= newSize)
		{
			EnsureOwnership();

			m_sharedString->size = newSize;
			m_sharedString->string[newSize] = '\0'; // Adds the EoS character
		}
		else // Then we want to make the string bigger
		{
			auto newString = std::make_shared<SharedString>(newSize);
			std::memcpy(newString->string.get(), m_sharedString->string.get(), m_sharedString->size);

			m_sharedString = std::move(newString);
		}

		return *this;
	}

	/*!
	* \brief Resize a copy of the string
	* \return A copy of what would be the string resized
	*
	* \param size Target size
	* \param flags Flag for the look up
	*/

	String String::Resized(std::intmax_t size, UInt32 flags) const
	{
		if (size < 0)
			size = m_sharedString->size + size;

		if (size <= 0)
			return String();

		std::size_t newSize = static_cast<std::size_t>(size);
		if (newSize == m_sharedString->size)
			return *this;

		if (flags & HandleUtf8 && newSize < m_sharedString->size)
		{
			std::size_t characterToRemove = m_sharedString->size - newSize;

			char* ptr = &m_sharedString->string[m_sharedString->size - 1];
			for (std::size_t i = 0; i < characterToRemove; ++i)
				utf8::prior(ptr, m_sharedString->string.get());

			newSize = ptr - m_sharedString->string.get();
		}

		auto sharedStr = std::make_shared<SharedString>(newSize);
		if (newSize > m_sharedString->size)
			std::memcpy(sharedStr->string.get(), m_sharedString->string.get(), m_sharedString->size);
		else
			std::memcpy(sharedStr->string.get(), m_sharedString->string.get(), newSize);

		return String(std::move(sharedStr));
	}

	/*!
	* \brief Reverses the string
	* \return A reference to this
	*/

	String& String::Reverse()
	{
		if (m_sharedString->size != 0)
		{
			std::size_t i = 0;
			std::size_t j = m_sharedString->size-1;

			while (i < j)
				std::swap(m_sharedString->string[i++], m_sharedString->string[j--]);
		}

		return *this;
	}

	/*!
	* \brief Reverses a copy of the string
	* \return A copy of what would be the string reversed
	*/

	String String::Reversed() const
	{
		if (m_sharedString->size == 0)
			return String();

		auto sharedStr = std::make_shared<SharedString>(m_sharedString->size);

		char* ptr = &sharedStr->string[m_sharedString->size - 1];
		char* p = m_sharedString->string.get();

		do
			*ptr-- = *p;
		while (*(++p));

		return String(std::move(sharedStr));
	}

	/*!
	* \brief Sets the string to the character
	* \return A reference to this
	*
	* \param character Single character
	*/

	String& String::Set(char character)
	{
		if (character != '\0')
		{
			if (m_sharedString->capacity >= 1)
			{
				EnsureOwnership(true);

				m_sharedString->size = 1;
				m_sharedString->string[1] = '\0';
			}
			else
				m_sharedString = std::make_shared<SharedString>(1);

			m_sharedString->string[0] = character;
		}
		else
			ReleaseString();

		return *this;
	}


	/*!
	* \brief Sets the string with multiple times the same character
	* \return A reference to this
	*
	* \param rep Number of repetitions of the character
	* \param character Single character
	*/

	String& String::Set(std::size_t rep, char character)
	{
		if (rep > 0)
		{
			if (m_sharedString->capacity >= rep)
			{
				EnsureOwnership(true);

				m_sharedString->size = rep;
				m_sharedString->string[rep] = '\0';
			}
			else
				m_sharedString = std::make_shared<SharedString>(rep);

			if (character != '\0')
				std::memset(m_sharedString->string.get(), character, rep);
		}
		else
			ReleaseString();

		return *this;
	}

	/*!
	* \brief Sets the string with multiple times the same string
	* \return A reference to this
	*
	* \param rep Number of repetitions of the string
	* \param string String to multiply
	*/

	String& String::Set(std::size_t rep, const char* string)
	{
		return Set(rep, string, (string) ? std::strlen(string) : 0);
	}

	/*!
	* \brief Sets the string with multiple times the same string
	* \return A reference to this
	*
	* \param rep Number of repetitions of the string
	* \param string String to multiply
	* \param length Length of the string
	*/

	String& String::Set(std::size_t rep, const char* string, std::size_t length)
	{
		std::size_t totalSize = rep*length;

		if (totalSize > 0)
		{
			if (m_sharedString->capacity >= totalSize)
			{
				EnsureOwnership(true);

				m_sharedString->size = totalSize;
				m_sharedString->string[totalSize] = '\0';
			}
			else
				m_sharedString = std::make_shared<SharedString>(totalSize);

			for (std::size_t i = 0; i < rep; ++i)
				std::memcpy(&m_sharedString->string[i*length], string, length);
		}
		else
			ReleaseString();

		return *this;
	}

	/*!
	* \brief Sets the string with multiple times the same string
	* \return A reference to this
	*
	* \param rep Number of repetitions of the string
	* \param string String to multiply
	*/

	String& String::Set(std::size_t rep, const String& string)
	{
		return Set(rep, string.GetConstBuffer(), string.m_sharedString->size);
	}

	/*!
	* \brief Sets the string with other "C string"
	* \return A reference to this
	*
	* \param string String to copy
	*/

	String& String::Set(const char* string)
	{
		return Set(string, (string) ? std::strlen(string) : 0);
	}

	/*!
	* \brief Sets the string with other "C string"
	* \return A reference to this
	*
	* \param string String to represent
	* \param length Length of the string
	*/

	String& String::Set(const char* string, std::size_t length)
	{
		if (length > 0)
		{
			if (m_sharedString->capacity >= length)
			{
				EnsureOwnership(true);

				m_sharedString->size = length;
				m_sharedString->string[length] = '\0';
			}
			else
				m_sharedString = std::make_shared<SharedString>(length);

			std::memcpy(m_sharedString->string.get(), string, length);
		}
		else
			ReleaseString();

		return *this;
	}

	/*!
	* \brief Sets the string with a std::string
	* \return A reference to this
	*
	* \param string String to copy
	*/

	String& String::Set(const std::string& string)
	{
		return Set(string.data(), string.size());
	}

	/*!
	* \brief Sets the string with other string
	* \return A reference to this
	*
	* \param string String to copy
	*/

	String& String::Set(const String& string)
	{
		m_sharedString = string.m_sharedString;

		return *this;
	}

	/*!
	* \brief Sets the string by move semantic
	* \return A reference to this
	*
	* \param string String to move
	*/

	String& String::Set(String&& string) noexcept
	{
		std::swap(m_sharedString, string.m_sharedString);

		return *this;
	}

	/*!
	* \brief Simplifies a copy of the string
	* \return A copy of what would be the string simplified
	*
	* \param flags Flag for the look up
	*/

	String String::Simplified(UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return String();

		auto newString = std::make_shared<SharedString>(m_sharedString->size);
		char* str = newString->string.get();
		char* p = str;

		const char* ptr = m_sharedString->string.get();
		bool inword = false;
		if (flags & HandleUtf8)
		{
			utf8::unchecked::iterator<const char*> it(ptr);
			do
			{
				if (Unicode::GetCategory(*it) & Unicode::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 (Unicode::GetCategory(*ptr) & Unicode::Category_Separator)
				{
					if (inword)
					{
						*p++ = ' ';
						inword = false;
					}
				}
				else
				{
					*p++ = *ptr;
					inword = true;
				}
			}
			while (++ptr != limit);
		}

		if (!inword && p != str)
			p--;

		*p = '\0';

		return String(std::move(newString));
	}

	/*!
	* \brief Simplifies the string
	* \return A reference to this
	*
	* \param flags Flag for the look up
	*/

	String& String::Simplify(UInt32 flags)
	{
		return Set(Simplified(flags));
	}

	/*!
	* \brief Splits the string into others
	* \return The number of splits
	*
	* \param result Resulting tokens
	* \param separation Separation character
	* \param start Index for the beginning of the search
	* \param flags Flag for the look up
	*/

	unsigned int String::Split(std::vector<String>& result, char separation, std::intmax_t start, UInt32 flags) const
	{
		if (separation == '\0' || m_sharedString->size == 0)
			return 0;

		std::size_t 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));

		for (;;)
		{
			std::size_t 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();
	}

	/*!
	* \brief Splits the string into others
	* \return The number of splits
	*
	* \param result Resulting tokens
	* \param separation Separation string
	* \param start Index for the beginning of the search
	* \param flags Flag for the look up
	*/

	unsigned int String::Split(std::vector<String>& result, const char* separation, std::intmax_t start, UInt32 flags) const
	{
		return Split(result, separation, std::strlen(separation), start, flags);
	}

	/*!
	* \brief Splits the string into others
	* \return The number of splits
	*
	* \param result Resulting tokens
	* \param separation Separation String
	* \param length Length of the string
	* \param start Index for the beginning of the search
	* \param flags Flag for the look up
	*/

	unsigned int String::Split(std::vector<String>& result, const char* separation, std::size_t length, std::intmax_t start, UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return 0;
		else if (length == 0)
		{
			result.reserve(m_sharedString->size);
			for (std::size_t i = 0; i < m_sharedString->size; ++i)
				result.push_back(String(m_sharedString->string[i]));

			return m_sharedString->size;
		}
		else if (length > m_sharedString->size)
		{
			result.push_back(*this);
			return 1;
		}

		std::size_t lastSep = Find(separation, start, flags);
		std::size_t oldSize = result.size();
		if (lastSep == npos)
		{
			result.push_back(*this);
			return 1;
		}
		else if (lastSep != 0)
			result.push_back(SubString(0, lastSep-1));

		std::size_t 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;
	}

	/*!
	* \brief Splits the string into others
	* \return The number of splits
	*
	* \param result Resulting tokens
	* \param separation Separation string
	* \param start Index for the beginning of the search
	* \param flags Flag for the look up
	*/

	unsigned int String::Split(std::vector<String>& result, const String& separation, std::intmax_t start, UInt32 flags) const
	{
		return Split(result, separation.m_sharedString->string.get(), separation.m_sharedString->size, start, flags);
	}

	/*!
	* \brief Splits the string into others
	* \return The number of splits
	*
	* \param result Resulting tokens
	* \param separation List of characters of separation
	* \param start Index for the beginning of the search
	* \param flags Flag for the look up
	*/

	unsigned int String::SplitAny(std::vector<String>& result, const char* separations, std::intmax_t start, UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return 0;

		std::size_t oldSize = result.size();

		std::size_t 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));

		std::size_t 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;
	}

	/*!
	* \brief Splits the string into others
	* \return The number of splits
	*
	* \param result Resulting tokens
	* \param separation List of characters of separation
	* \param start Index for the beginning of the search
	* \param flags Flag for the look up
	*/

	unsigned int String::SplitAny(std::vector<String>& result, const String& separations, std::intmax_t start, UInt32 flags) const
	{
		return SplitAny(result, separations.m_sharedString->string.get(), start, flags);
	}

	/*!
	* \brief Checks whether the string begins with the character
	* \return true if it the case
	*
	* \param character Single character
	* \param flags Flag for the look up
	*
	* \see EndsWith
	*/

	bool String::StartsWith(char character, UInt32 flags) const
	{
		if (character == '\0' || m_sharedString->size == 0)
			return false;

		if (flags & CaseInsensitive)
			return Detail::ToLower(m_sharedString->string[0]) == Detail::ToLower(character);
		else
			return m_sharedString->string[0] == character;
	}

	/*!
	* \brief Checks whether the string begins with the "C string"
	* \return true if it the case
	*
	* \param string String to match
	* \param flags Flag for the look up
	*
	* \see EndsWith
	*/

	bool String::StartsWith(const char* string, UInt32 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.get());
				utf8::unchecked::iterator<const char*> it2(string);
				do
				{
					if (*it2 == '\0')
						return true;

					if (Unicode::GetLowercase(*it) != Unicode::GetLowercase(*it2))
						return false;

					++it2;
				}
				while (*it++);
			}
			else
			{
				char* ptr = m_sharedString->string.get();
				const char* s = string;
				do
				{
					if (*s == '\0')
						return true;

					if (Detail::ToLower(*ptr) != Detail::ToLower(*s))
						return false;

					s++;
				}
				while (*ptr++);
			}
		}
		else
		{
			char* ptr = m_sharedString->string.get();
			const char* s = string;
			do
			{
				if (*s == '\0')
					return true;

				if (*ptr != *s)
					return false;

				s++;
			}
			while (*ptr++);
		}

		return false;
	}

	/*!
	* \brief Checks whether the string begins with the string
	* \return true if it the case
	*
	* \param string String to match
	* \param flags Flag for the look up
	*
	* \see EndsWith
	*/

	bool String::StartsWith(const String& string, UInt32 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.get());
				utf8::unchecked::iterator<const char*> it2(string.GetConstBuffer());
				do
				{
					if (*it2 == '\0')
						return true;

					if (Unicode::GetLowercase(*it) != Unicode::GetLowercase(*it2))
						return false;

					++it2;
				}
				while (*it++);
			}
			else
			{
				char* ptr = m_sharedString->string.get();
				const char* s = string.GetConstBuffer();
				do
				{
					if (*s == '\0')
						return true;

					if (Detail::ToLower(*ptr) != Detail::ToLower(*s))
						return false;

					s++;
				}
				while (*ptr++);
			}
		}
		else
			return std::memcmp(m_sharedString->string.get(), string.GetConstBuffer(), string.m_sharedString->size) == 0;

		return false;
	}

	/*!
	* \brief Returns a sub string of the string
	* \return SubString
	*
	* \param startPos Index for the beginning of the search
	* \param endPos Index for the end of the search
	*/

	String String::SubString(std::intmax_t startPos, std::intmax_t endPos) const
	{
		if (startPos < 0)
			startPos = std::max<std::size_t>(m_sharedString->size + startPos, 0);

		std::size_t start = static_cast<std::size_t>(startPos);

		if (endPos < 0)
		{
			endPos = m_sharedString->size+endPos;
			if (endPos < 0)
				return String();
		}

		std::size_t minEnd = std::min(static_cast<std::size_t>(endPos), m_sharedString->size - 1);
		if (start > minEnd || start >= m_sharedString->size)
			return String();

		std::size_t size = minEnd - start + 1;

		auto str = std::make_shared<SharedString>(size);
		std::memcpy(str->string.get(), &m_sharedString->string[start], size);

		return String(std::move(str));
	}

	/*!
	* \brief Returns a sub string of the string from a character
	* \return SubString
	*
	* \param charater Pattern to find
	* \param startPos Index for the beginning of the search
	* \param fromLast beginning by the end
	* \param include Include the character
	* \param flags Flag for the look up
	*/

	String String::SubStringFrom(char character, std::intmax_t startPos, bool fromLast, bool include, UInt32 flags) const
	{
		if (character == '\0')
			return *this;

		std::size_t 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 String();

		return SubString(pos + ((include) ? 0 : 1));
	}

	/*!
	* \brief Returns a sub string of the string from a string
	* \return SubString
	*
	* \param string Pattern to find
	* \param startPos Index for the beginning of the search
	* \param fromLast beginning by the end
	* \param include Include the character
	* \param flags Flag for the look up
	*/

	String String::SubStringFrom(const char* string, std::intmax_t startPos, bool fromLast, bool include, UInt32 flags) const
	{
		return SubStringFrom(string, std::strlen(string), startPos, fromLast, include, flags);
	}

	/*!
	* \brief Returns a sub string of the string from a string
	* \return SubString
	*
	* \param string Pattern to find
	* \param length Size of the string
	* \param startPos Index for the beginning of the search
	* \param fromLast beginning by the end
	* \param include Include the character
	* \param flags Flag for the look up
	*/

	String String::SubStringFrom(const char* string, std::size_t length, std::intmax_t startPos, bool fromLast, bool include, UInt32 flags) const
	{
		std::size_t 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 String();

		return SubString(pos + ((include) ? 0 : length));
	}

	/*!
	* \brief Returns a sub string of the string from a string
	* \return SubString
	*
	* \param string Pattern to find
	* \param startPos Index for the beginning of the search
	* \param fromLast beginning by the end
	* \param include Include the character
	* \param flags Flag for the look up
	*/

	String String::SubStringFrom(const String& string, std::intmax_t startPos, bool fromLast, bool include, UInt32 flags) const
	{
		return SubStringFrom(string.GetConstBuffer(), string.m_sharedString->size, startPos, fromLast, include, flags);
	}

	/*!
	* \brief Returns a sub string of the string up to a character
	* \return SubString
	*
	* \param charater Pattern to find
	* \param startPos Index for the beginning of the search
	* \param toLast beginning by the end
	* \param include Include the character
	* \param flags Flag for the look up
	*/

	String String::SubStringTo(char character, std::intmax_t startPos, bool toLast, bool include, UInt32 flags) const
	{
		if (character == '\0')
			return *this;

		std::size_t pos;
		if (toLast)
			pos = FindLast(character, startPos);
		else
			pos = Find(character, startPos, flags);

		if (pos == 0)
			return (include) ? String(character) : String();
		else if (pos == npos)
			return *this;

		return SubString(0, pos+((include) ? 1 : 0)-1);
	}

	/*!
	* \brief Returns a sub string of the string up to a string
	* \return SubString
	*
	* \param string Pattern to find
	* \param startPos Index for the beginning of the search
	* \param toLast beginning by the end
	* \param include Include the character
	* \param flags Flag for the look up
	*/

	String String::SubStringTo(const char* string, std::intmax_t startPos, bool toLast, bool include, UInt32 flags) const
	{
		return SubStringTo(string, std::strlen(string), startPos, toLast, include, flags);
	}

	/*!
	* \brief Returns a sub string of the string up to a string
	* \return SubString
	*
	* \param string Pattern to find
	* \param length Size of the string
	* \param startPos Index for the beginning of the search
	* \param toLast beginning by the end
	* \param include Include the character
	* \param flags Flag for the look up
	*/

	String String::SubStringTo(const char* string, std::size_t length, std::intmax_t startPos, bool toLast, bool include, UInt32 flags) const
	{
		std::size_t pos;
		if (toLast)
			pos = FindLast(string, startPos, flags);
		else
			pos = Find(string, startPos, flags);

		if (pos == 0)
			return (include) ? string : String();
		else if (pos == npos)
			return *this;

		return SubString(0, pos+((include) ? length : 0)-1);
	}

	/*!
	* \brief Returns a sub string of the string up to a string
	* \return SubString
	*
	* \param string Pattern to find
	* \param startPos Index for the beginning of the search
	* \param toLast beginning by the end
	* \param include Include the character
	* \param flags Flag for the look up
	*/

	String String::SubStringTo(const String& string, std::intmax_t startPos, bool toLast, bool include, UInt32 flags) const
	{
		return SubStringTo(string.GetConstBuffer(), string.m_sharedString->size, startPos, toLast, include, flags);
	}

	/*!
	* \brief Swaps the content with the other string
	*
	* \param str Other string to swap with
	*/

	void String::Swap(String& str)
	{
		std::swap(m_sharedString, str.m_sharedString);
	}

	/*!
	* \brief Converts the string to boolean
	* \return true if successful
	*
	* \param value Boolean to convert to
	* \param flags Flag for the look up
	*/

	bool String::ToBool(bool* value, UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return false;

		String 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(); // The identified words are in ASCII, no use of Unicode flag

			if (word == "true")
			{
				if (value)
					*value = true;
			}
			else if (word == "false")
			{
				if (value)
					*value = false;
			}
			else
				return false;
		}

		return true;
	}

	/*!
	* \brief Converts the string to double
	* \return true if successful
	*
	* \param value Double to convert to
	* \param flags Flag for the look up
	*/

	bool String::ToDouble(double* value) const
	{
		if (m_sharedString->size == 0)
			return false;

		if (value)
			*value = std::atof(m_sharedString->string.get());

		return true;
	}

	/*!
	* \brief Converts the string to integer
	* \return true if successful
	*
	* \param value Integer to convert to
	* \param flags Flag for the look up
	*/

	bool String::ToInteger(long long* value, UInt8 base) const
	{
		if (value)
		{
			bool ok;
			*value = StringToNumber(*this, base, &ok);

			return ok;
		}
		else
			return IsNumber(base);
	}

	/*!
	* \brief Converts the string to lower
	* \return Lower string
	*
	* \param flags Flag for the look up
	*/

	String String::ToLower(UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return *this;

		if (flags & HandleUtf8)
		{
			String lower;
			lower.Reserve(m_sharedString->size);
			utf8::unchecked::iterator<const char*> it(m_sharedString->string.get());
			do
				utf8::append(Unicode::GetLowercase(*it), std::back_inserter(lower));
			while (*++it);

			return lower;
		}
		else
		{
			auto str = std::make_shared<SharedString>(m_sharedString->size);

			char* ptr = m_sharedString->string.get();
			char* s = str->string.get();
			do
				*s++ = Detail::ToLower(*ptr);
			while (*++ptr);

			*s = '\0';

			return String(std::move(str));
		}
	}

	/*!
	* \brief Converts the string to upper
	* \return Upper string
	*
	* \param flags Flag for the look up
	*/

	String String::ToUpper(UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return *this;

		if (flags & HandleUtf8)
		{
			String upper;
			upper.Reserve(m_sharedString->size);
			utf8::unchecked::iterator<const char*> it(m_sharedString->string.get());
			do
				utf8::append(Unicode::GetUppercase(*it), std::back_inserter(upper));
			while (*++it);

			return upper;
		}
		else
		{
			auto str = std::make_shared<SharedString>(m_sharedString->size);

			char* ptr = m_sharedString->string.get();
			char* s = str->string.get();
			do
				*s++ = Detail::ToUpper(*ptr);
			while (*++ptr);

			*s = '\0';

			return String(std::move(str));
		}
	}

	/*!
	* \brief Trims the string
	* \return A reference to this
	*
	* \param flags Flag for the look up
	*/

	String& String::Trim(UInt32 flags)
	{
		return Set(Trimmed(flags));
	}

	/*!
	* \brief Trims the string from a character
	* \return A reference to this
	*
	* \param character Character to suppress
	* \param flags Flag for the look up
	*/

	String& String::Trim(char character, UInt32 flags)
	{
		return Set(Trimmed(character, flags));
	}

	/*!
	* \brief Trims a copy of the string
	* \return A copy of what would be the string trimmed
	*
	* \param flags Flag for the look up
	*/

	String String::Trimmed(UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return *this;

		std::size_t startPos;
		std::size_t endPos;
		if (flags & HandleUtf8)
		{
			if ((flags & TrimOnlyRight) == 0)
			{
				utf8::unchecked::iterator<const char*> it(m_sharedString->string.get());
				do
				{
					if (*it != '\t' && (Unicode::GetCategory(*it) & Unicode::Category_Separator) == 0)
						break;
				}
				while (*++it);

				startPos = it.base() - m_sharedString->string.get();
			}
			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.get())
				{
					if (*it != '\t' && (Unicode::GetCategory(*it) & Unicode::Category_Separator) == 0)
						break;
				}

				endPos = it.base() - m_sharedString->string.get();
			}
			else
				endPos = m_sharedString->size-1;
		}
		else
		{
			startPos = 0;
			if ((flags & TrimOnlyRight) == 0)
			{
				for (; startPos < m_sharedString->size; ++startPos)
				{
                    char c = m_sharedString->string[startPos];
					if (c != '\t' && (Unicode::GetCategory(c) & Unicode::Category_Separator) == 0)
						break;
				}
			}

			endPos = m_sharedString->size-1;
			if ((flags & TrimOnlyLeft) == 0)
			{
				for (; endPos > 0; --endPos)
				{
                    char c = m_sharedString->string[endPos];
					if (c != '\t' && (Unicode::GetCategory(c) & Unicode::Category_Separator) == 0)
						break;
				}
			}
		}

		return SubString(startPos, endPos);
	}

	/*!
	* \brief Trims a copy of the string from a character
	* \return A copy of what would be the string trimmed
	*
	* \param character Character to suppress
	* \param flags Flag for the look up
	*/

	String String::Trimmed(char character, UInt32 flags) const
	{
		if (m_sharedString->size == 0)
			return *this;

		std::size_t startPos = 0;
		std::size_t endPos = m_sharedString->size-1;
		if (flags & CaseInsensitive)
		{
			char ch = Detail::ToLower(character);
			if ((flags & TrimOnlyRight) == 0)
			{
				for (; startPos < m_sharedString->size; ++startPos)
				{
					if (Detail::ToLower(m_sharedString->string[startPos]) != ch)
						break;
				}
			}

			if ((flags & TrimOnlyLeft) == 0)
			{
				for (; endPos > 0; --endPos)
				{
					if (Detail::ToLower(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);
	}

	/*!
	* \brief Returns an iterator pointing to the beginning of the string
	* \return beginning of the string
	*/

	char* String::begin()
	{
		return m_sharedString->string.get();
	}

	/*!
	* \brief Returns an iterator pointing to the beginning of the string
	* \return beginning of the string
	*/

	const char* String::begin() const
	{
		return m_sharedString->string.get();
	}

	/*!
	* \brief Returns an iterator pointing to the end of the string
	* \return End of the string
	*/

	char* String::end()
	{
		return &m_sharedString->string[m_sharedString->size];
	}

	/*!
	* \brief Returns an iterator pointing to the end of the string
	* \return End of the string
	*/

	const char* String::end() const
	{
		return &m_sharedString->string[m_sharedString->size];
	}

	/*!
	* \brief Pushed the character to the front of the string
	*
	* \param c Single character
	*
	* \see Prepend
	*/

	void String::push_front(char c)
	{
		Prepend(c);
	}

	/*!
	* \brief Pushed the character to the back of the string
	*
	* \param c Single character
	*
	* \see Append
	*/

	void String::push_back(char c)
	{
		Append(c);
	}
	/*
	char* String::rbegin()
	{
		return &m_sharedString->string[m_sharedString->size-1];
	}

	const char* String::rbegin() const
	{
		return &m_sharedString->string[m_sharedString->size-1];
	}

	char* String::rend()
	{
		return &m_sharedString->string[-1];
	}

	const char* String::rend() const
	{
		return &m_sharedString->string[-1];
	}
	*/

	/*!
	* \brief Converts the string to std::string
	* \return std::string representation
	*/

	String::operator std::string() const
	{
		return std::string(m_sharedString->string.get(), m_sharedString->size);
	}

	/*!
	* \brief Gets the ith character in the string
	* \return A reference to the character
	*
	* \param pos Index of the character
	*
	* \remark If pos is greather than the size, Resize is called
	*/

	char& String::operator[](std::size_t pos)
	{
		EnsureOwnership();

		if (pos >= m_sharedString->size)
			Resize(pos+1);

		return m_sharedString->string[pos];
	}

	/*!
	* \brief Gets the ith character in the string
	* \return The character
	*
	* \param pos Index of the character
	*
	* \remark Produces a NazaraError if pos is greather than the size
	*/

	char String::operator[](std::size_t 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];
	}

	/*!
	* \brief Assigns the string to the character
	* \return A reference to this
	*
	* \param character Single character
	*/

	String& String::operator=(char character)
	{
		return Set(character);
	}

	/*!
	* \brief Assigns the string with other "C string"
	* \return A reference to this
	*
	* \param string String to copy
	*/

	String& String::operator=(const char* string)
	{
		return Set(string);
	}

	/*!
	* \brief Assigns the string with a std::string
	* \return A reference to this
	*
	* \param string String to copy
	*/

	String& String::operator=(const std::string& string)
	{
		return Set(string);
	}

	/*!
	* \brief Assigns the string with other string
	* \return A reference to this
	*
	* \param string String to copy
	*/

	String& String::operator=(const String& string)
	{
		return Set(string);
	}

	/*!
	* \brief Assigns the string by move semantic
	* \return A reference to this
	*
	* \param string String to move
	*/

	String& String::operator=(String&& string) noexcept
	{
		return Set(string);
	}

	/*!
	* \brief Concatenates the character to the string
	* \return String which is the result of the concatenation
	*
	* \param character Single character
	*/

	String String::operator+(char character) const
	{
		if (character == '\0')
			return *this;

		auto str = std::make_shared<SharedString>(m_sharedString->size + 1);
		std::memcpy(str->string.get(), GetConstBuffer(), m_sharedString->size);
		str->string[m_sharedString->size] = character;

		return String(std::move(str));
	}

	/*!
	* \brief Concatenates the "C string" to the string
	* \return String which is the result of the concatenation
	*
	* \param string String to add
	*/

	String String::operator+(const char* string) const
	{
		if (!string || !string[0])
			return *this;

		if (m_sharedString->size == 0)
			return string;

		std::size_t length = std::strlen(string);
		if (length == 0)
			return *this;

		auto str = std::make_shared<SharedString>(m_sharedString->size + length);
		std::memcpy(str->string.get(), GetConstBuffer(), m_sharedString->size);
		std::memcpy(&str->string[m_sharedString->size], string, length+1);

		return String(std::move(str));
	}

	/*!
	* \brief Concatenates the std::string to the string
	* \return String which is the result of the concatenation
	*
	* \param string String to add
	*/

	String String::operator+(const std::string& string) const
	{
		if (string.empty())
			return *this;

		if (m_sharedString->size == 0)
			return string;

		auto str = std::make_shared<SharedString>(m_sharedString->size + string.size());
		std::memcpy(str->string.get(), GetConstBuffer(), m_sharedString->size);
		std::memcpy(&str->string[m_sharedString->size], string.c_str(), string.size()+1);

		return String(std::move(str));
	}

	/*!
	* \brief Concatenates the string to the string
	* \return String which is the result of the concatenation
	*
	* \param string String to add
	*/

	String String::operator+(const String& string) const
	{
		if (string.m_sharedString->size == 0)
			return *this;

		if (m_sharedString->size == 0)
			return string;

		auto str = std::make_shared<SharedString>(m_sharedString->size + string.m_sharedString->size);
		std::memcpy(str->string.get(), GetConstBuffer(), m_sharedString->size);
		std::memcpy(&str->string[m_sharedString->size], string.GetConstBuffer(), string.m_sharedString->size);

		return String(std::move(str));
	}

	/*!
	* \brief Concatenates the character to this string
	* \return A reference to this
	*
	* \param character Single character
	*/

	String& String::operator+=(char character)
	{
		return Insert(m_sharedString->size, character);
	}

	/*!
	* \brief Concatenates the "C string" to this string
	* \return A reference to this
	*
	* \param string String to add
	*/

	String& String::operator+=(const char* string)
	{
		return Insert(m_sharedString->size, string);
	}

	/*!
	* \brief Concatenates the std::string to this string
	* \return A reference to this
	*
	* \param string String to add
	*/

	String& String::operator+=(const std::string& string)
	{
		return Insert(m_sharedString->size, string.c_str(), string.size());
	}

	/*!
	* \brief Concatenates the string to this string
	* \return A reference to this
	*
	* \param string String to add
	*/

	String& String::operator+=(const String& string)
	{
		return Insert(m_sharedString->size, string);
	}

	/*!
	* \brief Checks whether the string is equal to the character
	* \return true if it is the case
	*
	* \param character Single character
	*/

	bool String::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;
	}

	/*!
	* \brief Checks whether the string is equal to the "C string"
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator==(const char* string) const
	{
		if (m_sharedString->size == 0)
			return !string || !string[0];

		if (!string || !string[0])
			return false;

		return std::strcmp(GetConstBuffer(), string) == 0;
	}

	/*!
	* \brief Checks whether the string is equal to the std::string
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::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(GetConstBuffer(), string.c_str()) == 0;
	}

	/*!
	* \brief Checks whether the string is equal to the character
	* \return false if it is the case
	*
	* \param character Single character
	*/

	bool String::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;
	}

	/*!
	* \brief Checks whether the string is equal to the "C string"
	* \return false if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator!=(const char* string) const
	{
		if (m_sharedString->size == 0)
			return string && string[0];

		if (!string || !string[0])
			return true;

		return std::strcmp(GetConstBuffer(), string) != 0;
	}

	/*!
	* \brief Checks whether the string is equal to the std::string
	* \return false if it is the case
	*
	* \param string String to compare
	*/

	bool String::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(GetConstBuffer(), string.c_str()) != 0;
	}

	/*!
	* \brief Checks whether the string is less than the character
	* \return true if it is the case
	*
	* \param character Single character
	*/

	bool String::operator<(char character) const
	{
		if (character == '\0')
			return false;

		if (m_sharedString->size == 0)
			return true;

		return m_sharedString->string[0] < character;
	}

	/*!
	* \brief Checks whether the string is less than the "C string"
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator<(const char* string) const
	{
		if (!string || !string[0])
			return false;

		if (m_sharedString->size == 0)
			return true;

		return std::strcmp(GetConstBuffer(), string) < 0;
	}

	/*!
	* \brief Checks whether the string is less than the std::string
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator<(const std::string& string) const
	{
		if (string.empty())
			return false;

		if (m_sharedString->size == 0)
			return true;

		return std::strcmp(GetConstBuffer(), string.c_str()) < 0;
	}

	/*!
	* \brief Checks whether the string is less or equal than the character
	* \return true if it is the case
	*
	* \param character Single character
	*/

	bool String::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);
	}

	/*!
	* \brief Checks whether the string is less or equal than the "C string"
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator<=(const char* string) const
	{
		if (m_sharedString->size == 0)
			return true;

		if (!string || !string[0])
			return false;

		return std::strcmp(GetConstBuffer(), string) <= 0;
	}

	/*!
	* \brief Checks whether the string is less or equal than the std::string
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator<=(const std::string& string) const
	{
		if (m_sharedString->size == 0)
			return true;

		if (string.empty())
			return false;

		return std::strcmp(GetConstBuffer(), string.c_str()) <= 0;
	}

	/*!
	* \brief Checks whether the string is greather than the character
	* \return true if it is the case
	*
	* \param character Single character
	*/

	bool String::operator>(char character) const
	{
		if (m_sharedString->size == 0)
			return false;

		if (character == '\0')
			return true;

		return m_sharedString->string[0] > character;
	}

	/*!
	* \brief Checks whether the string is greather than the "C string"
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator>(const char* string) const
	{
		if (m_sharedString->size == 0)
			return false;

		if (!string || !string[0])
			return true;

		return std::strcmp(GetConstBuffer(), string) > 0;
	}

	/*!
	* \brief Checks whether the string is greather than the std::string
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator>(const std::string& string) const
	{
		if (m_sharedString->size == 0)
			return false;

		if (string.empty())
			return true;

		return std::strcmp(GetConstBuffer(), string.c_str()) > 0;
	}

	/*!
	* \brief Checks whether the string is greather or equal than the character
	* \return true if it is the case
	*
	* \param character Single character
	*/

	bool String::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);
	}

	/*!
	* \brief Checks whether the string is greather or equal than the "C string"
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator>=(const char* string) const
	{
		if (!string || !string[0])
			return true;

		if (m_sharedString->size == 0)
			return false;

		return std::strcmp(GetConstBuffer(), string) >= 0;
	}

	/*!
	* \brief Checks whether the string is greather or equal than the std::string
	* \return true if it is the case
	*
	* \param string String to compare
	*/

	bool String::operator>=(const std::string& string) const
	{
		if (string.empty())
			return true;

		if (m_sharedString->size == 0)
			return false;

		return std::strcmp(GetConstBuffer(), string.c_str()) >= 0;
	}

	/*!
	* \brief Converts the boolean to string
	* \return String representation of the boolean
	*
	* \param boolean Boolean value
	*/

	String String::Boolean(bool boolean)
	{
		std::size_t size = (boolean) ? 4 : 5;

		auto str = std::make_shared<SharedString>(size);
		std::memcpy(str->string.get(), (boolean) ? "true" : "false", size);

		return String(std::move(str));
	}

	/*!
	* \brief Lexicographically compares the string
	* \return The expected result
	*
	* \param first First string to use for comparison
	* \parma second Second string to use for comparison
	*/

	int String::Compare(const String& first, const String& 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.GetConstBuffer(), second.GetConstBuffer());
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Float value
	*/

	String String::Number(float number)
	{
		std::ostringstream oss;
		oss.precision(NAZARA_CORE_DECIMAL_DIGITS);
		oss << number;

		return String(oss.str());
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Double value
	*/

	String String::Number(double number)
	{
		std::ostringstream oss;
		oss.precision(NAZARA_CORE_DECIMAL_DIGITS);
		oss << number;

		return String(oss.str());
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Long double value
	*/

	String String::Number(long double number)
	{
		std::ostringstream oss;
		oss.precision(NAZARA_CORE_DECIMAL_DIGITS);
		oss << number;

		return String(oss.str());
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Signed char value
	* \param radix Base of the number
	*/

	String String::Number(signed char number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Unsigned char value
	* \param radix Base of the number
	*/

	String String::Number(unsigned char number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Short value
	* \param radix Base of the number
	*/

	String String::Number(short number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Unsigned short value
	* \param radix Base of the number
	*/

	String String::Number(unsigned short number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Int value
	* \param radix Base of the number
	*/

	String String::Number(int number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Unsigned int value
	* \param radix Base of the number
	*/

	String String::Number(unsigned int number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Long value
	* \param radix Base of the number
	*/

	String String::Number(long number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Unsigned long value
	* \param radix Base of the number
	*/

	String String::Number(unsigned long number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Long long value
	* \param radix Base of the number
	*/

	String String::Number(long long number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the number to string
	* \return String representation of the number
	*
	* \param number Unsigned long long value
	* \param radix Base of the number
	*/

	String String::Number(unsigned long long number, UInt8 radix)
	{
		return NumberToString(number, radix);
	}

	/*!
	* \brief Converts the pointer to string
	* \return String representation of the pointer
	*
	* \param ptr Pointer to represent
	*/

	String String::Pointer(const void* ptr)
	{
		const std::size_t capacity = sizeof(void*)*2 + 2;

		auto str = std::make_shared<SharedString>(capacity);
		str->size = std::sprintf(str->string.get(), "0x%p", ptr);

		return String(std::move(str));
	}

	/*!
	* \brief Converts the unicode point to string
	* \return String representation of the unicode point
	*
	* \param character Unicode point
	*/

	String String::Unicode(char32_t character)
	{
		if (character == '\0')
			return String();

		std::size_t count = 0;
		if (character < 0x80)
			count = 1;
		else if (character < 0x800)
			count = 2;
		else if (character < 0x10000)
			count = 3;
		else
			count = 4;

		auto str = std::make_shared<SharedString>(count);
		utf8::append(character, str->string.get());

		return String(std::move(str));
	}

	/*!
	* \brief Converts the unicode "C string" to string
	* \return String representation of the unicode "C string"
	*
	* \param u8String String in UTF-8
	*/

	String String::Unicode(const char* u8String)
	{
		return String(u8String);
	}

	/*!
	* \brief Converts the unicode "C string" to string
	* \return String representation of the unicode "C string"
	*
	* \param u16String String in UTF-16
	*/

	String String::Unicode(const char16_t* u16String)
	{
		if (!u16String || !u16String[0])
			return String();

		const char16_t* ptr = u16String;
		std::size_t count = 0;
		do
			count++;
		while (*++ptr);

		count *= 2; // We ensure to have enough place

		auto str = std::make_shared<SharedString>(count);

		char* r = utf8::utf16to8(u16String, ptr, str->string.get());
		*r = '\0';

		str->size = r - str->string.get();

		return String(std::move(str));
	}

	/*!
	* \brief Converts the unicode "C string" to string
	* \return String representation of the unicode "C string"
	*
	* \param u32String String in UTF-32
	*/

	String String::Unicode(const char32_t* u32String)
	{
		if (!u32String || !u32String[0])
			return String();

		const char32_t* ptr = u32String;
		std::size_t 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);

		auto str = std::make_shared<SharedString>(count);
		utf8::utf32to8(u32String, ptr, str->string.get());

		return String(std::move(str));
	}

	/*!
	* \brief Converts the unicode "C string" to string
	* \return String representation of the unicode "C string"
	*
	* \param wString String in Wide
	*/

	String String::Unicode(const wchar_t* wString)
	{
		if (!wString || !wString[0])
			return String();

		const wchar_t* ptr = wString;
		std::size_t 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);

		auto str = std::make_shared<SharedString>(count);
		utf8::utf32to8(wString, ptr, str->string.get());

		return String(std::move(str));
	}

	/*!
	* \brief Inputs the stream into the string
	* \return A reference to the stream
	*
	* \param is Stream to get information from
	* \param str String to set value
	*/

	std::istream& operator>>(std::istream& is, String& str)
	{
		str.Clear();

		char c;
		for (;;)
		{
			is.get(c);
			if (c == '\0')
				break;
			else if (std::isspace(c))
			{
				if (str.IsNull())
					continue;
				else
					break;
			}
			else
				str += c;
		}

		return is;
	}

	/*!
	* \brief Output operator
	* \return The stream
	*
	* \param out The stream
	* \param str The string to output
	*/

	std::ostream& operator<<(std::ostream& os, const String& str)
	{
		if (str.IsEmpty())
			return os;

		return operator<<(os, str.m_sharedString->string.get());
	}

	/*!
	* \brief Concatenates the character to the string
	* \return String which is the result of the concatenation
	*
	* \param character Single character
	* \param string String in the right hand side
	*/

	String operator+(char character, const String& string)
	{
		if (character == '\0')
			return string;

		if (string.IsEmpty())
			return String(character);

		auto str = std::make_shared<String::SharedString>(string.m_sharedString->size + 1);
		str->string[0] = character;
		std::memcpy(&str->string[1], string.GetConstBuffer(), string.m_sharedString->size);

		return String(std::move(str));
	}

	/*!
	* \brief Concatenates the "C string" to the string
	* \return String which is the result of the concatenation
	*
	* \param string String to add
	* \param string String in the right hand side
	*/

	String operator+(const char* string, const String& nstring)
	{
		if (!string || !string[0])
			return nstring;

		if (nstring.IsEmpty())
			return string;

		std::size_t size = std::strlen(string);
		std::size_t totalSize = size + nstring.m_sharedString->size;

		auto str = std::make_shared<String::SharedString>(totalSize);
		std::memcpy(str->string.get(), string, size);
		std::memcpy(&str->string[size], nstring.GetConstBuffer(), nstring.m_sharedString->size+1);

		return String(std::move(str));
	}

	/*!
	* \brief Concatenates the std::string to the string
	* \return String which is the result of the concatenation
	*
	* \param string String to add
	* \param string String in the right hand side
	*/

	String operator+(const std::string& string, const String& nstring)
	{
		if (string.empty())
			return nstring;

		if (nstring.m_sharedString->size == 0)
			return string;

		std::size_t totalSize = string.size() + nstring.m_sharedString->size;

		auto str = std::make_shared<String::SharedString>(totalSize);
		std::memcpy(str->string.get(), string.c_str(), string.size());
		std::memcpy(&str->string[string.size()], nstring.GetConstBuffer(), nstring.m_sharedString->size+1);

		return String(std::move(str));
	}

	/*!
	* \brief Checks whether the first string is equal to the second string
	* \return true if it is the case
	*
	* \param first String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator==(const String& first, const String& 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.GetConstBuffer(), second.GetConstBuffer()) == 0;
	}

	/*!
	* \brief Checks whether the first string is equal to the second string
	* \return false if it is the case
	*
	* \param first String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator!=(const String& first, const String& second)
	{
		return !operator==(first, second);
	}

	/*!
	* \brief Checks whether the first string is less than the second string
	* \return true if it is the case
	*
	* \param first String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator<(const String& first, const String& second)
	{
		if (second.m_sharedString->size == 0)
			return false;

		if (first.m_sharedString->size == 0)
			return true;

		return std::strcmp(first.GetConstBuffer(), second.GetConstBuffer()) < 0;
	}

	/*!
	* \brief Checks whether the first string is less or equal than the second string
	* \return true if it is the case
	*
	* \param first String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator<=(const String& first, const String& second)
	{
		return !operator<(second, first);
	}

	/*!
	* \brief Checks whether the first string is greather than the second string
	* \return true if it is the case
	*
	* \param first String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator>(const String& first, const String& second)
	{
		return second < first;
	}

	/*!
	* \brief Checks whether the first string is greather or equal than the second string
	* \return true if it is the case
	*
	* \param first String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator>=(const String& first, const String& second)
	{
		return !operator<(first, second);
	}

	/*!
	* \brief Checks whether the string is equal to the character
	* \return true if it is the case
	*
	* \param character Single character in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator==(char character, const String& nstring)
	{
		return nstring == character;
	}

	/*!
	* \brief Checks whether the string is equal to the "C string"
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator==(const char* string, const String& nstring)
	{
		return nstring == string;
	}

	/*!
	* \brief Checks whether the string is equal to the std::string
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator==(const std::string& string, const String& nstring)
	{
		return nstring == string;
	}

	/*!
	* \brief Checks whether the string is equal to the character
	* \return false if it is the case
	*
	* \param character Single character in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator!=(char character, const String& nstring)
	{
		return !operator==(character, nstring);
	}

	/*!
	* \brief Checks whether the string is equal to the "C string"
	* \return false if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator!=(const char* string, const String& nstring)
	{
		return !operator==(string, nstring);
	}

	/*!
	* \brief Checks whether the string is equal to the std::string
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator!=(const std::string& string, const String& nstring)
	{
		return !operator==(string, nstring);
	}

	/*!
	* \brief Checks whether the string is less than the character
	* \return true if it is the case
	*
	* \param character Single character in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator<(char character, const String& nstring)
	{
		return nstring > character;
	}

	/*!
	* \brief Checks whether the string is less than the "C string"
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator<(const char* string, const String& nstring)
	{
		return nstring > string;
	}

	/*!
	* \brief Checks whether the string is less than the std::string
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator<(const std::string& string, const String& nstring)
	{
		return nstring > string;
	}

	/*!
	* \brief Checks whether the string is less or equal than the character
	* \return true if it is the case
	*
	* \param character Single character in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator<=(char character, const String& nstring)
	{
		return !operator<(nstring, String(character));
	}

	/*!
	* \brief Checks whether the string is less or equal than the "C string"
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator<=(const char* string, const String& nstring)
	{
		return !operator<(nstring, string);
	}

	/*!
	* \brief Checks whether the string is less or equal than the std::string
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator<=(const std::string& string, const String& nstring)
	{
		return !operator<(nstring, string);
	}

	/*!
	* \brief Checks whether the string is greather than the character
	* \return true if it is the case
	*
	* \param character Single character in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator>(char character, const String& nstring)
	{
		return nstring < character;
	}

	/*!
	* \brief Checks whether the string is greather than the "C string"
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator>(const char* string, const String& nstring)
	{
		return nstring < string;
	}

	/*!
	* \brief Checks whether the string is greather than the std::string
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator>(const std::string& string, const String& nstring)
	{
		return nstring < string;
	}

	/*!
	* \brief Checks whether the string is greather or equal than the character
	* \return true if it is the case
	*
	* \param character Single character in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator>=(char character, const String& nstring)
	{
		return !operator<(character, nstring);
	}

	/*!
	* \brief Checks whether the string is greather or equal than the "C string"
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator>=(const char* string, const String& nstring)
	{
		return !operator<(string, nstring);
	}

	/*!
	* \brief Checks whether the string is greather or equal than the std::string
	* \return true if it is the case
	*
	* \param string String to compare in left hand side
	* \param second String to compare in right hand side
	*/

	bool operator>=(const std::string& string, const String& nstring)
	{
		return !operator<(string, nstring);
	}

	/*!
	* \brief Ensures the ownership of the string
	*
	* \param discardContent Should discard the content
	*/

	void String::EnsureOwnership(bool discardContent)
	{
		if (!m_sharedString)
			return;

		if (!m_sharedString.unique())
		{
			auto newSharedString = std::make_shared<SharedString>(GetSize(), GetCapacity());
			if (!discardContent)
				std::memcpy(newSharedString->string.get(), GetConstBuffer(), GetSize()+1);

			m_sharedString = std::move(newSharedString);
		}
	}

	/*!
	* \brief Gets the empty string
	* \return A reference to the empty string
	*/

	const std::shared_ptr<String::SharedString>& String::GetEmptyString()
	{
		static auto emptyString = std::make_shared<SharedString>();
		return emptyString;
	}

	/*!
	* \brief Serializes a string
	* \return true if successful
	*
	* \param context Context of serialization
	* \param string String to serialize
	*/
	bool Serialize(SerializationContext& context, const String& string)
	{
		if (!Serialize<UInt32>(context, string.GetSize()))
			return false;

		return context.stream->Write(string.GetConstBuffer(), string.GetSize()) == string.GetSize();
	}

	/*!
	* \brief Unserializes a string
	* \return true if successful
	*
	* \param context Context of unserialization
	* \param string String to unserialize
	*/
	bool Unserialize(SerializationContext& context, String* string)
	{
		UInt32 size;
		if (!Unserialize(context, &size))
			return false;

		string->Resize(size);
		return context.stream->Read(string->GetBuffer(), size) == size;
	}

	const std::size_t String::npos(std::numeric_limits<std::size_t>::max());
}

namespace std
{
	/*!
	* \brief Gets the line from the input stream
	* \return A reference to the stream
	*
	* \param is Input stream to get information from
	* \param str String to set
	*/

	istream& getline(istream& is, Nz::String& str)
	{
		str.Clear();

		char c;

		for (;;)
                {
			is.get(c);
			if (c != '\n' && c != '\0')
				str += c;
			else
				break;
		}

		return is;
	}

	/*!
	* \brief Gets the line from the input stream
	* \return A reference to the stream
	*
	* \param is Input stream to get information from
	* \param str String to set
	* \param delim Delimitor defining the end
	*/

	istream& getline(istream& is, Nz::String& str, char delim)
	{
		str.Clear();

		char c;

		for (;;) 
		{
			is.get(c);
			if (c != delim && c != '\0')
				str += c;
			else
				break;
		}

		return is;
	}

	/*!
	* \brief Swaps two strings, specialisation of std
	*
	* \param lhs First string
	* \param rhs Second string
	*/

	void swap(Nz::String& lhs, Nz::String& rhs)
	{
		lhs.Swap(rhs);
	}
}
