This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[v3, v7-branch] Bunch of work on string
- From: Paolo Carlini <pcarlini at suse dot de>
- To: "'gcc-patches at gcc dot gnu dot org'" <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 17 Nov 2005 17:20:06 +0100
- Subject: [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