OSDN Git Service

2002-04-15 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / include / bits / basic_string.tcc
index 7190e2e..3f4b5fb 100644 (file)
@@ -1,6 +1,7 @@
 // Components for manipulating sequences of characters -*- C++ -*-
 
-// Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+// Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
 #ifndef _CPP_BITS_STRING_TCC
 #define _CPP_BITS_STRING_TCC 1
 
+#pragma GCC system_header
+
 namespace std
 {
   template<typename _CharT, typename _Traits, typename _Alloc>
-    const _CharT 
+    const typename basic_string<_CharT, _Traits, _Alloc>::size_type 
     basic_string<_CharT, _Traits, _Alloc>::
-    _Rep::_S_terminal = _CharT();
+    _Rep::_S_max_size = (((npos - sizeof(_Rep))/sizeof(_CharT)) - 1) / 4;
 
   template<typename _CharT, typename _Traits, typename _Alloc>
-    const typename basic_string<_CharT, _Traits, _Alloc>::size_type 
+    const _CharT 
     basic_string<_CharT, _Traits, _Alloc>::
-    _Rep::_S_max_size = (((npos - sizeof(_Rep))/sizeof(_CharT)) - 1) / 4;
+    _Rep::_S_terminal = _CharT();
 
   template<typename _CharT, typename _Traits, typename _Alloc>
     const typename basic_string<_CharT, _Traits, _Alloc>::size_type
@@ -130,12 +133,16 @@ namespace std
   template<typename _CharT, typename _Traits, typename _Alloc>
     template <class _InIter>
       _CharT*
-      basic_string<_CharT,_Traits,_Alloc>::
+      basic_string<_CharT, _Traits, _Alloc>::
       _S_construct(_InIter __beg, _InIter __end, const _Alloc& __a, 
                   forward_iterator_tag)
       {
        size_type __dnew = static_cast<size_type>(distance(__beg, __end));
 
+       // NB: Not required, but considered best practice.
+       if (__builtin_expect(__beg == _InIter(0), 0))
+         __throw_logic_error("attempt to create string with null pointer");
+       
        if (__beg == __end && __a == _Alloc())
          return _S_empty_rep()._M_refcopy();
 
@@ -156,7 +163,7 @@ namespace std
 
   template<typename _CharT, typename _Traits, typename _Alloc>
     _CharT*
-    basic_string<_CharT,_Traits, _Alloc>::
+    basic_string<_CharT, _Traits, _Alloc>::
     _S_construct(size_type __n, _CharT __c, const _Alloc& __a)
     {
       if (__n == 0 && __a == _Alloc())
@@ -216,7 +223,8 @@ namespace std
   template<typename _CharT, typename _Traits, typename _Alloc>
     basic_string<_CharT, _Traits, _Alloc>::
     basic_string(const _CharT* __s, const _Alloc& __a)
-    : _M_dataplus(_S_construct(__s, __s + traits_type::length(__s), __a), __a)
+    : _M_dataplus(_S_construct(__s, __s ? __s + traits_type::length(__s) : 0, 
+                              __a), __a)
     { }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
@@ -265,6 +273,12 @@ namespace std
       _M_rep()->_M_set_leaked();
     }
 
+  // _M_mutate and, below, _M_clone, include, in the same form, an exponential
+  // growth policy, necessary to meet amortized linear time requirements of
+  // the library: see http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html.
+  // The policy is active for allocations requiring an amount of memory above
+  // system pagesize. This is consistent with the requirements of the standard:
+  // see, f.i., http://gcc.gnu.org/ml/libstdc++/2001-07/msg00130.html
   template<typename _CharT, typename _Traits, typename _Alloc>
     void
     basic_string<_CharT, _Traits, _Alloc>::
@@ -279,7 +293,21 @@ namespace std
        {
          // Must reallocate.
          allocator_type __a = get_allocator();
-         _Rep* __r = _Rep::_S_create(__new_size, __a);
+         // See below (_S_create) for the meaning and value of these
+         // constants.
+         const size_type __pagesize = 4096;
+         const size_type __malloc_header_size = 4 * sizeof (void*);
+         // The biggest string which fits in a memory page
+         const size_type __page_capacity = (__pagesize - __malloc_header_size
+                                            - sizeof(_Rep) - sizeof(_CharT)) 
+                                            / sizeof(_CharT);
+         _Rep* __r;
+         if (__new_size > capacity() && __new_size > __page_capacity)
+           // Growing exponentially.
+           __r = _Rep::_S_create(__new_size > 2*capacity() ?
+                                 __new_size : 2*capacity(), __a);
+         else
+           __r = _Rep::_S_create(__new_size, __a);
          try 
            {
              if (__pos)
@@ -315,6 +343,9 @@ namespace std
         {
          if (__res > this->max_size())
            __throw_length_error("basic_string::reserve");
+         // Make sure we don't shrink below the current size
+         if (__res < this->size())
+           __res = this->size();
          allocator_type __a = get_allocator();
          _CharT* __tmp = _M_rep()->_M_clone(__a, __res - this->size());
          _M_rep()->_M_dispose(__a);
@@ -346,13 +377,6 @@ namespace std
        }
     }
 
-#ifdef _GLIBCPP_ALLOC_CONTROL
-  template<typename _CharT, typename _Traits, typename _Alloc>
-    bool (*basic_string<_CharT, _Traits, _Alloc>::_Rep::_S_excess_slop) 
-    (size_t, size_t) = 
-    basic_string<_CharT, _Traits, _Alloc>::_Rep::_S_default_excess;
-#endif
-
   template<typename _CharT, typename _Traits, typename _Alloc>
     typename basic_string<_CharT, _Traits, _Alloc>::_Rep*
     basic_string<_CharT, _Traits, _Alloc>::_Rep::
@@ -371,12 +395,55 @@ namespace std
       // terminating null char_type() element, plus enough for the
       // _Rep data structure. Whew. Seemingly so needy, yet so elemental.
       size_t __size = (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep);
+
+      // The standard places no restriction on allocating more memory
+      // than is strictly needed within this layer at the moment or as
+      // requested by an explicit application call to reserve().  Many
+      // malloc implementations perform quite poorly when an
+      // application attempts to allocate memory in a stepwise fashion
+      // growing each allocation size by only 1 char.  Additionally,
+      // it makes little sense to allocate less linear memory than the
+      // natural blocking size of the malloc implementation.
+      // Unfortunately, we would need a somewhat low-level calculation
+      // with tuned parameters to get this perfect for any particular
+      // malloc implementation.  Fortunately, generalizations about
+      // common features seen among implementations seems to suffice.
+
+      // __pagesize need not match the actual VM page size for good
+      // results in practice, thus we pick a common value on the low
+      // side.  __malloc_header_size is an estimate of the amount of
+      // overhead per memory allocation (in practice seen N * sizeof
+      // (void*) where N is 0, 2 or 4).  According to folklore,
+      // picking this value on the high side is better than
+      // low-balling it (especially when this algorithm is used with
+      // malloc implementations that allocate memory blocks rounded up
+      // to a size which is a power of 2).
+      const size_t __pagesize = 4096; // must be 2^i * __subpagesize
+      const size_t __subpagesize = 128; // should be >> __malloc_header_size
+      const size_t __malloc_header_size = 4 * sizeof (void*);
+      if ((__size + __malloc_header_size) > __pagesize)
+       {
+         size_t __extra =
+           (__pagesize - ((__size + __malloc_header_size) % __pagesize))
+           % __pagesize;
+         __capacity += __extra / sizeof(_CharT);
+         __size = (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep);
+       }
+      else if (__size > __subpagesize)
+       {
+         size_t __extra =
+           (__subpagesize - ((__size + __malloc_header_size) % __subpagesize))
+           % __subpagesize;
+         __capacity += __extra / sizeof(_CharT);
+         __size = (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep);
+       }
+
       // NB: Might throw, but no worries about a leak, mate: _Rep()
       // does not throw.
       void* __place = _Raw_bytes_alloc(__alloc).allocate(__size);
       _Rep *__p = new (__place) _Rep;
       __p->_M_capacity = __capacity;
-      __p->_M_set_sharable();  // one reference
+      __p->_M_set_sharable();  // One reference.
       __p->_M_length = 0;
       return __p;
     }
@@ -386,7 +453,23 @@ namespace std
     basic_string<_CharT, _Traits, _Alloc>::_Rep::
     _M_clone(const _Alloc& __alloc, size_type __res)
     {
-      _Rep* __r = _Rep::_S_create(_M_length + __res, __alloc);
+      // Requested capacity of the clone.
+      const size_type __requested_cap = _M_length + __res;
+      // See above (_S_create) for the meaning and value of these constants.
+      const size_type __pagesize = 4096;
+      const size_type __malloc_header_size = 4 * sizeof (void*);
+      // The biggest string which fits in a memory page.
+      const size_type __page_capacity =
+        (__pagesize - __malloc_header_size - sizeof(_Rep) - sizeof(_CharT))
+        / sizeof(_CharT);
+      _Rep* __r;
+      if (__requested_cap > _M_capacity && __requested_cap > __page_capacity)
+        // Growing exponentially.
+        __r = _Rep::_S_create(__requested_cap > 2*_M_capacity ?
+                              __requested_cap : 2*_M_capacity, __alloc);
+      else
+        __r = _Rep::_S_create(__requested_cap, __alloc);
+      
       if (_M_length)
        {
          try 
@@ -402,19 +485,6 @@ namespace std
     }
   
   template<typename _CharT, typename _Traits, typename _Alloc>
-  inline bool
-#ifdef _GLIBCPP_ALLOC_CONTROL
-    basic_string<_CharT, _Traits, _Alloc>::_Rep::
-    _S_default_excess(size_t __s, size_t __r)
-#else
-    basic_string<_CharT, _Traits, _Alloc>::_Rep::
-    _S_excess_slop(size_t __s, size_t __r)
-#endif
-    {
-      return 2 * (__s <= 16 ? 16 : __s) < __r;
-    }
-  
-  template<typename _CharT, typename _Traits, typename _Alloc>
     void
     basic_string<_CharT, _Traits, _Alloc>::resize(size_type __n, _CharT __c)
     {
@@ -427,7 +497,10 @@ namespace std
        this->erase(__n);
       // else nothing (in particular, avoid calling _M_mutate() unnecessarily.)
     }
-  
+
+  // This is the general replace helper, which currently gets instantiated both
+  // for input iterators and reverse iterators. It buffers internally and then
+  // calls _M_replace_safe.
   template<typename _CharT, typename _Traits, typename _Alloc>
     template<typename _InputIter>
       basic_string<_CharT, _Traits, _Alloc>&
@@ -435,29 +508,34 @@ namespace std
       _M_replace(iterator __i1, iterator __i2, _InputIter __k1, 
                 _InputIter __k2, input_iterator_tag)
       {
+       // Save concerned source string data in a temporary.
        basic_string __s(__k1, __k2);
-       return this->replace(__i1, __i2, __s._M_ibegin(), __s._M_iend());
+       return _M_replace_safe(__i1, __i2, __s._M_ibegin(), __s._M_iend());
       }
 
+  // This is a special replace helper, which does not buffer internally
+  // and can be used in "safe" situations involving forward iterators,
+  // i.e., when source and destination ranges are known to not overlap.
   template<typename _CharT, typename _Traits, typename _Alloc>
     template<typename _ForwardIter>
       basic_string<_CharT, _Traits, _Alloc>&
       basic_string<_CharT, _Traits, _Alloc>::
-      _M_replace(iterator __i1, iterator __i2, _ForwardIter __k1, 
-                _ForwardIter __k2, forward_iterator_tag)
+      _M_replace_safe(iterator __i1, iterator __i2, _ForwardIter __k1, 
+                     _ForwardIter __k2)
       {
+       size_type __dnew = static_cast<size_type>(distance(__k1, __k2));
        size_type __dold = __i2 - __i1;
        size_type __dmax = this->max_size();
-       size_type __dnew = static_cast<size_type>(distance(__k1, __k2));
 
        if (__dmax <= __dnew)
          __throw_length_error("basic_string::_M_replace");
        size_type __off = __i1 - _M_ibegin();
        _M_mutate(__off, __dold, __dnew);
+
        // Invalidated __i1, __i2
-       if (__dnew)
+        if (__dnew)
          _S_copy_chars(_M_data() + __off, __k1, __k2);
-       
+
        return *this;
       }
 
@@ -467,14 +545,18 @@ namespace std
     replace(size_type __pos1, size_type __n1, const basic_string& __str,
            size_type __pos2, size_type __n2)
     {
-      return this->replace(_M_check(__pos1), _M_fold(__pos1, __n1),
-                          __str._M_check(__pos2), 
-                          __str._M_fold(__pos2, __n2));
+      const size_type __strsize = __str.size();
+      if (__pos2 > __strsize)
+       __throw_out_of_range("basic_string::replace");
+      const bool __testn2 = __n2 < __strsize - __pos2;
+      const size_type __foldn2 = __testn2 ? __n2 : __strsize - __pos2;
+      return this->replace(__pos1, __n1,
+                          __str._M_data() + __pos2, __foldn2);      
     }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
-    basic_string<_CharT,_Traits,_Alloc>&
-    basic_string<_CharT,_Traits,_Alloc>::
+    basic_string<_CharT, _Traits, _Alloc>&
+    basic_string<_CharT, _Traits, _Alloc>::
     append(const basic_string& __str)
     {
       // Iff appending itself, string needs to pre-reserve the
@@ -484,13 +566,13 @@ namespace std
       size_type __len = __size + this->size();
       if (__len > this->capacity())
        this->reserve(__len);
-      return this->replace(_M_iend(), _M_iend(), __str._M_ibegin(),
-                          __str._M_iend());
+      return _M_replace_safe(_M_iend(), _M_iend(), __str._M_ibegin(),
+                            __str._M_iend());
     }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
-    basic_string<_CharT,_Traits,_Alloc>&
-    basic_string<_CharT,_Traits,_Alloc>::
+    basic_string<_CharT, _Traits, _Alloc>&
+    basic_string<_CharT, _Traits, _Alloc>::
     append(const basic_string& __str, size_type __pos, size_type __n)
     {
       // Iff appending itself, string needs to pre-reserve the
@@ -499,24 +581,24 @@ namespace std
       size_type __len = min(__str.size() - __pos, __n) + this->size();
       if (__len > this->capacity())
        this->reserve(__len);
-      return this->replace(_M_iend(), _M_iend(), __str._M_check(__pos),
-                          __str._M_fold(__pos, __n));
+      return _M_replace_safe(_M_iend(), _M_iend(), __str._M_check(__pos),
+                            __str._M_fold(__pos, __n));
     }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
-    basic_string<_CharT,_Traits,_Alloc>&
-    basic_string<_CharT,_Traits,_Alloc>::
+    basic_string<_CharT, _Traits, _Alloc>&
+    basic_string<_CharT, _Traits, _Alloc>::
     append(const _CharT* __s, size_type __n)
     {
       size_type __len = __n + this->size();
       if (__len > this->capacity())
        this->reserve(__len);
-      return this->replace(_M_iend(), _M_iend(), __s, __s + __n);
+      return _M_replace_safe(_M_iend(), _M_iend(), __s, __s + __n);
     }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
-    basic_string<_CharT,_Traits,_Alloc>&
-    basic_string<_CharT,_Traits,_Alloc>::
+    basic_string<_CharT, _Traits, _Alloc>&
+    basic_string<_CharT, _Traits, _Alloc>::
     append(size_type __n, _CharT __c)
     {
       size_type __len = __n + this->size();
@@ -526,11 +608,11 @@ namespace std
     }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
-    basic_string<_CharT,_Traits,_Alloc>
+    basic_string<_CharT, _Traits, _Alloc>
     operator+(const _CharT* __lhs,
-             const basic_string<_CharT,_Traits,_Alloc>& __rhs)
+             const basic_string<_CharT, _Traits, _Alloc>& __rhs)
     {
-      typedef basic_string<_CharT,_Traits,_Alloc> __string_type;
+      typedef basic_string<_CharT, _Traits, _Alloc> __string_type;
       typedef typename __string_type::size_type          __size_type;
       __size_type __len = _Traits::length(__lhs);
       __string_type __str;
@@ -541,10 +623,10 @@ namespace std
     }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
-    basic_string<_CharT,_Traits,_Alloc>
-    operator+(_CharT __lhs, const basic_string<_CharT,_Traits,_Alloc>& __rhs)
+    basic_string<_CharT, _Traits, _Alloc>
+    operator+(_CharT __lhs, const basic_string<_CharT, _Traits, _Alloc>& __rhs)
     {
-      typedef basic_string<_CharT,_Traits,_Alloc> __string_type;
+      typedef basic_string<_CharT, _Traits, _Alloc> __string_type;
       typedef typename __string_type::size_type          __size_type;
       __string_type __str;
       __size_type __len = __rhs.size();
@@ -627,7 +709,7 @@ namespace std
       size_type __size = this->size();
       if (__n <= __size)
        {
-         __pos = std::min(__size - __n ,__pos);
+         __pos = std::min(__size - __n__pos);
          const _CharT* __data = _M_data();
          do 
            {
@@ -811,7 +893,7 @@ namespace std
 
   template<typename _CharT, typename _Traits, typename _Alloc>
     int
-    basic_string <_CharT,_Traits,_Alloc>::
+    basic_string <_CharT, _Traits, _Alloc>::
     compare(size_type __pos, size_type __n1, const _CharT* __s) const
     {
       size_type __size = this->size();
@@ -829,7 +911,7 @@ namespace std
 
   template<typename _CharT, typename _Traits, typename _Alloc>
     int
-    basic_string <_CharT,_Traits,_Alloc>::
+    basic_string <_CharT, _Traits, _Alloc>::
     compare(size_type __pos, size_type __n1, const _CharT* __s, 
            size_type __n2) const
     {
@@ -857,6 +939,37 @@ namespace std
       _Traits::copy(__buf, __str.data(), __bytes);
       __buf[__bytes] = _CharT();
     }
+
+  // Inhibit implicit instantiations for required instantiations,
+  // which are defined via explicit instantiations elsewhere.  
+  // NB: This syntax is a GNU extension.
+  extern template class basic_string<char>;
+  extern template 
+    basic_istream<char>& 
+    operator>>(basic_istream<char>&, string&);
+  extern template 
+    basic_ostream<char>& 
+    operator<<(basic_ostream<char>&, const string&);
+  extern template 
+    basic_istream<char>& 
+    getline(basic_istream<char>&, string&, char);
+  extern template 
+    basic_istream<char>& 
+    getline(basic_istream<char>&, string&);
+
+  extern template class basic_string<wchar_t>;
+  extern template 
+    basic_istream<wchar_t>& 
+    operator>>(basic_istream<wchar_t>&, wstring&);
+  extern template 
+    basic_ostream<wchar_t>& 
+    operator<<(basic_ostream<wchar_t>&, const wstring&);
+  extern template 
+    basic_istream<wchar_t>& 
+    getline(basic_istream<wchar_t>&, wstring&, wchar_t);
+  extern template 
+    basic_istream<wchar_t>& 
+    getline(basic_istream<wchar_t>&, wstring&);
 } // namespace std
 
 #endif