📄 rope
字号:
// _M_ref_count, and member functions _M_incr and _M_decr, which perform
// atomic preincrement/predecrement. The constructor initializes
// _M_ref_count.
struct _Refcount_Base
{
// The type _RC_t
typedef size_t _RC_t;
// The data member _M_ref_count
volatile _RC_t _M_ref_count;
// Constructor
__gthread_mutex_t _M_ref_count_lock;
_Refcount_Base(_RC_t __n) : _M_ref_count(__n), _M_ref_count_lock()
{
#ifdef __GTHREAD_MUTEX_INIT
__gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
_M_ref_count_lock = __tmp;
#elif defined(__GTHREAD_MUTEX_INIT_FUNCTION)
__GTHREAD_MUTEX_INIT_FUNCTION (&_M_ref_count_lock);
#else
#error __GTHREAD_MUTEX_INIT or __GTHREAD_MUTEX_INIT_FUNCTION should be defined by gthr.h abstraction layer, report problem to libstdc++@gcc.gnu.org.
#endif
}
void
_M_incr()
{
__gthread_mutex_lock(&_M_ref_count_lock);
++_M_ref_count;
__gthread_mutex_unlock(&_M_ref_count_lock);
}
_RC_t
_M_decr()
{
__gthread_mutex_lock(&_M_ref_count_lock);
volatile _RC_t __tmp = --_M_ref_count;
__gthread_mutex_unlock(&_M_ref_count_lock);
return __tmp;
}
};
//
// What follows should really be local to rope. Unfortunately,
// that doesn't work, since it makes it impossible to define generic
// equality on rope iterators. According to the draft standard, the
// template parameters for such an equality operator cannot be inferred
// from the occurrence of a member class as a parameter.
// (SGI compilers in fact allow this, but the __result wouldn't be
// portable.)
// Similarly, some of the static member functions are member functions
// only to avoid polluting the global namespace, and to circumvent
// restrictions on type inference for template functions.
//
//
// The internal data structure for representing a rope. This is
// private to the implementation. A rope is really just a pointer
// to one of these.
//
// A few basic functions for manipulating this data structure
// are members of _RopeRep. Most of the more complex algorithms
// are implemented as rope members.
//
// Some of the static member functions of _RopeRep have identically
// named functions in rope that simply invoke the _RopeRep versions.
#define __ROPE_DEFINE_ALLOCS(__a) \
__ROPE_DEFINE_ALLOC(_CharT,_Data) /* character data */ \
typedef _Rope_RopeConcatenation<_CharT,__a> __C; \
__ROPE_DEFINE_ALLOC(__C,_C) \
typedef _Rope_RopeLeaf<_CharT,__a> __L; \
__ROPE_DEFINE_ALLOC(__L,_L) \
typedef _Rope_RopeFunction<_CharT,__a> __F; \
__ROPE_DEFINE_ALLOC(__F,_F) \
typedef _Rope_RopeSubstring<_CharT,__a> __S; \
__ROPE_DEFINE_ALLOC(__S,_S)
// Internal rope nodes potentially store a copy of the allocator
// instance used to allocate them. This is mostly redundant.
// But the alternative would be to pass allocator instances around
// in some form to nearly all internal functions, since any pointer
// assignment may result in a zero reference count and thus require
// deallocation.
#define __STATIC_IF_SGI_ALLOC /* not static */
template <class _CharT, class _Alloc>
struct _Rope_rep_base
: public _Alloc
{
typedef _Alloc allocator_type;
allocator_type
get_allocator() const { return *static_cast<const _Alloc*>(this); }
_Rope_rep_base(size_t __size, const allocator_type&)
: _M_size(__size) {}
size_t _M_size;
# define __ROPE_DEFINE_ALLOC(_Tp, __name) \
typedef typename \
_Alloc::template rebind<_Tp>::other __name##Alloc; \
static _Tp* __name##_allocate(size_t __n) \
{ return __name##Alloc().allocate(__n); } \
static void __name##_deallocate(_Tp *__p, size_t __n) \
{ __name##Alloc().deallocate(__p, __n); }
__ROPE_DEFINE_ALLOCS(_Alloc)
# undef __ROPE_DEFINE_ALLOC
};
namespace _Rope_constants
{
enum { _S_max_rope_depth = 45 };
enum _Tag {_S_leaf, _S_concat, _S_substringfn, _S_function};
}
template<class _CharT, class _Alloc>
struct _Rope_RopeRep : public _Rope_rep_base<_CharT,_Alloc>
# ifndef __GC
, _Refcount_Base
# endif
{
public:
_Rope_constants::_Tag _M_tag:8;
bool _M_is_balanced:8;
unsigned char _M_depth;
__GC_CONST _CharT* _M_c_string;
__gthread_mutex_t _M_c_string_lock;
/* Flattened version of string, if needed. */
/* typically 0. */
/* If it's not 0, then the memory is owned */
/* by this node. */
/* In the case of a leaf, this may point to */
/* the same memory as the data field. */
typedef typename _Rope_rep_base<_CharT,_Alloc>::allocator_type
allocator_type;
using _Rope_rep_base<_CharT,_Alloc>::get_allocator;
_Rope_RopeRep(_Rope_constants::_Tag __t, int __d, bool __b, size_t __size,
allocator_type __a)
: _Rope_rep_base<_CharT,_Alloc>(__size, __a),
# ifndef __GC
_Refcount_Base(1),
# endif
_M_tag(__t), _M_is_balanced(__b), _M_depth(__d), _M_c_string(0)
#ifdef __GTHREAD_MUTEX_INIT
{
// Do not copy a POSIX/gthr mutex once in use. However, bits are bits.
__gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
_M_c_string_lock = __tmp;
}
#else
{ __GTHREAD_MUTEX_INIT_FUNCTION (&_M_c_string_lock); }
#endif
# ifdef __GC
void _M_incr () {}
# endif
static void _S_free_string(__GC_CONST _CharT*, size_t __len,
allocator_type __a);
# define __STL_FREE_STRING(__s, __l, __a) _S_free_string(__s, __l, __a);
// Deallocate data section of a leaf.
// This shouldn't be a member function.
// But its hard to do anything else at the
// moment, because it's templatized w.r.t.
// an allocator.
// Does nothing if __GC is defined.
# ifndef __GC
void _M_free_c_string();
void _M_free_tree();
// Deallocate t. Assumes t is not 0.
void _M_unref_nonnil()
{
if (0 == _M_decr()) _M_free_tree();
}
void _M_ref_nonnil()
{
_M_incr();
}
static void _S_unref(_Rope_RopeRep* __t)
{
if (0 != __t) {
__t->_M_unref_nonnil();
}
}
static void _S_ref(_Rope_RopeRep* __t)
{
if (0 != __t) __t->_M_incr();
}
static void _S_free_if_unref(_Rope_RopeRep* __t)
{
if (0 != __t && 0 == __t->_M_ref_count) __t->_M_free_tree();
}
# else /* __GC */
void _M_unref_nonnil() {}
void _M_ref_nonnil() {}
static void _S_unref(_Rope_RopeRep*) {}
static void _S_ref(_Rope_RopeRep*) {}
static void _S_free_if_unref(_Rope_RopeRep*) {}
# endif
protected:
_Rope_RopeRep&
operator=(const _Rope_RopeRep&);
_Rope_RopeRep(const _Rope_RopeRep&);
};
template<class _CharT, class _Alloc>
struct _Rope_RopeLeaf : public _Rope_RopeRep<_CharT,_Alloc> {
public:
// Apparently needed by VC++
// The data fields of leaves are allocated with some
// extra space, to accommodate future growth and for basic
// character types, to hold a trailing eos character.
enum { _S_alloc_granularity = 8 };
static size_t _S_rounded_up_size(size_t __n) {
size_t __size_with_eos;
if (_S_is_basic_char_type((_CharT*)0)) {
__size_with_eos = __n + 1;
} else {
__size_with_eos = __n;
}
# ifdef __GC
return __size_with_eos;
# else
// Allow slop for in-place expansion.
return (__size_with_eos + _S_alloc_granularity-1)
&~ (_S_alloc_granularity-1);
# endif
}
__GC_CONST _CharT* _M_data; /* Not necessarily 0 terminated. */
/* The allocated size is */
/* _S_rounded_up_size(size), except */
/* in the GC case, in which it */
/* doesn't matter. */
typedef typename _Rope_rep_base<_CharT,_Alloc>::allocator_type
allocator_type;
_Rope_RopeLeaf(__GC_CONST _CharT* __d, size_t __size, allocator_type __a)
: _Rope_RopeRep<_CharT,_Alloc>(_Rope_constants::_S_leaf, 0, true, __size, __a), _M_data(__d)
{
if (_S_is_basic_char_type((_CharT *)0)) {
// already eos terminated.
this->_M_c_string = __d;
}
}
// The constructor assumes that d has been allocated with
// the proper allocator and the properly padded size.
// In contrast, the destructor deallocates the data:
# ifndef __GC
~_Rope_RopeLeaf() throw() {
if (_M_data != this->_M_c_string) {
this->_M_free_c_string();
}
__STL_FREE_STRING(_M_data, this->_M_size, this->get_allocator());
}
# endif
protected:
_Rope_RopeLeaf&
operator=(const _Rope_RopeLeaf&);
_Rope_RopeLeaf(const _Rope_RopeLeaf&);
};
template<class _CharT, class _Alloc>
struct _Rope_RopeConcatenation : public _Rope_RopeRep<_CharT,_Alloc> {
public:
_Rope_RopeRep<_CharT,_Alloc>* _M_left;
_Rope_RopeRep<_CharT,_Alloc>* _M_right;
typedef typename _Rope_rep_base<_CharT,_Alloc>::allocator_type
allocator_type;
_Rope_RopeConcatenation(_Rope_RopeRep<_CharT,_Alloc>* __l,
_Rope_RopeRep<_CharT,_Alloc>* __r,
allocator_type __a)
: _Rope_RopeRep<_CharT,_Alloc>(_Rope_constants::_S_concat,
std::max(__l->_M_depth, __r->_M_depth) + 1,
false,
__l->_M_size + __r->_M_size, __a),
_M_left(__l), _M_right(__r)
{}
# ifndef __GC
~_Rope_RopeConcatenation() throw() {
this->_M_free_c_string();
_M_left->_M_unref_nonnil();
_M_right->_M_unref_nonnil();
}
# endif
protected:
_Rope_RopeConcatenation&
operator=(const _Rope_RopeConcatenation&);
_Rope_RopeConcatenation(const _Rope_RopeConcatenation&);
};
template<class _CharT, class _Alloc>
struct _Rope_RopeFunction : public _Rope_RopeRep<_CharT,_Alloc> {
public:
char_producer<_CharT>* _M_fn;
# ifndef __GC
bool _M_delete_when_done; // Char_producer is owned by the
// rope and should be explicitly
// deleted when the rope becomes
// inaccessible.
# else
// In the GC case, we either register the rope for
// finalization, or not. Thus the field is unnecessary;
// the information is stored in the collector data structures.
// We do need a finalization procedure to be invoked by the
// collector.
static void _S_fn_finalization_proc(void * __tree, void *) {
delete ((_Rope_RopeFunction *)__tree) -> _M_fn;
}
# endif
typedef typename _Rope_rep_base<_CharT,_Alloc>::allocator_type
allocator_type;
_Rope_RopeFunction(char_producer<_CharT>* __f, size_t __size,
bool __d, allocator_type __a)
: _Rope_RopeRep<_CharT,_Alloc>(_Rope_constants::_S_function,
0, true, __size, __a)
, _M_fn(__f)
# ifndef __GC
, _M_delete_when_done(__d)
# endif
{
# ifdef __GC
if (__d) {
GC_REGISTER_FINALIZER(
this, _Rope_RopeFunction::_S_fn_finalization_proc, 0, 0, 0);
}
# endif
}
# ifndef __GC
~_Rope_RopeFunction() throw() {
this->_M_free_c_string();
if (_M_delete_when_done) {
delete _M_fn;
}
}
# endif
protected:
_Rope_RopeFunction&
operator=(const _Rope_RopeFunction&);
_Rope_RopeFunction(const _Rope_RopeFunction&);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -