📄 rc_string_base.h
字号:
// Reference-counted versatile string base -*- C++ -*-// Copyright (C) 2005, 2006 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// terms of the GNU General Public License as published by the// Free Software Foundation; either version 2, or (at your option)// any later version.// This library is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// You should have received a copy of the GNU General Public License along// with this library; see the file COPYING. If not, write to the Free// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,// USA.// As a special exception, you may use this file as part of a free software// library without restriction. Specifically, if other files instantiate// templates or use macros or inline functions from this file, or you compile// this file and link it with other files to produce an executable, this// file does not by itself cause the resulting executable to be covered by// the GNU General Public License. This exception does not however// invalidate any other reasons why the executable file might be covered by// the GNU General Public License./** @file ext/rc_string_base.h * This file is a GNU extension to the Standard C++ Library. * This is an internal header file, included by other library headers. * You should not attempt to use it directly. */#ifndef _RC_STRING_BASE_H#define _RC_STRING_BASE_H 1#include <bits/atomicity.h>namespace __gnu_cxx{ /** * @if maint * Documentation? What's that? * Nathan Myers <ncm@cantrip.org>. * * A string looks like this: * * @code * [_Rep] * _M_length * [__rc_string_base<char_type>] _M_capacity * _M_dataplus _M_refcount * _M_p ----------------> unnamed array of char_type * @endcode * * Where the _M_p points to the first character in the string, and * you cast it to a pointer-to-_Rep and subtract 1 to get a * pointer to the header. * * This approach has the enormous advantage that a string object * requires only one allocation. All the ugliness is confined * within a single pair of inline functions, which each compile to * a single "add" instruction: _Rep::_M_refdata(), and * __rc_string_base::_M_rep(); and the allocation function which gets a * block of raw bytes and with room enough and constructs a _Rep * object at the front. * * The reason you want _M_data pointing to the character array and * not the _Rep is so that the debugger can see the string * contents. (Probably we should add a non-inline member to get * the _Rep for the debugger to use, so users can check the actual * string length.) * * Note that the _Rep object is a POD so that you can have a * static "empty string" _Rep object already "constructed" before * static constructors have run. The reference-count encoding is * chosen so that a 0 indicates one reference, so you never try to * destroy the empty-string _Rep object. * * All but the last paragraph is considered pretty conventional * for a C++ string implementation. * @endif */ template<typename _CharT, typename _Traits, typename _Alloc> class __rc_string_base : protected __vstring_utility<_CharT, _Traits, _Alloc> { public: typedef _Traits traits_type; typedef typename _Traits::char_type value_type; typedef _Alloc allocator_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: // _Rep: string representation // Invariants: // 1. String really contains _M_length + 1 characters: due to 21.3.4 // must be kept null-terminated. // 2. _M_capacity >= _M_length // Allocated memory is always (_M_capacity + 1) * sizeof(_CharT). // 3. _M_refcount has three states: // -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 // beyond-the-end for a null terminator; thus, the shared // empty string representation needs no constructor. struct _Rep { 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<_Rep>::other _Rep_alloc_type; _CharT* _M_refdata() throw() { return reinterpret_cast<_CharT*>(this + 1); } _CharT* _M_refcopy() throw() { __atomic_add(&_M_info._M_refcount, 1); return _M_refdata(); } // XXX MT void _M_set_length(size_type __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()); } // Create & Destroy static _Rep* _S_create(size_type, size_type, const _Alloc&); void _M_destroy(const _Alloc&) throw(); _CharT* _M_clone(const _Alloc&, size_type __res = 0); }; struct _Rep_empty : public _Rep { _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 // is the maximum number of bytes the allocator can allocate.) // If one was to divvy up the theoretical largest size string, // with a terminating character and m _CharT elements, it'd // look like this: // npos = sizeof(_Rep) + (m * sizeof(_CharT)) + sizeof(_CharT) // Solving for m: // m = ((npos - sizeof(_Rep)) / sizeof(_CharT)) - 1 // In addition, this implementation quarters this amount. enum { _S_max_size = (((static_cast<size_type>(-1) - sizeof(_Rep)) / sizeof(_CharT)) - 1) / 4 }; // Data Member (private): mutable typename _Util_Base::template _Alloc_hider<_Alloc> _M_dataplus; void _M_data(_CharT* __p) { _M_dataplus._M_p = __p; } _Rep* _M_rep() const { return &((reinterpret_cast<_Rep*>(_M_data()))[-1]); } _CharT* _M_grab(const _Alloc& __alloc) const { return (!_M_is_leaked() && _M_get_allocator() == __alloc) ? _M_rep()->_M_refcopy() : _M_rep()->_M_clone(__alloc); } void _M_dispose() { if (__exchange_and_add(&_M_rep()->_M_info._M_refcount, -1) <= 0) _M_rep()->_M_destroy(_M_get_allocator()); } // 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 _InIterator is an integral type template<typename _InIterator> static _CharT* _S_construct_aux(_InIterator __beg, _InIterator __end, const _Alloc& __a, __false_type) { typedef typename iterator_traits<_InIterator>::iterator_category _Tag; return _S_construct(__beg, __end, __a, _Tag()); } template<typename _InIterator> static _CharT* _S_construct_aux(_InIterator __beg, _InIterator __end, const _Alloc& __a, __true_type) { return _S_construct(static_cast<size_type>(__beg), static_cast<value_type>(__end), __a); } template<typename _InIterator> static _CharT* _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a) { typedef typename std::__is_integer<_InIterator>::__type _Integral; return _S_construct_aux(__beg, __end, __a, _Integral()); } // For Input Iterators, used in istreambuf_iterators, etc. template<typename _InIterator> static _CharT* _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a, std::input_iterator_tag); // For forward_iterators up to random_access_iterators, used for // string::iterator, _CharT*, etc. template<typename _FwdIterator> static _CharT* _S_construct(_FwdIterator __beg, _FwdIterator __end, const _Alloc& __a, std::forward_iterator_tag); static _CharT* _S_construct(size_type __req, _CharT __c, const _Alloc& __a); public: size_type _M_max_size() const { return size_type(_S_max_size); } _CharT* _M_data() const { return _M_dataplus._M_p; } size_type _M_length() const { return _M_rep()->_M_info._M_length; } size_type _M_capacity() const { return _M_rep()->_M_info._M_capacity; } bool _M_is_shared() const { return _M_rep()->_M_info._M_refcount > 0; } void _M_set_leaked() { _M_rep()->_M_info._M_refcount = -1; } void _M_leak() // for use in begin() & non-const op[] { if (!_M_is_leaked()) _M_leak_hard(); } void _M_set_length(size_type __n) { _M_rep()->_M_set_length(__n); } __rc_string_base() : _M_dataplus(_Alloc(), _S_empty_rep._M_refcopy()) { } __rc_string_base(const _Alloc& __a); __rc_string_base(const __rc_string_base& __rcs); __rc_string_base(size_type __n, _CharT __c, const _Alloc& __a); template<typename _InputIterator> __rc_string_base(_InputIterator __beg, _InputIterator __end, const _Alloc& __a); ~__rc_string_base() { _M_dispose(); } allocator_type& _M_get_allocator() { return _M_dataplus; } const allocator_type& _M_get_allocator() const { return _M_dataplus; } void _M_swap(__rc_string_base& __rcs); void _M_assign(const __rc_string_base& __rcs); void _M_reserve(size_type __res); void _M_mutate(size_type __pos, size_type __len1, const _CharT* __s, size_type __len2); void _M_erase(size_type __pos, size_type __n); bool _M_compare(const __rc_string_base&) const { return false; } }; 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, const _Alloc& __alloc) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -