00001
00032 #ifndef INCLUDE_GUARD_2EE24263_BD1F_4E5D_8CDA_A3217E867BF0
00033 #define INCLUDE_GUARD_2EE24263_BD1F_4E5D_8CDA_A3217E867BF0
00034
00035 #include <algorithm>
00036 #include <cstddef>
00037 #include <climits>
00038 #include <cstring>
00039 #include <ostream>
00040 #include <string>
00041
00042 #include <type_traits>
00043
00044 #include <iostream>
00045
00046 namespace ssoX {
00047
00048 namespace detail {
00049
00050 static std::size_t const high_bit_mask = static_cast<std::size_t>(1) << (sizeof(std::size_t) * CHAR_BIT - 1);
00051 static std::size_t const sec_high_bit_mask = static_cast<std::size_t>(1) << (sizeof(std::size_t) * CHAR_BIT - 2);
00052
00053 template <typename T>
00054 unsigned char* uchar_cast(T* p) {
00055 return reinterpret_cast<unsigned char*>(p);
00056 }
00057
00058 template <typename T>
00059 unsigned char const* uchar_cast(T const* p) {
00060 return reinterpret_cast<unsigned char const*>(p);
00061 }
00062
00063 template <typename T>
00064 unsigned char& most_sig_byte(T& obj) {
00065 return *(reinterpret_cast<unsigned char*>(&obj) + sizeof(obj) - 1);
00066 }
00067
00068 template <int N>
00069 bool lsb(unsigned char byte) {
00070 return byte & (1u << N);
00071 }
00072
00073 template <int N>
00074 bool msb(unsigned char byte) {
00075 return byte & (1u << (CHAR_BIT - N - 1));
00076 }
00077
00078 template <int N>
00079 void set_lsb(unsigned char& byte, bool bit) {
00080 if(bit) {
00081 byte |= 1u << N;
00082 } else {
00083 byte &= ~(1u << N);
00084 }
00085 }
00086
00087 template <int N>
00088 void set_msb(unsigned char& byte, bool bit) {
00089 if(bit) {
00090 byte |= 1u << (CHAR_BIT - N - 1);
00091 } else {
00092 byte &= ~(1u << (CHAR_BIT - N - 1));
00093 }
00094 }
00095
00096 }
00097
00098 template <typename CharT, typename Traits = std::char_traits<CharT>>
00099 class basic_string {
00100 typedef typename std::make_unsigned<CharT>::type UCharT;
00101 public:
00102 basic_string() noexcept
00103 : basic_string("", static_cast<std::size_t>(0)) {
00104 }
00105
00106 basic_string(CharT const* string, std::size_t size) {
00107
00108 if(size <= sso_capacity) {
00109 Traits::move(m_data.sso.string, string, size);
00110 Traits::assign(m_data.sso.string[size], static_cast<CharT>(0));
00111 set_sso_size(size);
00112 } else {
00113 size_t new_size = std::max( sso_capacity*2, size );
00114 m_data.non_sso.ptr = new CharT[new_size +1 ];
00115 Traits::move(m_data.non_sso.ptr, string, size);
00116 Traits::assign(m_data.non_sso.ptr[size], static_cast<CharT>(0));
00117 set_non_sso_data(size, size);
00118 }
00119 }
00120
00121 basic_string(CharT const* string)
00122 : basic_string{string, std::strlen(string)} {
00123 }
00124
00125 basic_string(const basic_string& other) {
00126 if(other.sso()) {
00127 m_data.sso = other.m_data.sso;
00128 } else {
00129 new (this) basic_string{other.data(), other.size() };
00130 }
00131 }
00132
00133 basic_string(basic_string&& other) noexcept {
00134 m_data = other.m_data;
00135 other.set_moved_from();
00136 }
00137
00138 basic_string(const std::basic_string<CharT>& other):
00139 basic_string( other.c_str(), other.size() )
00140 {
00141
00142 }
00143
00144 basic_string& operator=(basic_string const& other) {
00145 auto copy = other;
00146 swap(copy, *this);
00147 return *this;
00148 }
00149
00150 basic_string& operator=(basic_string&& other) {
00151 this->~basic_string();
00152 m_data = other.m_data;
00153 other.set_moved_from();
00154 return *this;
00155 }
00156
00157 basic_string& operator=(const std::basic_string<CharT>& other) {
00158 *this = basic_string( other.data(), other.size() );
00159 return *this;
00160 }
00161
00162 basic_string operator+(basic_string const& other) {
00163 basic_string out( *this) ;
00164 out.append( other.data(), other.size() );
00165 return out;
00166 }
00167
00168 void clear()
00169 {
00170 this->resize(0);
00171 }
00172
00173 void assign(const CharT* buffer, size_t length )
00174 {
00175 this->resize(length);
00176
00177 if(length <= sso_capacity) {
00178 Traits::move( m_data.sso.string, buffer, length);
00179 } else {
00180 Traits::move( m_data.non_sso.ptr, buffer, length);
00181 }
00182 }
00183
00184 void resize( size_t new_size)
00185 {
00186 size_t old_size = this->size();
00187 if(new_size <= sso_capacity)
00188 {
00189
00190 if( !this->sso() ) {
00191 CharT* ptr = m_data.non_sso.ptr;
00192 Traits::move( m_data.sso.string, ptr, std::min(old_size, new_size) );
00193 delete[] ptr;
00194 }
00195 Traits::assign(m_data.sso.string[new_size], static_cast<CharT>(0));
00196 set_sso_size(new_size);
00197 } else {
00198
00199 size_t new_capacity = 0;
00200 CharT* ptr = nullptr;
00201
00202 if( this->sso() ){
00203
00204 new_capacity = std::max(new_size, sso_capacity*2);
00205 ptr = new CharT[ new_capacity + 1];
00206 Traits::move( ptr, m_data.sso.string, std::min(old_size, new_size) );
00207 m_data.non_sso.ptr = ptr;
00208 }
00209 else if( new_size < capacity() ){
00210
00211 new_capacity = capacity();
00212 ptr = m_data.non_sso.ptr;
00213 }
00214 else{
00215
00216 new_capacity = std::max(new_size, capacity()*3/2);
00217 ptr = new CharT[ new_capacity + 1];
00218 Traits::move( ptr, m_data.non_sso.ptr, std::min(old_size, new_size) );
00219 delete[] m_data.non_sso.ptr ;
00220 m_data.non_sso.ptr = ptr;
00221 }
00222
00223 Traits::assign(m_data.non_sso.ptr[new_size], static_cast<CharT>(0));
00224 set_non_sso_data(new_size, new_capacity);
00225 }
00226 }
00227
00228 basic_string& append(const basic_string& other)
00229 {
00230 return append( other.data(), other.size() );
00231 }
00232
00233 basic_string& append(CharT const* string)
00234 {
00235 return append( string, std::strlen(string) );
00236 }
00237
00238 basic_string& append(CharT const* string,size_t length)
00239 {
00240 size_t old_size = this->size();
00241 size_t new_size = old_size + length ;
00242
00243 this->resize( new_size );
00244
00245 if(new_size <= sso_capacity) {
00246 Traits::move( &m_data.sso.string[old_size], string, length);
00247 Traits::assign(m_data.sso.string[new_size], static_cast<CharT>(0));
00248 } else {
00249 Traits::move( &m_data.non_sso.ptr[old_size], string, length);
00250 Traits::assign(m_data.non_sso.ptr[new_size], static_cast<CharT>(0));
00251 }
00252 return *this;
00253 }
00254
00255 ~basic_string() {
00256 if(!sso()) {
00257 delete[] m_data.non_sso.ptr;
00258 }
00259 }
00260
00261 CharT const* data() const noexcept {
00262 return sso() ? m_data.sso.string : m_data.non_sso.ptr;
00263 }
00264
00265 std::size_t size() const noexcept {
00266 if(sso()) {
00267 return sso_size();
00268 } else {
00269 return read_non_sso_data().first;
00270 }
00271 }
00272
00273 const char at( size_t index )
00274 {
00275 return data()[index];
00276 }
00277
00278 const char at( size_t index ) const
00279 {
00280 return data()[index];
00281 }
00282
00283 std::size_t capacity() const noexcept {
00284 if(sso()) {
00285 return sizeof(m_data) - 1;
00286 } else {
00287 return read_non_sso_data().second;
00288 }
00289 }
00290
00291 friend void swap(basic_string& lhs, basic_string& rhs) {
00292 std::swap(lhs.m_data, rhs.m_data);
00293 }
00294
00295
00296 bool isSso() const noexcept {
00297 return sso();
00298 }
00299
00300 int compare(const basic_string& other)
00301 {
00302 return strcmp( data(), other.data() );
00303 }
00304
00305 std::basic_string<CharT> toStdString() const {
00306 return std::basic_string<CharT>(data(), size() );
00307 }
00308
00309
00310 private:
00311 void set_moved_from() {
00312 set_sso_size(0);
00313 }
00314
00315
00316 bool sso() const noexcept {
00317 return !detail::lsb<0>(m_data.sso.size) && !detail::lsb<1>(m_data.sso.size);
00318 }
00319
00320
00321 void set_sso_size(unsigned char size) noexcept {
00322 m_data.sso.size = static_cast<UCharT>(sso_capacity - size) << 2;
00323 }
00324
00325
00326 std::size_t sso_size() const noexcept {
00327 return sso_capacity - ((m_data.sso.size >> 2) & 63u);
00328 }
00329
00330 void set_non_sso_data(std::size_t size, std::size_t capacity) {
00331 auto& size_hsb = detail::most_sig_byte(size);
00332 auto const size_high_bit = detail::msb<0>(size_hsb);
00333
00334 auto& cap_hsb = detail::most_sig_byte(capacity);
00335 auto const cap_high_bit = detail::msb<0>(cap_hsb);
00336 auto const cap_sec_high_bit = detail::msb<1>(cap_hsb);
00337
00338 detail::set_msb<0>(size_hsb, cap_sec_high_bit);
00339
00340 cap_hsb <<= 2;
00341 detail::set_lsb<0>(cap_hsb, cap_high_bit);
00342 detail::set_lsb<1>(cap_hsb, !size_high_bit);
00343
00344 m_data.non_sso.size = size;
00345 m_data.non_sso.capacity = capacity;
00346 }
00347
00348 std::pair<std::size_t, std::size_t> read_non_sso_data() const {
00349 auto size = m_data.non_sso.size;
00350 auto capacity = m_data.non_sso.capacity;
00351
00352 auto& size_hsb = detail::most_sig_byte(size);
00353 auto& cap_hsb = detail::most_sig_byte(capacity);
00354
00355
00356 auto const cap_high_bit = detail::lsb<0>(cap_hsb);
00357 auto const size_high_bit = !detail::lsb<1>(cap_hsb);
00358 auto const cap_sec_high_bit = detail::msb<0>(size_hsb);
00359
00360 detail::set_msb<0>(size_hsb, size_high_bit);
00361
00362 cap_hsb >>= 2;
00363 detail::set_msb<0>(cap_hsb, cap_high_bit);
00364 detail::set_msb<1>(cap_hsb, cap_sec_high_bit);
00365
00366 return std::make_pair(size, capacity);
00367 }
00368
00369 private:
00370 union Data {
00371 struct NonSSO {
00372 CharT overhead[ 32 - sizeof(CharT*) - 2*sizeof(std::size_t)];
00373 CharT* ptr;
00374 std::size_t size;
00375 std::size_t capacity;
00376 } non_sso;
00377 struct SSO {
00378 CharT string [ sizeof(NonSSO) / sizeof(CharT) - 1];
00379 UCharT size;
00380 } sso;
00381 } m_data;
00382
00383 public:
00384 static std::size_t const sso_capacity = sizeof(typename Data::NonSSO) / sizeof(CharT) - 1;
00385 };
00386
00387 template <typename CharT, typename Traits>
00388 bool operator==(const basic_string<CharT, Traits>& lhs, const CharT* rhs) noexcept {
00389 return !std::strcmp(lhs.data(), rhs);
00390 }
00391
00392 template <typename CharT, typename Traits>
00393 bool operator==(const CharT* lhs, const basic_string<CharT, Traits>& rhs) noexcept {
00394 return rhs == lhs;
00395 }
00396
00397 template <typename CharT, typename Traits>
00398 bool operator==(const basic_string<CharT, Traits>& lhs,
00399 const basic_string<CharT, Traits>& rhs) noexcept {
00400 if(lhs.size() != rhs.size()) return false;
00401 return !std::strcmp(lhs.data(), rhs.data());
00402 }
00403
00404 template <typename CharT, typename Traits>
00405 std::ostream& operator<<(std::ostream& stream, const basic_string<CharT, Traits>& string) {
00406 return stream << string.data();
00407 }
00408
00409 template <typename CharT, typename Traits>
00410 bool operator < (const basic_string<CharT, Traits>& lhs,
00411 const basic_string<CharT, Traits>& rhs) noexcept {
00412 return std::strcmp(lhs.data(), rhs.data()) < 0;
00413 }
00414
00415
00416 }
00417
00418 #endif