sso_string_base.h

Go to the documentation of this file.
00001 // Short-string-optimized versatile string base -*- C++ -*-
00002 
00003 // Copyright (C) 2005, 2006 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 2, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // You should have received a copy of the GNU General Public License along
00017 // with this library; see the file COPYING.  If not, write to the Free
00018 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00019 // USA.
00020 
00021 // As a special exception, you may use this file as part of a free software
00022 // library without restriction.  Specifically, if other files instantiate
00023 // templates or use macros or inline functions from this file, or you compile
00024 // this file and link it with other files to produce an executable, this
00025 // file does not by itself cause the resulting executable to be covered by
00026 // the GNU General Public License.  This exception does not however
00027 // invalidate any other reasons why the executable file might be covered by
00028 // the GNU General Public License.
00029 
00036 #ifndef _SSO_STRING_BASE_H
00037 #define _SSO_STRING_BASE_H 1
00038 
00039 namespace __gnu_cxx
00040 {
00041   template<typename _CharT, typename _Traits, typename _Alloc>
00042     class __sso_string_base
00043     : protected __vstring_utility<_CharT, _Traits, _Alloc>
00044     {
00045     public:
00046       typedef _Traits                       traits_type;
00047       typedef typename _Traits::char_type           value_type;
00048 
00049       typedef __vstring_utility<_CharT, _Traits, _Alloc>    _Util_Base;
00050       typedef typename _Util_Base::_CharT_alloc_type        _CharT_alloc_type;
00051       typedef typename _CharT_alloc_type::size_type     size_type;
00052       
00053     private:
00054       // The maximum number of individual char_type elements of an
00055       // individual string is determined by _S_max_size. This is the
00056       // value that will be returned by max_size().  (Whereas npos
00057       // is the maximum number of bytes the allocator can allocate.)
00058       // If one was to divvy up the theoretical largest size string,
00059       // with a terminating character and m _CharT elements, it'd
00060       // look like this:
00061       // npos = m * sizeof(_CharT) + sizeof(_CharT)
00062       // Solving for m:
00063       // m = npos / sizeof(_CharT) - 1
00064       // In addition, this implementation halfs this amount.
00065       enum { _S_max_size = (((static_cast<size_type>(-1)
00066                   / sizeof(_CharT)) - 1) / 2) };
00067 
00068       // Data Members (private):
00069       typename _Util_Base::template _Alloc_hider<_CharT_alloc_type>
00070                                                             _M_dataplus;
00071       size_type                                             _M_string_length;
00072 
00073       enum { _S_local_capacity = 15 };
00074       
00075       union
00076       {
00077     _CharT           _M_local_data[_S_local_capacity + 1];
00078     size_type        _M_allocated_capacity;
00079       };
00080 
00081       void
00082       _M_data(_CharT* __p)
00083       { _M_dataplus._M_p = __p; }
00084 
00085       void
00086       _M_length(size_type __length)
00087       { _M_string_length = __length; }
00088 
00089       void
00090       _M_capacity(size_type __capacity)
00091       { _M_allocated_capacity = __capacity; }
00092 
00093       bool
00094       _M_is_local() const
00095       { return _M_data() == _M_local_data; }
00096 
00097       // Create & Destroy
00098       _CharT*
00099       _M_create(size_type&, size_type);
00100       
00101       void
00102       _M_dispose()
00103       {
00104     if (!_M_is_local())
00105       _M_destroy(_M_allocated_capacity);
00106       }
00107 
00108       void
00109       _M_destroy(size_type) throw();
00110 
00111       // _M_construct_aux is used to implement the 21.3.1 para 15 which
00112       // requires special behaviour if _InIterator is an integral type
00113       template<typename _InIterator>
00114         void
00115         _M_construct_aux(_InIterator __beg, _InIterator __end, __false_type)
00116     {
00117           typedef typename iterator_traits<_InIterator>::iterator_category _Tag;
00118           _M_construct(__beg, __end, _Tag());
00119     }
00120 
00121       template<typename _InIterator>
00122         void
00123         _M_construct_aux(_InIterator __beg, _InIterator __end, __true_type)
00124     { _M_construct(static_cast<size_type>(__beg),
00125                static_cast<value_type>(__end)); }
00126 
00127       template<typename _InIterator>
00128         void
00129         _M_construct(_InIterator __beg, _InIterator __end)
00130     {
00131       typedef typename std::__is_integer<_InIterator>::__type _Integral;
00132       _M_construct_aux(__beg, __end, _Integral());
00133         }
00134 
00135       // For Input Iterators, used in istreambuf_iterators, etc.
00136       template<typename _InIterator>
00137         void
00138         _M_construct(_InIterator __beg, _InIterator __end,
00139              std::input_iterator_tag);
00140       
00141       // For forward_iterators up to random_access_iterators, used for
00142       // string::iterator, _CharT*, etc.
00143       template<typename _FwdIterator>
00144         void
00145         _M_construct(_FwdIterator __beg, _FwdIterator __end,
00146              std::forward_iterator_tag);
00147 
00148       void
00149       _M_construct(size_type __req, _CharT __c);
00150 
00151     public:
00152       size_type
00153       _M_max_size() const
00154       { return size_type(_S_max_size); }
00155 
00156       _CharT*
00157       _M_data() const
00158       { return _M_dataplus._M_p; }
00159 
00160       size_type
00161       _M_length() const
00162       { return _M_string_length; }
00163 
00164       size_type
00165       _M_capacity() const
00166       {
00167     return _M_is_local() ? size_type(_S_local_capacity)
00168                          : _M_allocated_capacity; 
00169       }
00170 
00171       bool
00172       _M_is_shared() const
00173       { return false; }
00174 
00175       void
00176       _M_set_leaked() { }
00177 
00178       void
00179       _M_leak() { }
00180 
00181       void
00182       _M_set_length(size_type __n)
00183       {
00184     _M_length(__n);
00185     traits_type::assign(_M_data()[__n], _CharT());
00186       }
00187 
00188       __sso_string_base()
00189       : _M_dataplus(_Alloc(), _M_local_data)
00190       { _M_set_length(0); }
00191 
00192       __sso_string_base(const _Alloc& __a);
00193 
00194       __sso_string_base(const __sso_string_base& __rcs);
00195 
00196       __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a);
00197 
00198       template<typename _InputIterator>
00199         __sso_string_base(_InputIterator __beg, _InputIterator __end,
00200               const _Alloc& __a);
00201 
00202       ~__sso_string_base()
00203       { _M_dispose(); }
00204 
00205       _CharT_alloc_type&
00206       _M_get_allocator()
00207       { return _M_dataplus; }
00208 
00209       const _CharT_alloc_type&
00210       _M_get_allocator() const
00211       { return _M_dataplus; }
00212 
00213       void
00214       _M_swap(__sso_string_base& __rcs);
00215 
00216       void
00217       _M_assign(const __sso_string_base& __rcs);
00218 
00219       void
00220       _M_reserve(size_type __res);
00221 
00222       void
00223       _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
00224         size_type __len2);
00225 
00226       void
00227       _M_erase(size_type __pos, size_type __n);
00228 
00229       void
00230       _M_clear()
00231       { _M_set_length(0); }
00232 
00233       bool
00234       _M_compare(const __sso_string_base&) const
00235       { return false; }
00236     };
00237 
00238   template<typename _CharT, typename _Traits, typename _Alloc>
00239     void
00240     __sso_string_base<_CharT, _Traits, _Alloc>::
00241     _M_destroy(size_type __size) throw()
00242     { _M_dataplus._CharT_alloc_type::deallocate(_M_data(), __size + 1); }
00243 
00244   template<typename _CharT, typename _Traits, typename _Alloc>
00245     void
00246     __sso_string_base<_CharT, _Traits, _Alloc>::
00247     _M_swap(__sso_string_base& __rcs)
00248     {
00249       // NB: Implement Option 3 of DR 431 (see N1599).
00250       std::__alloc_swap<_CharT_alloc_type>::_S_do_it(_M_get_allocator(),
00251                              __rcs._M_get_allocator());
00252 
00253       if (_M_is_local())
00254     if (__rcs._M_is_local())
00255       {
00256         if (_M_length() && __rcs._M_length())
00257           {
00258         _CharT __tmp_data[_S_local_capacity + 1];
00259         traits_type::copy(__tmp_data, __rcs._M_local_data,
00260                   _S_local_capacity + 1);
00261         traits_type::copy(__rcs._M_local_data, _M_local_data,
00262                   _S_local_capacity + 1);
00263         traits_type::copy(_M_local_data, __tmp_data,
00264                   _S_local_capacity + 1);
00265           }
00266         else if (__rcs._M_length())
00267           {
00268         traits_type::copy(_M_local_data, __rcs._M_local_data,
00269                   _S_local_capacity + 1);
00270         _M_length(__rcs._M_length());
00271         __rcs._M_set_length(0);
00272         return;
00273           }
00274         else if (_M_length())
00275           {
00276         traits_type::copy(__rcs._M_local_data, _M_local_data,
00277                   _S_local_capacity + 1);
00278         __rcs._M_length(_M_length());
00279         _M_set_length(0);
00280         return;
00281           }
00282       }
00283     else
00284       {
00285         const size_type __tmp_capacity = __rcs._M_allocated_capacity;
00286         traits_type::copy(__rcs._M_local_data, _M_local_data,
00287                   _S_local_capacity + 1);
00288         _M_data(__rcs._M_data());
00289         __rcs._M_data(__rcs._M_local_data);
00290         _M_capacity(__tmp_capacity);
00291       }
00292       else
00293     {
00294       const size_type __tmp_capacity = _M_allocated_capacity;
00295       if (__rcs._M_is_local())
00296         {
00297           traits_type::copy(_M_local_data, __rcs._M_local_data,
00298                 _S_local_capacity + 1);
00299           __rcs._M_data(_M_data());
00300           _M_data(_M_local_data);
00301         }
00302       else
00303         {
00304           _CharT* __tmp_ptr = _M_data();
00305           _M_data(__rcs._M_data());
00306           __rcs._M_data(__tmp_ptr);
00307           _M_capacity(__rcs._M_allocated_capacity);
00308         }
00309       __rcs._M_capacity(__tmp_capacity);
00310     }
00311 
00312       const size_type __tmp_length = _M_length();
00313       _M_length(__rcs._M_length());
00314       __rcs._M_length(__tmp_length);
00315     }
00316 
00317   template<typename _CharT, typename _Traits, typename _Alloc>
00318     _CharT*
00319     __sso_string_base<_CharT, _Traits, _Alloc>::
00320     _M_create(size_type& __capacity, size_type __old_capacity)
00321     {
00322       // _GLIBCXX_RESOLVE_LIB_DEFECTS
00323       // 83.  String::npos vs. string::max_size()
00324       if (__capacity > size_type(_S_max_size))
00325     std::__throw_length_error(__N("__sso_string_base::_M_create"));
00326 
00327       // The below implements an exponential growth policy, necessary to
00328       // meet amortized linear time requirements of the library: see
00329       // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html.
00330       if (__capacity > __old_capacity && __capacity < 2 * __old_capacity)
00331     {
00332       __capacity = 2 * __old_capacity;
00333       // Never allocate a string bigger than _S_max_size.
00334       if (__capacity > size_type(_S_max_size))
00335         __capacity = size_type(_S_max_size);
00336     }
00337 
00338       // NB: Need an array of char_type[__capacity], plus a terminating
00339       // null char_type() element.
00340       return _M_dataplus._CharT_alloc_type::allocate(__capacity + 1);
00341     }
00342 
00343   template<typename _CharT, typename _Traits, typename _Alloc>
00344     __sso_string_base<_CharT, _Traits, _Alloc>::
00345     __sso_string_base(const _Alloc& __a)
00346     : _M_dataplus(__a, _M_local_data)
00347     { _M_set_length(0); }
00348 
00349   template<typename _CharT, typename _Traits, typename _Alloc>
00350     __sso_string_base<_CharT, _Traits, _Alloc>::
00351     __sso_string_base(const __sso_string_base& __rcs)
00352     : _M_dataplus(__rcs._M_get_allocator(), _M_local_data)
00353     { _M_construct(__rcs._M_data(), __rcs._M_data() + __rcs._M_length()); }
00354 
00355   template<typename _CharT, typename _Traits, typename _Alloc>
00356     __sso_string_base<_CharT, _Traits, _Alloc>::
00357     __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a)
00358     : _M_dataplus(__a, _M_local_data)
00359     { _M_construct(__n, __c); }
00360 
00361   template<typename _CharT, typename _Traits, typename _Alloc>
00362     template<typename _InputIterator>
00363     __sso_string_base<_CharT, _Traits, _Alloc>::
00364     __sso_string_base(_InputIterator __beg, _InputIterator __end,
00365               const _Alloc& __a)
00366     : _M_dataplus(__a, _M_local_data)
00367     { _M_construct(__beg, __end); }
00368 
00369   // NB: This is the special case for Input Iterators, used in
00370   // istreambuf_iterators, etc.
00371   // Input Iterators have a cost structure very different from
00372   // pointers, calling for a different coding style.
00373   template<typename _CharT, typename _Traits, typename _Alloc>
00374     template<typename _InIterator>
00375       void
00376       __sso_string_base<_CharT, _Traits, _Alloc>::
00377       _M_construct(_InIterator __beg, _InIterator __end,
00378            std::input_iterator_tag)
00379       {
00380     size_type __len = 0;
00381     size_type __capacity = size_type(_S_local_capacity);
00382 
00383     while (__beg != __end && __len < __capacity)
00384       {
00385         _M_data()[__len++] = *__beg;
00386         ++__beg;
00387       }
00388     
00389     try
00390       {
00391         while (__beg != __end)
00392           {
00393         if (__len == __capacity)
00394           {
00395             // Allocate more space.
00396             __capacity = __len + 1;
00397             _CharT* __another = _M_create(__capacity, __len);
00398             _S_copy(__another, _M_data(), __len);
00399             _M_dispose();
00400             _M_data(__another);
00401             _M_capacity(__capacity);
00402           }
00403         _M_data()[__len++] = *__beg;
00404         ++__beg;
00405           }
00406       }
00407     catch(...)
00408       {
00409         _M_dispose();
00410         __throw_exception_again;
00411       }
00412 
00413     _M_set_length(__len);
00414       }
00415 
00416   template<typename _CharT, typename _Traits, typename _Alloc>
00417     template<typename _InIterator>
00418       void
00419       __sso_string_base<_CharT, _Traits, _Alloc>::
00420       _M_construct(_InIterator __beg, _InIterator __end,
00421            std::forward_iterator_tag)
00422       {
00423     // NB: Not required, but considered best practice.
00424     if (__builtin_expect(_S_is_null_pointer(__beg) && __beg != __end, 0))
00425       std::__throw_logic_error(__N("__sso_string_base::"
00426                        "_M_construct NULL not valid"));
00427 
00428     size_type __dnew = static_cast<size_type>(std::distance(__beg, __end));
00429 
00430     if (__dnew > size_type(_S_local_capacity))
00431       {
00432         _M_data(_M_create(__dnew, size_type(0)));
00433         _M_capacity(__dnew);
00434       }
00435 
00436     // Check for out_of_range and length_error exceptions.
00437     try
00438       { _S_copy_chars(_M_data(), __beg, __end); }
00439     catch(...)
00440       {
00441         _M_dispose();
00442         __throw_exception_again;
00443       }
00444 
00445     _M_set_length(__dnew);
00446       }
00447 
00448   template<typename _CharT, typename _Traits, typename _Alloc>
00449     void
00450     __sso_string_base<_CharT, _Traits, _Alloc>::
00451     _M_construct(size_type __n, _CharT __c)
00452     {
00453       if (__n > size_type(_S_local_capacity))
00454     {
00455       _M_data(_M_create(__n, size_type(0)));
00456       _M_capacity(__n);
00457     }
00458 
00459       if (__n)
00460     _S_assign(_M_data(), __n, __c);
00461 
00462       _M_set_length(__n);
00463     }
00464 
00465   template<typename _CharT, typename _Traits, typename _Alloc>
00466     void
00467     __sso_string_base<_CharT, _Traits, _Alloc>::
00468     _M_assign(const __sso_string_base& __rcs)
00469     {
00470       if (this != &__rcs)
00471     {
00472       const size_type __rsize = __rcs._M_length();
00473       const size_type __capacity = _M_capacity();
00474 
00475       if (__rsize > __capacity)
00476         {
00477           size_type __new_capacity = __rsize;
00478           _CharT* __tmp = _M_create(__new_capacity, __capacity);
00479           _M_dispose();
00480           _M_data(__tmp);
00481           _M_capacity(__new_capacity);
00482         }
00483 
00484       if (__rsize)
00485         _S_copy(_M_data(), __rcs._M_data(), __rsize);
00486 
00487       _M_set_length(__rsize);
00488     }
00489     }
00490 
00491   template<typename _CharT, typename _Traits, typename _Alloc>
00492     void
00493     __sso_string_base<_CharT, _Traits, _Alloc>::
00494     _M_reserve(size_type __res)
00495     {
00496       // Make sure we don't shrink below the current size.
00497       if (__res < _M_length())
00498     __res = _M_length();
00499 
00500       const size_type __capacity = _M_capacity();
00501       if (__res != __capacity)
00502     {
00503       if (__res > __capacity
00504           || __res > size_type(_S_local_capacity))
00505         {
00506           _CharT* __tmp = _M_create(__res, __capacity);
00507           _S_copy(__tmp, _M_data(), _M_length() + 1);
00508           _M_dispose();
00509           _M_data(__tmp);
00510           _M_capacity(__res);
00511         }
00512       else if (!_M_is_local())
00513         {
00514           _S_copy(_M_local_data, _M_data(), _M_length() + 1);
00515           _M_destroy(__capacity);
00516           _M_data(_M_local_data);
00517         }
00518     }
00519     }
00520 
00521   template<typename _CharT, typename _Traits, typename _Alloc>
00522     void
00523     __sso_string_base<_CharT, _Traits, _Alloc>::
00524     _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
00525           const size_type __len2)
00526     {
00527       const size_type __how_much = _M_length() - __pos - __len1;
00528       
00529       size_type __new_capacity = _M_length() + __len2 - __len1;
00530       _CharT* __r = _M_create(__new_capacity, _M_capacity());
00531 
00532       if (__pos)
00533     _S_copy(__r, _M_data(), __pos);
00534       if (__s && __len2)
00535     _S_copy(__r + __pos, __s, __len2);
00536       if (__how_much)
00537     _S_copy(__r + __pos + __len2,
00538         _M_data() + __pos + __len1, __how_much);
00539       
00540       _M_dispose();
00541       _M_data(__r);
00542       _M_capacity(__new_capacity);
00543     }
00544 
00545   template<typename _CharT, typename _Traits, typename _Alloc>
00546     void
00547     __sso_string_base<_CharT, _Traits, _Alloc>::
00548     _M_erase(size_type __pos, size_type __n)
00549     {
00550       const size_type __how_much = _M_length() - __pos - __n;
00551 
00552       if (__how_much && __n)
00553     _S_move(_M_data() + __pos, _M_data() + __pos + __n,
00554         __how_much);
00555 
00556       _M_set_length(_M_length() - __n);
00557     }
00558 
00559   template<>
00560     inline bool
00561     __sso_string_base<char, std::char_traits<char>,
00562               std::allocator<char> >::
00563     _M_compare(const __sso_string_base& __rcs) const
00564     {
00565       if (this == &__rcs)
00566     return true;
00567       return false;
00568     }
00569 
00570   template<>
00571     inline bool
00572     __sso_string_base<wchar_t, std::char_traits<wchar_t>,
00573               std::allocator<wchar_t> >::
00574     _M_compare(const __sso_string_base& __rcs) const
00575     {
00576       if (this == &__rcs)
00577     return true;
00578       return false;
00579     }
00580 } // namespace __gnu_cxx
00581 
00582 #endif /* _SSO_STRING_BASE_H */

Generated on Tue Feb 2 16:56:33 2010 for GNU C++ STL by  doxygen 1.4.7