diff options
Diffstat (limited to 'libstdc++-v3/include/ext/rc_string_base.h')
-rw-r--r-- | libstdc++-v3/include/ext/rc_string_base.h | 181 |
1 files changed, 95 insertions, 86 deletions
diff --git a/libstdc++-v3/include/ext/rc_string_base.h b/libstdc++-v3/include/ext/rc_string_base.h index e462680eddf..58994222eae 100644 --- a/libstdc++-v3/include/ext/rc_string_base.h +++ b/libstdc++-v3/include/ext/rc_string_base.h @@ -92,8 +92,8 @@ namespace __gnu_cxx typedef typename _Traits::char_type value_type; typedef _Alloc allocator_type; - typedef typename __vstring_utility<_CharT, _Traits, _Alloc>:: - _CharT_alloc_type _CharT_alloc_type; + typedef __vstring_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: @@ -107,16 +107,25 @@ namespace __gnu_cxx // -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; + } _M_info; + + // 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() @@ -125,15 +134,15 @@ namespace __gnu_cxx _CharT* _M_refcopy() throw() { - __atomic_add(&_M_refcount, 1); + __atomic_add(&_M_info._M_refcount, 1); return _M_refdata(); } // XXX MT void _M_set_length(size_type __n) { - _M_refcount = 0; // One reference. - _M_length = __n; + _M_info._M_refcount = 0; // One reference. + _M_info._M_length = __n; // grrr. (per 21.3.4) // You cannot leave those LWG people alone for a second. traits_type::assign(_M_refdata()[__n], _CharT()); @@ -150,11 +159,14 @@ namespace __gnu_cxx _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 @@ -169,28 +181,12 @@ namespace __gnu_cxx 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 - struct _Alloc_hider : _Alloc - { - _Alloc_hider(_CharT* __dat, const _Alloc& __a) - : _Alloc(__a), _M_p(__dat) { } - - _CharT* _M_p; // The actual data. - }; - // Data Member (private): - mutable _Alloc_hider _M_dataplus; - - static _Rep_empty& - _S_empty_rep() - { - static _Rep_empty _Empty_rep; - return _Empty_rep; - } + mutable typename _Util_Base::template _Alloc_hider<_Alloc> _M_dataplus; - _CharT* + void _M_data(_CharT* __p) - { return (_M_dataplus._M_p = __p); } + { _M_dataplus._M_p = __p; } _Rep* _M_rep() const @@ -206,15 +202,23 @@ namespace __gnu_cxx void _M_dispose(const _Alloc& __a) { - if (__exchange_and_add(&_M_rep()->_M_refcount, -1) <= 0) + if (__exchange_and_add(&_M_rep()->_M_info._M_refcount, -1) <= 0) _M_rep()->_M_destroy(__a); } // XXX MT + bool + _M_is_leaked() const + { return _M_rep()->_M_info._M_refcount < 0; } + + void + _M_set_sharable() + { _M_rep()->_M_info._M_refcount = 0; } + void _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, @@ -266,31 +270,19 @@ namespace __gnu_cxx size_type _M_length() const - { return _M_rep()->_M_length; } + { return _M_rep()->_M_info._M_length; } size_type _M_capacity() const - { return _M_rep()->_M_capacity; } + { return _M_rep()->_M_info._M_capacity; } bool _M_is_shared() const - { return _M_rep()->_M_refcount > 0; } - - bool - _M_is_leaked() const - { return _M_rep()->_M_refcount < 0; } - - void - _M_set_sharable() - { _M_rep()->_M_refcount = 0; } + { return _M_rep()->_M_info._M_refcount > 0; } void _M_set_leaked() - { _M_rep()->_M_refcount = -1; } - - void - _M_set_length(size_type __n) - { _M_rep()->_M_set_length(__n); } + { _M_rep()->_M_info._M_refcount = -1; } void _M_leak() // for use in begin() & non-const op[] @@ -299,8 +291,12 @@ namespace __gnu_cxx _M_leak_hard(); } + void + _M_set_length(size_type __n) + { _M_rep()->_M_set_length(__n); } + __rc_string_base() - : _M_dataplus(_S_empty_rep()._M_refcopy(), _Alloc()) { } + : _M_dataplus(_Alloc(), _S_empty_rep._M_refcopy()) { } __rc_string_base(const _Alloc& __a); @@ -310,7 +306,7 @@ namespace __gnu_cxx template<typename _InputIterator> __rc_string_base(_InputIterator __beg, _InputIterator __end, - const _Alloc& __a); + const _Alloc& __a); ~__rc_string_base() { _M_dispose(_M_get_allocator()); } @@ -320,12 +316,7 @@ namespace __gnu_cxx { return _M_dataplus; } void - _M_swap(__rc_string_base& __rcs) - { - _CharT* __tmp = _M_data(); - _M_data(__rcs._M_data()); - __rcs._M_data(__tmp); - } + _M_swap(__rc_string_base& __rcs); void _M_assign(const __rc_string_base& __rcs); @@ -338,6 +329,10 @@ namespace __gnu_cxx }; template<typename _CharT, typename _Traits, typename _Alloc> + typename __rc_string_base<_CharT, _Traits, _Alloc>::_Rep_empty + __rc_string_base<_CharT, _Traits, _Alloc>::_S_empty_rep; + + template<typename _CharT, typename _Traits, typename _Alloc> typename __rc_string_base<_CharT, _Traits, _Alloc>::_Rep* __rc_string_base<_CharT, _Traits, _Alloc>::_Rep:: _S_create(size_type __capacity, size_type __old_capacity, @@ -388,8 +383,8 @@ namespace __gnu_cxx // plus sizeof(size_type) - 1 to upper round to a size multiple // of sizeof(size_type). // 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) @@ -399,16 +394,14 @@ namespace __gnu_cxx // 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; - __p->_M_capacity = __capacity; + _Rep* __place = _Rep_alloc_type(__alloc).allocate(__size / sizeof(_Rep)); + _Rep* __p = new (__place) _Rep; + __p->_M_info._M_capacity = __capacity; return __p; } @@ -417,10 +410,9 @@ namespace __gnu_cxx __rc_string_base<_CharT, _Traits, _Alloc>::_Rep:: _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)); + const size_type __size = ((_M_info._M_capacity + 1) * sizeof(_CharT) + + 2 * sizeof(_Rep) - 1); + _Rep_alloc_type(__a).deallocate(this, __size / sizeof(_Rep)); } template<typename _CharT, typename _Traits, typename _Alloc> @@ -429,41 +421,40 @@ namespace __gnu_cxx _M_clone(const _Alloc& __alloc, size_type __res) { // Requested capacity of the clone. - const size_type __requested_cap = _M_length + __res; - _Rep* __r = _Rep::_S_create(__requested_cap, _M_capacity, __alloc); + const size_type __requested_cap = _M_info._M_length + __res; + _Rep* __r = _Rep::_S_create(__requested_cap, _M_info._M_capacity, + __alloc); - if (_M_length) - _S_copy(__r->_M_refdata(), _M_refdata(), _M_length); + if (_M_info._M_length) + _S_copy(__r->_M_refdata(), _M_refdata(), _M_info._M_length); - __r->_M_set_length(_M_length); + __r->_M_set_length(_M_info._M_length); return __r->_M_refdata(); } template<typename _CharT, typename _Traits, typename _Alloc> __rc_string_base<_CharT, _Traits, _Alloc>:: __rc_string_base(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_base<_CharT, _Traits, _Alloc>:: __rc_string_base(const __rc_string_base& __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_base<_CharT, _Traits, _Alloc>:: __rc_string_base(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_base<_CharT, _Traits, _Alloc>:: __rc_string_base(_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 @@ -487,7 +478,7 @@ namespace __gnu_cxx 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]; @@ -532,10 +523,10 @@ namespace __gnu_cxx 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_p(__beg) && __beg != __end, 0)) + if (__builtin_expect(_S_is_null_pointer(__beg) && __beg != __end, 0)) std::__throw_logic_error(__N("__rc_string_base::" "_S_construct NULL not valid")); @@ -560,7 +551,7 @@ namespace __gnu_cxx _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); @@ -574,6 +565,24 @@ namespace __gnu_cxx template<typename _CharT, typename _Traits, typename _Alloc> void __rc_string_base<_CharT, _Traits, _Alloc>:: + _M_swap(__rc_string_base& __rcs) + { + if (_M_is_leaked()) + _M_set_sharable(); + if (__rcs._M_is_leaked()) + __rcs._M_set_sharable(); + + _CharT* __tmp = _M_data(); + _M_data(__rcs._M_data()); + __rcs._M_data(__tmp); + + // NB: Implement Option 3 of DR 431 (see N1599). + _M_dataplus._M_alloc_swap(__rcs._M_dataplus); + } + + template<typename _CharT, typename _Traits, typename _Alloc> + void + __rc_string_base<_CharT, _Traits, _Alloc>:: _M_assign(const __rc_string_base& __rcs) { if (_M_rep() != __rcs._M_rep()) |