string.hpp
Go to the documentation of this file.
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 //#include <assert.h>
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           // it will be SSO
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) ); // most probably 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           // it will be non_sso
00199             size_t new_capacity = 0;
00200             CharT* ptr = nullptr;
00201 
00202             if( this->sso() ){
00203                 // from sso to non_sso. Need to allocate new memory
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                 // was non_sso, still non_sso. Capacity is sufficient. Do nothing
00211                 new_capacity = capacity();
00212                 ptr =  m_data.non_sso.ptr;
00213             }
00214             else{
00215                 // was non_sso, still non_sso. But I need to allocate more memory
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     // We are using sso if the last two bits are 0
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     // We are using sso if the last two bits are 0
00316     bool sso() const noexcept {
00317         return !detail::lsb<0>(m_data.sso.size) && !detail::lsb<1>(m_data.sso.size);
00318     }
00319 
00320     // good
00321     void set_sso_size(unsigned char size) noexcept {
00322         m_data.sso.size = static_cast<UCharT>(sso_capacity - size) << 2;
00323     }
00324 
00325     // good
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         // Remember to negate the high bits
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


ros_type_introspection
Author(s): Davide Faconti
autogenerated on Sun Oct 1 2017 02:54:53