namespace nall { string::string() : _data(nullptr), _capacity(SSO - 1), _size(0) { } auto string::pointer() -> char* { if(_capacity < SSO) return _text; if(*_refs > 1) _copy(); return _data; } auto string::data() const -> const char* { if(_capacity < SSO) return _text; return _data; } auto string::reset() -> type& { if(_capacity >= SSO && !--*_refs) memory::free(_data); _data = nullptr; _capacity = SSO - 1; _size = 0; return *this; } auto string::reserve(unsigned capacity) -> type& { if(capacity <= _capacity) return *this; capacity = bit::round(capacity + 1) - 1; if(_capacity < SSO) { _capacity = capacity; _allocate(); } else if(*_refs > 1) { _capacity = capacity; _copy(); } else { _capacity = capacity; _resize(); } return *this; } auto string::resize(unsigned size) -> type& { reserve(size); pointer()[_size = size] = 0; return *this; } auto string::operator=(const string& source) -> type& { if(&source == this) return *this; reset(); if(source._capacity >= SSO) { _data = source._data; _refs = source._refs; _capacity = source._capacity; _size = source._size; ++*_refs; } else { memory::copy(_text, source._text, SSO); _capacity = source._capacity; _size = source._size; } return *this; } auto string::operator=(string&& source) -> type& { if(&source == this) return *this; reset(); memory::copy(this, &source, sizeof(string)); source._data = nullptr; source._capacity = SSO - 1; source._size = 0; return *this; } //SSO -> COW auto string::_allocate() -> void { char _temp[SSO]; memory::copy(_temp, _text, SSO); _data = (char*)memory::allocate(_capacity + 1 + sizeof(unsigned)); memory::copy(_data, _temp, SSO); _refs = (unsigned*)(_data + _capacity + 1); //always aligned by 32 via reserve() *_refs = 1; } //COW -> Unique auto string::_copy() -> void { auto _temp = (char*)memory::allocate(_capacity + 1 + sizeof(unsigned)); memory::copy(_temp, _data, _size = min(_capacity, _size)); _temp[_size] = 0; --*_refs; _data = _temp; _refs = (unsigned*)(_data + _capacity + 1); *_refs = 1; } //COW -> Resize auto string::_resize() -> void { _data = (char*)memory::resize(_data, _capacity + 1 + sizeof(unsigned)); _refs = (unsigned*)(_data + _capacity + 1); *_refs = 1; } }