Continue SSO

This commit is contained in:
Baptiste Wicht 2014-03-04 22:48:32 +01:00
parent 59482b3466
commit 554a0dec2d

View File

@ -1,5 +1,4 @@
//======================================================================= //=======================================================================// Copyright Baptiste Wicht 2013-2014.
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
@ -13,6 +12,8 @@
#include <vector.hpp> #include <vector.hpp>
#include <unique_ptr.hpp> #include <unique_ptr.hpp>
void k_print(const char* s);
namespace std { namespace std {
inline uint64_t str_len(const char* a){ inline uint64_t str_len(const char* a){
@ -23,41 +24,66 @@ inline uint64_t str_len(const char* a){
return length; return length;
} }
static constexpr const size_t SSO_SIZE = 16;
template<typename CharT> template<typename CharT>
struct base_small { struct base_long {
CharT data[SSO_SIZE];
};
template<typename CharT>
struct base_big {
size_t capacity; size_t capacity;
unique_ptr<CharT[]> data; unique_ptr<CharT[]> data;
base_big(size_t capacity, CharT* array) : capacity(capacity), data(array){ base_long() = default;
//Nothing to do
} base_long(size_t capacity, CharT* array) : capacity(capacity), data(array) {}
base_long(base_long&) = delete;
base_long& operator=(base_long&) = delete;
base_long(base_long&&) = default;
base_long& operator=(base_long&&) = default;
};
static constexpr const size_t min_capacity = 16;
static constexpr const size_t words = min_capacity / sizeof(size_t);
template<typename CharT>
struct base_short {
CharT data[min_capacity];
base_short() = default;
base_short(base_short&) = delete;
base_short& operator=(base_short&) = delete;
base_short(base_short&&) = default;
base_short& operator=(base_short&&) = default;
};
struct base_raw {
size_t data[words];
base_raw() = delete;
base_raw(base_raw&) = delete;
base_raw& operator=(base_raw&) = delete;
base_raw(base_raw&&) = delete;
base_raw& operator=(base_raw&&) = delete;
}; };
template<typename CharT> template<typename CharT>
union base_storage { union base_storage {
base_small<CharT> small; base_short<CharT> small;
base_big<CharT> big; base_long<CharT> big;
base_raw raw;
base_storage(){ base_storage(){
//Default construction: Nothing to do //Default construction: Nothing to do
} }
base_storage(size_t capacity, CharT* array) : big(capacity, array) {
//Default construction: Nothing to do
}
~base_storage() {} ~base_storage() {}
}; };
static_assert(SSO_SIZE == sizeof(base_small<char>), "base_small must be the correct SSO size"); static_assert(min_capacity == sizeof(base_short<char>), "base_short must be the correct SSO size");
static_assert(SSO_SIZE == sizeof(base_big<char>), "base_big must be the correct SSO size"); static_assert(min_capacity == sizeof(base_long<char>), "base_long must be the correct SSO size");
static_assert(min_capacity == sizeof(base_raw), "base_raw must be the correct SSO size");
template<typename CharT> template<typename CharT>
struct basic_string { struct basic_string {
@ -72,73 +98,144 @@ private:
base_storage<CharT> storage; base_storage<CharT> storage;
void set_long(bool small){
if(small){
_size |= (1UL << 63);
} else {
_size &= ~(1UL << 63);
}
}
void set_small(bool small){
set_long(!small);
}
void set_size(size_t size){
if(is_long()){
_size = size | (1UL << 63);
} else {
_size = size;
}
}
bool is_long() const {
return _size & (1UL << 63);
}
bool is_small() const { bool is_small() const {
return _size < 16; return !is_long();
}
void zero(){
for(size_t i = 0; i < words; ++i){
storage.raw.data[i] = 0;
}
} }
public: public:
//Constructors //Constructors
basic_string() : _size(0){ basic_string() : _size(0){
storage.small.data[0] = '\0'; k_print("basic_string ");
set_small(true);
(*this)[0] = '\0';
} }
basic_string(const CharT* s) : _size(str_len(s)) { basic_string(const CharT* s) : _size(str_len(s)) {
auto capacity = _size + 1; k_print("basic_string(raw) ");
auto capacity = size() + 1;
if(is_small()){ set_small(capacity <= 16);
std::copy_n(&storage.small.data[0], s, capacity);
} else { if(!is_small()){
storage.big.capacity = capacity; new (&storage.big) base_long<CharT>(capacity, new CharT[capacity]);
storage.big.data.reset(new CharT[capacity]);
std::copy_n(storage.big.data.get(), s, capacity);
} }
std::copy_n(begin(), s, capacity);
} }
explicit basic_string(size_t __capacity) : _size(0), _capacity(__capacity), _data(new CharT[_capacity]) { explicit basic_string(size_t __capacity) : _size(0) {
_data[0] = '\0'; k_print("basic_string(cap) ");
set_small(__capacity <= 16);
if(!is_small()){
new (&storage.big) base_long<CharT>(__capacity, new CharT[__capacity]);
}
(*this)[0] = '\0';
} }
//Copy constructors //Copy
basic_string(const basic_string& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data() { basic_string(const basic_string& rhs) : _size(rhs._size) {
if(_capacity > 0){ k_print("basic_string(&) ");
_data.reset(new CharT[_capacity]); if(!is_small()){
new (&storage.big) base_long<CharT>(size() + 1, new CharT[size() + 1]);
std::copy_n(_data.get(), rhs._data.get(), _size + 1);
} }
std::copy_n(begin(), rhs.begin(), size() + 1);
} }
basic_string& operator=(const basic_string& rhs){ basic_string& operator=(const basic_string& rhs){
k_print("operator=(&) ");
if(this != &rhs){ if(this != &rhs){
if(_capacity < rhs._capacity || !_data){ set_size(rhs.size());
_capacity = rhs._capacity;
_data.reset(new CharT[_capacity]); if(capacity() < rhs.capacity()){
auto capacity = rhs.capacity();
if(is_small()){
new (&storage.big) base_long<CharT>(capacity, new CharT[capacity]);
set_small(false);
} else {
storage.big.capacity = capacity;
storage.big.data.reset(new CharT[capacity]);
}
} }
_size = rhs._size; std::copy_n(begin(), rhs.begin(), size() + 1);
std::copy_n(_data.get(), rhs._data.get(), _size + 1);
} }
return *this; return *this;
} }
//Move constructors //Move
basic_string(basic_string&& rhs) : _size(rhs._size) {
k_print("basic_string(&&) ");
if(is_small()){
new (&storage.small) base_short<CharT>(std::move(rhs.storage.small));
} else {
new (&storage.big) base_long<CharT>(std::move(rhs.storage.big));
}
basic_string(basic_string&& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data(std::move(rhs._data)) {
rhs._size = 0; rhs._size = 0;
rhs._capacity = 0; rhs.zero();
//rhs._data = nullptr;
} }
basic_string& operator=(basic_string&& rhs){ basic_string& operator=(basic_string&& rhs){
k_print("operator=(&&) ");
if(!rhs.data_ptr()){
k_print("KABOOM ");
}
bool was_small = is_small();
_size = rhs._size; _size = rhs._size;
_capacity = rhs._capacity;
_data = std::move(rhs._data); if(is_small()){
storage.small = std::move(rhs.storage.small);
} else {
if(was_small){
new (&storage.big) base_long<CharT>(std::move(rhs.storage.big));
} else {
storage.big = std::move(rhs.storage.big);
}
}
rhs._size = 0; rhs._size = 0;
rhs._capacity = 0; rhs.zero();
//rhs._data = nullptr;
return *this; return *this;
} }
@ -146,24 +243,27 @@ public:
//Destructors //Destructors
~basic_string(){ ~basic_string(){
if(!is_small()){ k_print("~BS_S ");
storage.big.~base_big(); if(is_long()){
storage.big.~base_long();
} }
k_print("~BS_E ");
} }
//Modifiers //Modifiers
void adjust_size(size_t size){ void adjust_size(size_t size){
_size = size; set_size(size);
} }
void clear(){ void clear(){
_size = 0; set_size(0);
_data[0] = '\0'; (*this)[0] = '\0';
} }
void pop_back(){ void pop_back(){
_data[--_size] = '\0'; set_size(size() - 1);
(*this)[size()] = '\0';
} }
void reserve(size_t new_capacity){ void reserve(size_t new_capacity){
@ -179,52 +279,58 @@ public:
} }
basic_string& operator+=(CharT c){ basic_string& operator+=(CharT c){
ensure_capacity(_size + 2); ensure_capacity(size() + 2);
_data[_size] = c; (*this)[size()] = c;
_data[++_size] = '\0'; (*this)[size() + 1] = '\0';
set_size(size() + 1);
return *this; return *this;
} }
void ensure_capacity(size_t new_capacity){ void ensure_capacity(size_t new_capacity){
if(new_capacity > 0 && (!_data || _capacity < new_capacity)){ if(new_capacity > 0 && (capacity() < new_capacity)){
_capacity = _capacity ? _capacity * 2 : 1; k_print("grow ");
auto new_cap = capacity() * 2;
if(_capacity < new_capacity){ auto new_data = new CharT[new_cap];
_capacity = new_capacity;
std::copy_n(new_data, begin(), size());
if(is_small()){
new (&storage.big) base_long<CharT>(new_cap, new_data);
set_small(false);
} else {
storage.big.data.reset(new_data);
storage.big.capacity = new_cap;
} }
auto new_data = new CharT[_capacity];
std::copy_n(new_data, _data.get(), _size);
_data.reset(new_data);
} }
} }
basic_string& operator+=(const char* rhs){ basic_string& operator+=(const char* rhs){
auto len = str_len(rhs); auto len = str_len(rhs);
ensure_capacity(_size + len + 1); ensure_capacity(size() + len + 1);
std::copy_n(_data.get() + _size, rhs, len); std::copy_n(begin() + size(), rhs, len);
_size += len; set_size(size() + len);
_data[_size] = '\0'; (*this)[size()] = '\0';
return *this; return *this;
} }
basic_string& operator+=(const basic_string& rhs){ basic_string& operator+=(const basic_string& rhs){
ensure_capacity(_size + rhs.size() + 1); ensure_capacity(size() + rhs.size() + 1);
std::copy_n(_data.get() + _size, rhs.c_str(), rhs.size()); std::copy_n(begin() + size(), rhs.begin(), rhs.size());
_size += rhs.size(); set_size(size() + rhs.size());
_data[_size] = '\0'; (*this)[size()] = '\0';
return *this; return *this;
} }
@ -232,36 +338,56 @@ public:
//Accessors //Accessors
size_t size() const { size_t size() const {
return _size; return _size & ~(1UL << 63);
} }
size_t capacity() const { size_t capacity() const {
return _capacity; if(is_small()){
return 16;
} else {
return storage.big.capacity;
}
} }
bool empty() const { bool empty() const {
return !_size; return size() == 0;
}
CharT* data_ptr(){
if(is_small()){
return &storage.small.data[0];
} else {
return storage.big.data.get();
}
}
const CharT* data_ptr() const {
if(is_small()){
return &storage.small.data[0];
} else {
return storage.big.data.get();
}
} }
CharT* c_str(){ CharT* c_str(){
return _data.get(); return data_ptr();
} }
const CharT* c_str() const { const CharT* c_str() const {
return _data.get(); return data_ptr();
} }
CharT& operator[](size_t i){ CharT& operator[](size_t i){
return _data[i]; return *(data_ptr() + i);
} }
const CharT& operator[](size_t i) const { const CharT& operator[](size_t i) const {
return _data[i]; return *(data_ptr() + i);
} }
size_t find(char c) const { size_t find(char c) const {
for(size_t i = 0; i < size(); ++i){ for(size_t i = 0; i < size(); ++i){
if(_data[i] == c){ if((*this)[i] == c){
return i; return i;
} }
} }
@ -277,7 +403,7 @@ public:
} }
for(size_t i = 0; i < size(); ++i){ for(size_t i = 0; i < size(); ++i){
if(_data[i] != s[i]){ if((*this)[i] != s[i]){
return false; return false;
} }
} }
@ -295,7 +421,7 @@ public:
} }
for(size_t i = 0; i < size(); ++i){ for(size_t i = 0; i < size(); ++i){
if(_data[i] != rhs._data[i]){ if((*this)[i] != rhs[i]){
return false; return false;
} }
} }
@ -310,19 +436,19 @@ public:
//Iterators //Iterators
iterator begin(){ iterator begin(){
return iterator(&_data[0]); return iterator(data_ptr());
} }
iterator end(){ iterator end(){
return iterator(&_data[_size]); return iterator(data_ptr() + size());
} }
const_iterator begin() const { const_iterator begin() const {
return const_iterator(&_data[0]); return const_iterator(data_ptr());
} }
const_iterator end() const { const_iterator end() const {
return const_iterator(&_data[_size]); return const_iterator(data_ptr() + size());
} }
}; };