This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[v3, v7-branch] Bunch of work on string


Hi,

various things: commonize the _Alloc_hider class between the two
available bases, fix *once and for all* the existing alignment issues of
the rc base, various clean ups. Tested x86-linux and ia64-linux.

Paolo.

P.S. After a bit of additional testing, an appropriate version will go
in mainline too, for ext/vstring. The plan, in general, is keeping
v7/string and ext/vstring as much in sync as possible.

//////////////
2005-11-17  Paolo Carlini  <pcarlini@suse.de>

	* include/ext/sso_string.h (_Alloc_hider): Move ...
	* include/ext/string_util.h (__string_utility::_Alloc_hider): ... here.
	* include/ext/rc_string.h (_Alloc_hider): Likewise, adjust users.

	* include/ext/string_util.h (__is_null_pointer): Move inside
	struct __string_utility as static _S_is_null_pointer.
	* include/ext/sso_string.h
	(__sso_string<>::_M_construct(std::forward_iterator_tag): Adjust.
	* include/ext/rc_string.h
	(__rc_string<>::_S_construct(std::forward_iterator_tag): Likewise.

	* include/ext/rc_string.h (__rc_string<>::_Rep): Use anonymous union
	together with _CharT to fix alignment issues, rebind to _Rep and
	rename _Raw_alloc to _Rep_alloc_type.
	(__rc_string<>::_Rep::_S_create, _M_destroy): Adjust consistently.

	* include/ext/rc_string.h (__rc_string<>::_S_empty_rep()): Just use
	a static member.
	(__rc_string<>::__rc_string(), _S_construct): Adjust.
Index: include/ext/rc_string.h
===================================================================
--- include/ext/rc_string.h	(revision 106945)
+++ include/ext/rc_string.h	(working copy)
@@ -91,8 +91,8 @@
       typedef typename _Traits::char_type		    value_type;
       typedef _Alloc					    allocator_type;
 
-      typedef typename __string_utility<_CharT, _Traits, _Alloc>::
-        _CharT_alloc_type                                   _CharT_alloc_type;
+      typedef __string_utility<_CharT, _Traits, _Alloc>     _Util_Base;
+      typedef typename _Util_Base::_CharT_alloc_type        _CharT_alloc_type;
       typedef typename _CharT_alloc_type::size_type	    size_type;
 
     private:
@@ -106,16 +106,25 @@
       //      -1: leaked, one reference, no ref-copies allowed, non-const.
       //       0: one reference, non-const.
       //     n>0: n + 1 references, operations require a lock, const.
-      //   4. All fields==0 is an empty string, given the extra storage
+      //   4. All fields == 0 is an empty string, given the extra storage
       //      beyond-the-end for a null terminator; thus, the shared
       //      empty string representation needs no constructor.
       struct _Rep
       {
-	size_type		_M_length;
-	size_type		_M_capacity;
-	_Atomic_word		_M_refcount;
+	union
+	{
+	  struct
+	  {
+	    size_type	    _M_length;
+	    size_type	    _M_capacity;
+	    _Atomic_word    _M_refcount;
+	  };
+	  
+	  // Only for alignment purposes.
+	  _CharT            _M_align;
+	};
 
-	typedef typename _Alloc::template rebind<size_type>::other _Raw_alloc;
+	typedef typename _Alloc::template rebind<_Rep>::other _Rep_alloc_type;
 
  	_CharT*
 	_M_refdata() throw()
@@ -149,11 +158,14 @@
 	_M_clone(const _Alloc&, size_type __res = 0);
       };
 
-      struct _Rep_empty : _Rep
+      struct _Rep_empty
+      : public _Rep
       {
-	_CharT                  _M_terminal;
+	_CharT              _M_terminal;
       };
 
+      static _Rep_empty     _S_empty_rep;
+
       // The maximum number of individual char_type elements of an
       // individual string is determined by _S_max_size. This is the
       // value that will be returned by max_size().  (Whereas npos
@@ -168,49 +180,9 @@
       enum { _S_max_size = (((static_cast<size_type>(-1) - sizeof(_Rep))
 			     / sizeof(_CharT)) - 1) / 4 };
 
-      // Use empty-base optimization: http://www.cantrip.org/emptyopt.html
-      template<typename _Alloc1, bool = std::__is_empty<_Alloc1>::__value>
-        struct _Alloc_hider
-	: public _Alloc1
-	{
-	  _Alloc_hider(_CharT* __ptr, const _Alloc1& __a)
-	  : _Alloc1(__a), _M_p(__ptr) { }
-	  
-	  void _M_alloc_swap(_Alloc_hider&) { }
-
-	  _CharT* _M_p; // The actual data.
-	};
-
-      template<typename _Alloc1>
-        struct _Alloc_hider<_Alloc1, false>
-	: public _Alloc1
-	{
-	  _Alloc_hider(_CharT* __ptr, const _Alloc1& __a)
-	  : _Alloc1(__a), _M_p(__ptr) { }
-
-	  void
-	  _M_alloc_swap(_Alloc_hider& __ah)
-	  {
-	    // Precondition: swappable allocators.
-	    _Alloc1& __this = static_cast<_Alloc1&>(*this);
-	    _Alloc1& __that = static_cast<_Alloc1&>(__ah);
-	    if (__this != __that)
-	      swap(__this, __that);
-	  }
-
-	  _CharT*  _M_p; // The actual data.
-	};
-
       // Data Member (private):
-      mutable _Alloc_hider<_Alloc>	_M_dataplus;
+      mutable typename _Util_Base::template _Alloc_hider<_Alloc>  _M_dataplus;
 
-      static _Rep_empty&
-      _S_empty_rep()
-      {
-	static _Rep_empty _Empty_rep;
-	return _Empty_rep;
-      }
-
       void
       _M_data(_CharT* __p)
       { _M_dataplus._M_p = __p; }
@@ -245,7 +217,7 @@
       _M_leak_hard();
 
       // _S_construct_aux is used to implement the 21.3.1 para 15 which
-      // requires special behaviour if _InIter is an integral type
+      // requires special behaviour if _InIterator is an integral type
       template<class _InIterator>
         static _CharT*
         _S_construct_aux(_InIterator __beg, _InIterator __end,
@@ -323,7 +295,7 @@
       { _M_rep()->_M_set_length(__n); }
 
       __rc_string()
-      : _M_dataplus(_S_empty_rep()._M_refcopy(), _Alloc()) { }
+      : _M_dataplus(_Alloc(), _S_empty_rep._M_refcopy()) { }
 
       __rc_string(const _Alloc& __a);
 
@@ -356,6 +328,10 @@
     };
 
   template<typename _CharT, typename _Traits, typename _Alloc>
+    typename __rc_string<_CharT, _Traits, _Alloc>::_Rep_empty
+    __rc_string<_CharT, _Traits, _Alloc>::_S_empty_rep;
+
+  template<typename _CharT, typename _Traits, typename _Alloc>
     typename __rc_string<_CharT, _Traits, _Alloc>::_Rep*
     __rc_string<_CharT, _Traits, _Alloc>::_Rep::
     _S_create(size_type __capacity, size_type __old_capacity,
@@ -403,11 +379,11 @@
 
       // NB: Need an array of char_type[__capacity], plus a terminating
       // null char_type() element, plus enough for the _Rep data structure,
-      // plus sizeof(size_type) - 1 to upper round to a size multiple
-      // of sizeof(size_type).
+      // plus sizeof(_Rep) - 1 to upper round to a size multiple of
+      // sizeof(_Rep).
       // Whew. Seemingly so needy, yet so elemental.
-      size_type __size = ((__capacity + 1) * sizeof(_CharT) + sizeof(_Rep)
-			  + sizeof(size_type) - 1);
+      size_type __size = ((__capacity + 1) * sizeof(_CharT) 
+			  + 2 * sizeof(_Rep) - 1);
 
       const size_type __adj_size = __size + __malloc_header_size;
       if (__adj_size > __pagesize && __capacity > __old_capacity)
@@ -417,15 +393,13 @@
 	  // Never allocate a string bigger than _S_max_size.
 	  if (__capacity > size_type(_S_max_size))
 	    __capacity = size_type(_S_max_size);
-	  __size = ((__capacity + 1) * sizeof(_CharT) + sizeof(_Rep)
-		    + sizeof(size_type) - 1);
+	  __size = (__capacity + 1) * sizeof(_CharT) + 2 * sizeof(_Rep) - 1;
 	}
 
       // NB: Might throw, but no worries about a leak, mate: _Rep()
       // does not throw.
-      void* __place = _Raw_alloc(__alloc).allocate(__size
-						   / sizeof(size_type));
-      _Rep *__p = new (__place) _Rep;
+      _Rep* __place = _Rep_alloc_type(__alloc).allocate(__size / sizeof(_Rep));
+      _Rep* __p = new (__place) _Rep;
       __p->_M_capacity = __capacity;
       return __p;
     }
@@ -436,9 +410,8 @@
     _M_destroy(const _Alloc& __a) throw ()
     {
       const size_type __size = ((_M_capacity + 1) * sizeof(_CharT)
-				+ sizeof(_Rep) + sizeof(size_type) - 1);
-      _Raw_alloc(__a).deallocate(reinterpret_cast<size_type*>(this),
-				 __size / sizeof(size_type));
+				+ 2 * sizeof(_Rep) - 1);
+      _Rep_alloc_type(__a).deallocate(this, __size / sizeof(_Rep));
     }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
@@ -460,27 +433,25 @@
   template<typename _CharT, typename _Traits, typename _Alloc>
     __rc_string<_CharT, _Traits, _Alloc>::
     __rc_string(const _Alloc& __a)
-    : _M_dataplus(_S_construct(size_type(), _CharT(), __a), __a) { }
+    : _M_dataplus(__a, _S_construct(size_type(), _CharT(), __a)) { }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
     __rc_string<_CharT, _Traits, _Alloc>::
     __rc_string(const __rc_string& __rcs)
-    : _M_dataplus(__rcs._M_grab(_Alloc(__rcs._M_get_allocator()),
-				__rcs._M_get_allocator()),
-		  __rcs._M_get_allocator()) { }
+    : _M_dataplus(__rcs._M_get_allocator(),
+		  __rcs._M_grab(_Alloc(__rcs._M_get_allocator()),
+				__rcs._M_get_allocator())) { }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
     __rc_string<_CharT, _Traits, _Alloc>::
     __rc_string(size_type __n, _CharT __c, const _Alloc& __a)
-    : _M_dataplus(_S_construct(__n, __c, __a), __a)
-    { }
+    : _M_dataplus(__a, _S_construct(__n, __c, __a)) { }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
     template<typename _InputIterator>
     __rc_string<_CharT, _Traits, _Alloc>::
     __rc_string(_InputIterator __beg, _InputIterator __end, const _Alloc& __a)
-    : _M_dataplus(_S_construct(__beg, __end, __a), __a)
-    { }
+    : _M_dataplus(__a, _S_construct(__beg, __end, __a)) { }
 
   template<typename _CharT, typename _Traits, typename _Alloc>
     void
@@ -504,7 +475,7 @@
 		   std::input_iterator_tag)
       {
 	if (__beg == __end && __a == _Alloc())
-	  return _S_empty_rep()._M_refcopy();
+	  return _S_empty_rep._M_refcopy();
 
 	// Avoid reallocation for common case.
 	_CharT __buf[128];
@@ -549,10 +520,10 @@
 		   std::forward_iterator_tag)
       {
 	if (__beg == __end && __a == _Alloc())
-	  return _S_empty_rep()._M_refcopy();
+	  return _S_empty_rep._M_refcopy();
 
 	// NB: Not required, but considered best practice.
-	if (__builtin_expect(__is_null_pointer(__beg) && __beg != __end, 0))
+	if (__builtin_expect(_S_is_null_pointer(__beg) && __beg != __end, 0))
 	  std::__throw_logic_error(__N("__rc_string::"
 				       "_S_construct NULL not valid"));
 
@@ -577,7 +548,7 @@
     _S_construct(size_type __n, _CharT __c, const _Alloc& __a)
     {
       if (__n == 0 && __a == _Alloc())
-	return _S_empty_rep()._M_refcopy();
+	return _S_empty_rep._M_refcopy();
 
       // Check for out_of_range and length_error exceptions.
       _Rep* __r = _Rep::_S_create(__n, size_type(0), __a);
Index: include/ext/sso_string.h
===================================================================
--- include/ext/sso_string.h	(revision 106945)
+++ include/ext/sso_string.h	(working copy)
@@ -47,8 +47,8 @@
       typedef typename _Traits::char_type		    value_type;
       typedef _Alloc					    allocator_type;
 
-      typedef typename __string_utility<_CharT, _Traits, _Alloc>::
-        _CharT_alloc_type                                   _CharT_alloc_type;
+      typedef __string_utility<_CharT, _Traits, _Alloc>     _Util_Base;
+      typedef typename _Util_Base::_CharT_alloc_type        _CharT_alloc_type;
       typedef typename _CharT_alloc_type::size_type	    size_type;
       
     private:
@@ -66,42 +66,9 @@
       enum { _S_max_size = ((static_cast<size_type>(-1)
 			     / sizeof(_CharT)) - 1) / 4 };
 
-      // Use empty-base optimization: http://www.cantrip.org/emptyopt.html
-      template<typename _Alloc1, bool = std::__is_empty<_Alloc1>::__value>
-        struct _Alloc_hider
-	: public _Alloc1
-	{
-	  _Alloc_hider(const _Alloc1& __a, _CharT* __ptr)
-	  : _Alloc1(__a), _M_p(__ptr) { }
-	  
-	  void _M_alloc_swap(_Alloc_hider&) { }
-
-	  _CharT* _M_p; // The actual data.
-	};
-
-      template<typename _Alloc1>
-        struct _Alloc_hider<_Alloc1, false>
-	: public _Alloc1
-	{
-	  _Alloc_hider(const _Alloc1& __a, _CharT* __ptr)
-	  : _Alloc1(__a), _M_p(__ptr) { }
-
-	  void
-	  _M_alloc_swap(_Alloc_hider& __ah)
-	  {
-	    // Precondition: swappable allocators.
-	    _Alloc1& __this = static_cast<_Alloc1&>(*this);
-	    _Alloc1& __that = static_cast<_Alloc1&>(__ah);
-	    if (__this != __that)
-	      swap(__this, __that);
-	  }
-
-	  _CharT*  _M_p; // The actual data.
-	};
-      
       // Data Members (private):
-      _Alloc_hider<_Alloc>      _M_dataplus;
-      size_type                 _M_string_length;
+      typename _Util_Base::template _Alloc_hider<_Alloc>    _M_dataplus;
+      size_type                                             _M_string_length;
 
       enum { _S_local_capacity = 15 };
       
@@ -142,7 +109,7 @@
       _M_destroy(size_type) throw();
 
       // _M_construct_aux is used to implement the 21.3.1 para 15 which
-      // requires special behaviour if _InIter is an integral type
+      // requires special behaviour if _InIterator is an integral type
       template<class _InIterator>
         void
         _M_construct_aux(_InIterator __beg, _InIterator __end, __false_type)
@@ -387,7 +354,6 @@
       _M_construct(_InIterator __beg, _InIterator __end,
 		   std::input_iterator_tag)
       {
-	// Avoid reallocation for common case.
 	size_type __len = 0;
 	size_type __capacity = size_type(_S_local_capacity);
 
@@ -432,7 +398,7 @@
 		   std::forward_iterator_tag)
       {
 	// NB: Not required, but considered best practice.
-	if (__builtin_expect(__is_null_pointer(__beg) && __beg != __end, 0))
+	if (__builtin_expect(_S_is_null_pointer(__beg) && __beg != __end, 0))
 	  std::__throw_logic_error(__N("__sso_string::"
 				       "_M_construct NULL not valid"));
 
Index: include/ext/string_util.h
===================================================================
--- include/ext/string_util.h	(revision 106945)
+++ include/ext/string_util.h	(working copy)
@@ -1,4 +1,4 @@
-// String utilities -*- C++ -*-
+// String utility -*- C++ -*-
 
 // Copyright (C) 2005 Free Software Foundation, Inc.
 //
@@ -44,16 +44,6 @@
 
 namespace __gnu_cxx
 {
-  template<typename _Type>
-    inline bool
-    __is_null_pointer(_Type* __ptr)
-    { return __ptr == 0; }
-
-  template<typename _Type>
-    inline bool
-    __is_null_pointer(_Type)
-    { return false; }
-
   template<typename _CharT, typename _Traits, typename _Alloc>
     struct __string_utility
     {
@@ -73,6 +63,53 @@
 			std::basic_string<_CharT, _Traits, _Alloc> >
         const_iterator;
 
+      // NB:  When the allocator is empty, deriving from it saves space 
+      // (http://www.cantrip.org/emptyopt.html).  We do that anyway for
+      // consistency.
+      template<typename _Alloc1, bool = std::__is_empty<_Alloc1>::__value>
+        struct _Alloc_hider
+	: public _Alloc1
+	{
+	  _Alloc_hider(const _Alloc1& __a, _CharT* __ptr)
+	  : _Alloc1(__a), _M_p(__ptr) { }
+	  
+	  void _M_alloc_swap(_Alloc_hider&) { }
+
+	  _CharT*  _M_p; // The actual data.
+	};
+
+      template<typename _Alloc1>
+        struct _Alloc_hider<_Alloc1, false>
+	: public _Alloc1
+	{
+	  _Alloc_hider(const _Alloc1& __a, _CharT* __ptr)
+	  : _Alloc1(__a), _M_p(__ptr) { }
+
+	  void
+	  _M_alloc_swap(_Alloc_hider& __ah)
+	  {
+	    // Implement Option 3 of DR 431 (see N1599).
+	    // Precondition: swappable allocators.
+	    _Alloc1& __this = static_cast<_Alloc1&>(*this);
+	    _Alloc1& __that = static_cast<_Alloc1&>(__ah);
+	    if (__this != __that)
+	      swap(__this, __that);
+	  }
+
+	  _CharT*  _M_p; // The actual data.
+	};
+
+      // For use in _M_construct (_S_construct) forward_iterator_tag.
+      template<typename _Type>
+        static bool
+        _S_is_null_pointer(_Type* __ptr)
+        { return __ptr == 0; }
+
+      template<typename _Type>
+        static bool
+        _S_is_null_pointer(_Type)
+        { return false; }
+
       // When __n = 1 way faster than the general multichar
       // traits_type::copy/move/assign.
       static void

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]