672 lines
18 KiB
C++
Executable File
672 lines
18 KiB
C++
Executable File
#include "ustring.h"
|
||
#include "ustring_asm.h"
|
||
#include <fstream>
|
||
#include <cstring>
|
||
|
||
/**
|
||
* Конструктор по умолчанию
|
||
*/
|
||
ustring::ustring(): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||
{
|
||
_pData = new char32_t(0);
|
||
_len = 0;
|
||
_capacity = 0;
|
||
}
|
||
|
||
/**
|
||
* Копирующий конструктор
|
||
* @param str Исходная строка
|
||
*/
|
||
ustring::ustring(const ustring& str): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||
{
|
||
std::cout << "ustring copy constructor" << std::endl;
|
||
_len = str.length();
|
||
_capacity = _len;
|
||
_pData = new char32_t[_len + 1];
|
||
std::memcpy(_pData, str._pData, _len*sizeof(char32_t));
|
||
_pData[_len] = char32_t(0);
|
||
}
|
||
|
||
/**
|
||
* Конструктор перемещения
|
||
* @param str Исходная строка
|
||
* @detailed Данные перемещаются (не копируются!) из исходной строки
|
||
*/
|
||
ustring::ustring(ustring&& str): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||
{
|
||
std::cout << "ustring move constructor" << std::endl;
|
||
_pData = std::move(str._pData);
|
||
_len = str._len;
|
||
_capacity = _len;
|
||
str._pData = nullptr;
|
||
str._len = 0;
|
||
}
|
||
|
||
/**
|
||
* Конструктор из UTF-8 строки
|
||
* @param str Исходная строка в UTF-8 (null terminated)
|
||
* @param needUnescape Определяет нужно ли декодировать экранированные UTF-8 символы (\uXXXX и \UXXXXXXXX)
|
||
* @detailed Так как символы ASCII являются подмножеством UTF-8, при создании строки
|
||
* из массива ASCII символов нужно применять именно этот конструктор
|
||
*/
|
||
ustring::ustring(const char* str, bool needUnescape /* = false */): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||
{
|
||
init_from_utf8_str(str, needUnescape);
|
||
}
|
||
|
||
/**
|
||
* Конструктор из UTF-16 строки
|
||
* @param str Исходная строка в UTF-16 (null terminated)
|
||
* @param byteOrder Порядок байт
|
||
*/
|
||
ustring::ustring(const char16_t* str, byte_order byteOrder /* = BYTE_ORDER_LITTLE_ENDIAN */): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||
{
|
||
init_from_utf16_str(str, byteOrder);
|
||
}
|
||
|
||
/**
|
||
* Конструктор из UTF-32 строки
|
||
* @param str Исходная строка в UTF-32 (null terminated)
|
||
* @param byteOrder Порядок байт
|
||
*/
|
||
ustring::ustring(const char32_t* str, byte_order byteOrder /* = BYTE_ORDER_LITTLE_ENDIAN */): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||
{
|
||
init_from_utf32_str(str, byteOrder);
|
||
}
|
||
|
||
/**
|
||
* Конструктор из std::string
|
||
* @param str Исходная строка в UTF-8
|
||
* @param needUnescape Определяет нужно ли декодировать экранированные UTF-8 символы (\uXXXX и \UXXXXXXXX)
|
||
*/
|
||
ustring::ustring(const std::string& str, bool needUnescape /* = false */): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||
{
|
||
init_from_utf8_str(str.c_str(), needUnescape);
|
||
}
|
||
|
||
/**
|
||
* Конструктор из std::wstring
|
||
* @param str Исходная строка в UTF-16/UTF-32 (в зависимости от платформы)
|
||
*/
|
||
ustring::ustring(const std::wstring& str): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||
{
|
||
#ifdef __GNUC__
|
||
init_from_utf32_str((const char32_t*)str.c_str());
|
||
#else
|
||
init_from_utf16_str((const char16_t*)str.c_str());
|
||
#endif
|
||
}
|
||
|
||
ustring::ustring( std::size_t n ): _pUtf8(nullptr), _pUtf16(nullptr), _pUtf32(nullptr)
|
||
{
|
||
_pData = new char32_t[n + 1];
|
||
_len = 0;
|
||
_capacity = n;
|
||
}
|
||
|
||
|
||
void ustring::init_from_utf8_str(const char* str, bool needUnescape)
|
||
{
|
||
const char* strData = utf8_skip_bom(str);
|
||
_len = utf8_str_len(strData, needUnescape);
|
||
_capacity = _len;
|
||
_pData = new char32_t[_len + 1];
|
||
utf8_to_ucs4(strData, _pData, _len, needUnescape);
|
||
_pData[_len] = char32_t(0);
|
||
}
|
||
|
||
inline void ustring::init_from_utf16_str( const char16_t* str, byte_order byteOrder /*= BYTE_ORDER_LITTLE_ENDIAN*/ )
|
||
{
|
||
const char16_t* strData = utf16_skip_bom(str);
|
||
_len = utf16_str_len(strData);
|
||
_capacity = _len;
|
||
_pData = new char32_t[_len + 1];
|
||
utf16_to_ucs4(strData, _pData, _len, byteOrder);
|
||
_pData[_len] = char32_t(0);
|
||
}
|
||
|
||
inline void ustring::init_from_utf32_str( const char32_t* str, byte_order byteOrder /*= BYTE_ORDER_LITTLE_ENDIAN*/ )
|
||
{
|
||
const char32_t* strData = utf32_skip_bom(str);
|
||
_len = utf32_str_len(strData);
|
||
_capacity = _len;
|
||
_pData = new char32_t[_len + 1];
|
||
utf32_strcpy_with_convert_byteorder(str, _pData, _len, byteOrder);
|
||
_pData[_len] = char32_t(0);
|
||
}
|
||
|
||
ustring::operator std::string() const
|
||
{
|
||
return utf8_str();
|
||
}
|
||
|
||
ustring::operator std::wstring() const
|
||
{
|
||
#ifdef __GNUC__
|
||
return (wchar_t*)utf32_str();
|
||
#else
|
||
return (wchar_t*)utf16_str();
|
||
#endif
|
||
}
|
||
|
||
/**
|
||
* Возвращает указатель на временный буфер с UTF-8 строкой
|
||
* @param addBom Указывает, добавлять ли BOM в возвращаемую строку
|
||
* @param needEscape Определяет, нужно ли экранировать не-ASCII символы
|
||
* @return Указатель на буфер со строкой, закодированной в UTF-8
|
||
* @detailed Этот буфер является временным и будет высвобожден при любом изменении строки
|
||
*/
|
||
const char* ustring::utf8_str(bool addBom /*= false*/ , bool needEscape /*= false*/) const
|
||
{
|
||
std::size_t bomSize = (addBom ? sizeof(g_utf8_bom) : 0);
|
||
std::size_t len = ucs4_get_utf8_str_bytes(_pData, needEscape);
|
||
_pUtf8 = new char[bomSize + len + 1];
|
||
ucs4_to_utf8(_pData, _pUtf8 + bomSize, length(), needEscape);
|
||
_pUtf8[len + bomSize] = char(0);
|
||
|
||
if(addBom)
|
||
{
|
||
memcpy(_pUtf8, g_utf8_bom, bomSize);
|
||
}
|
||
|
||
return _pUtf8;
|
||
}
|
||
|
||
/**
|
||
* @param addBom Указывает, добавлять ли BOM в возвращаемую строку
|
||
* @param byteOrder Задает порядок байт в возвращаемой строке
|
||
* @return Указатель на буфер со строкой, закодированной в UTF-16
|
||
*/
|
||
const char16_t* ustring::utf16_str( bool addBom /*= false*/, byte_order byteOrder /*= BYTE_ORDER_LITTLE_ENDIAN*/ ) const
|
||
{
|
||
std::size_t bomSize = (addBom ? sizeof(g_utf16le_bom)/2 : 0);
|
||
std::size_t len = ucs4_get_utf16_str_bytes(_pData)/2;
|
||
_pUtf16 = new char16_t[bomSize + len + 1];
|
||
ucs4_to_utf16(_pData, _pUtf16 + bomSize, length(), byteOrder);
|
||
_pUtf16[len + bomSize] = char16_t(0);
|
||
|
||
if(addBom)
|
||
{
|
||
memcpy(_pUtf16, (byteOrder == BYTE_ORDER_LITTLE_ENDIAN ? g_utf16le_bom : g_utf16be_bom), sizeof(g_utf16le_bom));
|
||
}
|
||
|
||
return _pUtf16;
|
||
}
|
||
|
||
/**
|
||
* @param addBom Указывает, добавлять ли BOM в возвращаемую строку
|
||
* @param byteOrder Задает порядок байт в возвращаемой строке
|
||
* @return Указатель на буфер со строкой, закодированной в UTF-32
|
||
*/
|
||
const char32_t* ustring::utf32_str( bool addBom /*= false*/, byte_order byteOrder /*= BYTE_ORDER_LITTLE_ENDIAN*/ ) const
|
||
{
|
||
std::size_t bomSize = (addBom ? sizeof(g_utf32le_bom)/sizeof(char32_t) : 0);
|
||
_pUtf32 = new char32_t[bomSize + _len + 1];
|
||
utf32_strcpy_with_convert_byteorder(_pData, _pUtf32 + bomSize, _len, byteOrder);
|
||
_pUtf32[_len + bomSize] = char16_t(0);
|
||
|
||
if(addBom)
|
||
{
|
||
memcpy(_pUtf32, (byteOrder == BYTE_ORDER_LITTLE_ENDIAN ? g_utf32le_bom : g_utf32be_bom), sizeof(g_utf32le_bom));
|
||
}
|
||
|
||
return _pUtf32;
|
||
}
|
||
|
||
ustring::~ustring()
|
||
{
|
||
delete[] _pData;
|
||
delete[] _pUtf8;
|
||
delete[] _pUtf16;
|
||
delete[] _pUtf32;
|
||
}
|
||
|
||
void ustring::clear_internal_buffers() const
|
||
{
|
||
if(_pUtf8)
|
||
{
|
||
delete[] _pUtf8;
|
||
_pUtf8 = nullptr;
|
||
}
|
||
if(_pUtf16)
|
||
{
|
||
delete[] _pUtf16;
|
||
_pUtf16 = nullptr;
|
||
}
|
||
if(_pUtf32)
|
||
{
|
||
delete[] _pUtf32;
|
||
_pUtf32 = nullptr;
|
||
}
|
||
}
|
||
|
||
std::ostream& operator<<(std::ostream& os, const ustring& str)
|
||
{
|
||
os << str.utf8_str();
|
||
|
||
return os;
|
||
}
|
||
|
||
std::istream& operator>>(std::istream& is, ustring& ustr)
|
||
{
|
||
std::string str;
|
||
|
||
is >> str;
|
||
ustr = str;
|
||
|
||
return is;
|
||
}
|
||
|
||
/**
|
||
* @brief Возвращает длину строки
|
||
* @return Длина строки в символах (не вы байтах!)
|
||
*/
|
||
std::size_t ustring::length() const
|
||
{
|
||
return _len;
|
||
}
|
||
|
||
ustring& ustring::operator=(const ustring& str)
|
||
{
|
||
std::cout << "ustring copy assign operator" << std::endl;
|
||
|
||
if(this == &str)
|
||
{
|
||
return *this;
|
||
}
|
||
|
||
delete _pData;
|
||
clear_internal_buffers();
|
||
|
||
_len = str.length();
|
||
_capacity = _len;
|
||
_pData = new char32_t[_len + 1];
|
||
std::memcpy(_pData, str._pData, _len*sizeof(char32_t));
|
||
_pData[_len] = char32_t(0);
|
||
|
||
return *this;
|
||
}
|
||
|
||
ustring& ustring::operator=(ustring&& str)
|
||
{
|
||
std::cout << "ustring move assign operator" << std::endl;
|
||
|
||
if(this == &str)
|
||
{
|
||
return *this;
|
||
}
|
||
|
||
delete _pData;
|
||
clear_internal_buffers();
|
||
|
||
_pData = std::move(str._pData);
|
||
_len = str._len;
|
||
_capacity = _len;
|
||
str._pData = nullptr;
|
||
str._len = 0;
|
||
|
||
return *this;
|
||
}
|
||
|
||
ustring& ustring::operator+=(const ustring& str)
|
||
{
|
||
clear_internal_buffers();
|
||
|
||
std::size_t curLength = length(), strLength = str.length();
|
||
std::size_t totalLength = curLength + strLength;
|
||
|
||
char32_t* pBuffer = new char32_t[totalLength + 1];
|
||
std::memcpy(pBuffer, _pData, curLength*sizeof(char32_t));
|
||
std::memcpy(pBuffer + curLength, str._pData, strLength*sizeof(char32_t));
|
||
pBuffer[totalLength] = char32_t(0);
|
||
delete _pData;
|
||
_pData = pBuffer;
|
||
_len = totalLength;
|
||
return *this;
|
||
}
|
||
|
||
|
||
ustring& ustring::operator+(const ustring& str)
|
||
{
|
||
return (*this += str);
|
||
}
|
||
|
||
char32_t& ustring::operator[](std::size_t index)
|
||
{
|
||
return _pData[index];
|
||
}
|
||
|
||
bool ustring::operator==( const ustring& str ) const
|
||
{
|
||
return ( (_len == str._len) && (!memcmp(_pData, str._pData, _len*sizeof(char32_t))) );
|
||
}
|
||
|
||
bool ustring::operator!=( const ustring& str ) const
|
||
{
|
||
return !(*this == str);
|
||
}
|
||
|
||
/**
|
||
* Поиск символа в строке
|
||
* @param symbol Символ, который требуется найти
|
||
* @param pos Начальная позиция, с которой начинается поиск
|
||
* @return индекс символа в строке или ustring::npos, если символ не найден
|
||
*/
|
||
std::size_t ustring::find(char32_t symbol, std::size_t pos /* = 0 */) const
|
||
{
|
||
char32_t* pBuf = _pData + pos;
|
||
|
||
do
|
||
{
|
||
if(*pBuf == symbol)
|
||
{
|
||
return (pBuf - _pData);
|
||
}
|
||
}
|
||
while(*pBuf++ != 0);
|
||
|
||
return npos;
|
||
}
|
||
|
||
/**
|
||
* Поиск подстроки в строке
|
||
* @param строка, которую требуется найти
|
||
* @param pos Начальная позиция, с которой начинается поиск
|
||
* @return индекс символа в строке или ustring::npos, если строка не найдена
|
||
*/
|
||
std::size_t ustring::find(const ustring& str, std::size_t pos /* = 0 */) const
|
||
{
|
||
if(str.length() > (_len - pos))
|
||
{
|
||
return npos;
|
||
}
|
||
|
||
#if defined(__GNUC__) // GCC and clang
|
||
/*
|
||
char32_t* fpos = reinterpret_cast<char32_t*>(memmem(_pData + pos, (_len - pos)*sizeof(char32_t), str._pData, str._len*sizeof(char32_t)));
|
||
if(fpos)
|
||
{
|
||
return (fpos - _pData);
|
||
}
|
||
*/
|
||
const char32_t* fpos = _asm_ucs4_strstr(_pData + pos, (_len - pos), str._pData, str._len);
|
||
if(fpos)
|
||
{
|
||
return (fpos - _pData);
|
||
}
|
||
#else
|
||
const char32_t* pStr = str._pData;
|
||
const std::size_t len = _len - str.length();
|
||
for(std::size_t i = pos; i <= len; ++i)
|
||
{
|
||
if(_pData[i] == *pStr)
|
||
{
|
||
if(!memcmp(&_pData[i], pStr, str.length()*sizeof(char32_t)))
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
return npos;
|
||
}
|
||
|
||
/**
|
||
* Загружает содержимое текстового файла в строку
|
||
* @param fileName Имя файла
|
||
* @param enc Кодировка файла
|
||
* @return Количество считанных байт
|
||
*/
|
||
std::size_t ustring::load_from_file( const ustring& fileName, encoding enc ) // TODO: this terrible function needs refactoring
|
||
{
|
||
std::ifstream file;
|
||
|
||
#ifdef WIN32
|
||
file.open(fileName.utf16_str(), std::ios::binary);
|
||
#else
|
||
file.open(fileName.utf8_str(), std::ios::binary);
|
||
#endif
|
||
|
||
// get file size
|
||
file.seekg(0, std::ios::end);
|
||
std::size_t fileLength = static_cast<std::size_t>(file.tellg());
|
||
file.seekg(0, std::ios::beg);
|
||
|
||
char* fileData = new char[fileLength + sizeof(char32_t)];
|
||
file.read(fileData, fileLength);
|
||
std::memset(fileData + fileLength, 0, sizeof(char32_t));
|
||
|
||
switch(enc)
|
||
{
|
||
case ustring::UTF8:
|
||
*this = ustring(fileData);
|
||
break;
|
||
case ustring::UTF16LE:
|
||
*this = ustring(reinterpret_cast<char16_t*>(fileData));
|
||
break;
|
||
case ustring::UTF32LE:
|
||
*this = ustring(reinterpret_cast<char32_t*>(fileData));
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return fileLength;
|
||
}
|
||
|
||
/**
|
||
* Сохраняет содержимое строки в текстовый файл
|
||
* @param fileName Имя файла
|
||
* @param enc Кодировка файла
|
||
* @return Количество записанных байт
|
||
*/
|
||
std::size_t ustring::store_to_file( const ustring& fileName, encoding enc ) const // TODO: this terrible function needs refactoring
|
||
{
|
||
std::ofstream file;
|
||
const char* data = nullptr;
|
||
std::size_t dataSize = 0;
|
||
|
||
const char utf16leBom[] = { char(0xFF), char(0xFE) };
|
||
const char utf8Bom[] = { char(0xEF), char(0xBB), char(0xBF) };
|
||
const char utf32leBom[] = { char(0xFF), char(0xFE), char(0x00), char(0x00)};
|
||
|
||
#ifdef WIN32
|
||
file.open(fileName.utf16_str(), std::ios::binary);
|
||
#else
|
||
file.open(fileName.utf8_str(), std::ios::binary);
|
||
#endif
|
||
|
||
switch(enc)
|
||
{
|
||
case ustring::UTF8:
|
||
data = utf8_str();
|
||
dataSize = ucs4_get_utf8_str_bytes(_pData, false);
|
||
file.write(utf8Bom, sizeof(utf8Bom));
|
||
break;
|
||
case ustring::UTF16LE:
|
||
data = reinterpret_cast<const char*>(utf16_str());
|
||
dataSize = ucs4_get_utf16_str_bytes(_pData);
|
||
file.write(utf16leBom, sizeof(utf16leBom));
|
||
break;
|
||
case ustring::UTF32LE:
|
||
data = reinterpret_cast<const char*>(utf32_str());
|
||
dataSize = utf32_str_len(utf32_str())*sizeof(char32_t);
|
||
file.write(utf32leBom, sizeof(utf32leBom));
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
file.write(data, dataSize);
|
||
|
||
return dataSize;
|
||
}
|
||
|
||
/**
|
||
* Очищает строку
|
||
*/
|
||
void ustring::clear()
|
||
{
|
||
*_pData = char32_t(0);
|
||
_len = 0;
|
||
clear_internal_buffers();
|
||
}
|
||
|
||
/**
|
||
* Проверяет строку на пустоту
|
||
* @return true, если строка имеет ненулевую длину, иначе false
|
||
*/
|
||
bool ustring::empty() const
|
||
{
|
||
return (_len == 0);
|
||
}
|
||
|
||
/**
|
||
* Выделяет подстроку из строки
|
||
* @param pos Позиция требуемой подстроки
|
||
* @param len Длина подстроки в символах
|
||
* @return Возвращает искомую подстроку
|
||
*/
|
||
ustring ustring::substr( size_t pos /*= 0*/, size_t len /*= npos*/ ) const
|
||
{
|
||
std::size_t bufLength = (len == npos ? (_len - pos) : len);
|
||
ustring retVal(bufLength);
|
||
|
||
retVal.assign(_pData + pos, bufLength);
|
||
return retVal;
|
||
}
|
||
|
||
/**
|
||
* Формирует строку из массива символов заданного размера
|
||
* @param str Массив символов UCS-4
|
||
* @param n Количество символов
|
||
* @return *this
|
||
*/
|
||
ustring& ustring::assign( const char32_t* str, std::size_t n )
|
||
{
|
||
clear_internal_buffers();
|
||
|
||
if(n == 0)
|
||
{
|
||
clear();
|
||
return *this;
|
||
}
|
||
|
||
if(n > _capacity)
|
||
{
|
||
delete[] _pData;
|
||
_pData = new char32_t[n + 1];
|
||
_capacity = n;
|
||
}
|
||
|
||
memcpy(_pData, str, n*sizeof(char32_t));
|
||
_pData[n] = char32_t(0);
|
||
_len = n;
|
||
|
||
return *this;
|
||
}
|
||
|
||
/**
|
||
* Вырезает часть строки
|
||
* @param pos Начало вырезаемой части строки
|
||
* @param len Длина вырезаемой части строки
|
||
* @return *this
|
||
*/
|
||
ustring& ustring::erase( std::size_t pos /*= 0*/, std::size_t len /*= npos*/ )
|
||
{
|
||
if((pos >= _len) || (len == 0))
|
||
{
|
||
return *this;
|
||
}
|
||
|
||
std::size_t bufLength = (len == npos ? (_len - pos) : len);
|
||
|
||
if(len == npos || (pos + len == _len))
|
||
{
|
||
_pData[pos] = char32_t(0);
|
||
_len = pos;
|
||
}
|
||
else
|
||
{
|
||
memmove(_pData + pos, _pData + pos + bufLength, (_len - pos - len)*sizeof(char32_t));
|
||
_pData[_len - bufLength] = char32_t(0);
|
||
_len -= bufLength;
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
|
||
/**
|
||
* Вставляет строку в произвольное место исходной строки
|
||
* @param pos Позиция для вставки строки
|
||
* @param str Вставляемая строка
|
||
* @return *this
|
||
*/
|
||
ustring& ustring::insert( std::size_t pos, const ustring& str )
|
||
{
|
||
std::size_t destLength = _len + str.length();
|
||
clear_internal_buffers();
|
||
|
||
if(pos > _len)
|
||
{
|
||
pos = _len;
|
||
}
|
||
|
||
if(_capacity < destLength)
|
||
{
|
||
const char32_t* oldData = _pData;
|
||
_pData = new char32_t[destLength + 1];
|
||
_capacity = destLength;
|
||
memcpy(_pData, oldData, pos*sizeof(char32_t));
|
||
memcpy(_pData + pos, str._pData, str.length()*sizeof(char32_t));
|
||
memcpy(_pData + pos + str.length(), oldData + pos, (_len - pos)*sizeof(char32_t));
|
||
delete[] oldData;
|
||
}
|
||
else
|
||
{
|
||
memmove(_pData + pos + str.length(), _pData + pos, (_len - pos)*sizeof(char32_t));
|
||
memcpy(_pData + pos, str._pData, str.length()*sizeof(char32_t));
|
||
}
|
||
|
||
_len = destLength;
|
||
return *this;
|
||
}
|
||
|
||
/**
|
||
* Заменяет все вхождения подстроки "what" на строку "by"
|
||
* @param what Подстрока, которую нужно заменить
|
||
* @param by Строка, которая замещает исходную
|
||
* @return *this
|
||
*/
|
||
ustring& ustring::replace( const ustring& what, const ustring& by )
|
||
{
|
||
std::ptrdiff_t diff = by.length() - what.length();
|
||
std::size_t pos = 0, newLength = _len;
|
||
clear_internal_buffers();
|
||
|
||
while((pos = find(what, pos)) != npos)
|
||
{
|
||
if((diff > 0) && (_len + diff > _capacity))
|
||
{
|
||
newLength = _len + diff*5;
|
||
const char32_t* oldData = _pData;
|
||
_pData = new char32_t[newLength + 1];
|
||
_capacity = newLength;
|
||
memcpy(_pData, oldData, pos*sizeof(char32_t));
|
||
memcpy(_pData + pos, by._pData, by.length()*sizeof(char32_t));
|
||
memcpy(_pData + pos + by.length(), oldData + pos + what.length(), (_len - pos - what.length())*sizeof(char32_t));
|
||
delete[] oldData;
|
||
}
|
||
else
|
||
{
|
||
memmove(_pData + pos + by.length(), _pData + pos + what.length(), (_len - pos - what.length())*sizeof(char32_t));
|
||
memcpy(_pData + pos, by._pData, by.length()*sizeof(char32_t));
|
||
}
|
||
|
||
_len += diff;
|
||
}
|
||
|
||
return *this;
|
||
}
|