// SGI's rope class -*- C++ -*-// Copyright (C) 2001-2015 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 3, 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.// Under Section 7 of GPL version 3, you are granted additional// permissions described in the GCC Runtime Library Exception, version// 3.1, as published by the Free Software Foundation.// You should have received a copy of the GNU General Public License and// a copy of the GCC Runtime Library Exception along with this program;// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see// <http://www.gnu.org/licenses/>./*
* Copyright (c) 1997
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*//** @file ext/rope
* This file is a GNU extension to the Standard C++ Library (possibly
* containing extensions from the HP/SGI STL subset).
*/#ifndef _ROPE#define _ROPE 1#pragma GCC system_header#include<algorithm>#include<iosfwd>#include<bits/stl_construct.h>#include<bits/stl_uninitialized.h>#include<bits/stl_function.h>#include<bits/stl_numeric.h>#include<bits/allocator.h>#include<bits/gthr.h>#include<tr1/functional># ifdef __GC# define __GC_CONST const# else# define __GC_CONST // constant except for deallocation# endif#include<ext/memory>// For uninitialized_copy_nnamespace __gnu_cxx _GLIBCXX_VISIBILITY(default){
namespace __detail
{
enum{
_S_max_rope_depth =45};enum _Tag {
_S_leaf, _S_concat, _S_substringfn, _S_function};}// namespace __detailusing std::size_t;using std::ptrdiff_t;using std::allocator;using std::_Destroy;
_GLIBCXX_BEGIN_NAMESPACE_VERSION
// See libstdc++/36832.template<typename _ForwardIterator,typename _Allocator>void_Destroy_const(_ForwardIterator __first,
_ForwardIterator __last, _Allocator __alloc){
for(; __first != __last;++__first)
__alloc.destroy(&*__first);}template<typename _ForwardIterator,typename _Tp>inlinevoid_Destroy_const(_ForwardIterator __first,
_ForwardIterator __last, allocator<_Tp>){
_Destroy(__first, __last);}// The _S_eos function is used for those functions that// convert to/from C-like strings to detect the end of the string.// The end-of-C-string character.// This is what the draft standard says it should be.template<class_CharT>inline _CharT
_S_eos(_CharT*){
return_CharT();}// Test for basic character types.// For basic character types leaves having a trailing eos.template<class_CharT>inlinebool_S_is_basic_char_type(_CharT*){
returnfalse;}template<class_CharT>inlinebool_S_is_one_byte_char_type(_CharT*){
returnfalse;}inlinebool_S_is_basic_char_type(char*){
returntrue;}inlinebool_S_is_one_byte_char_type(char*){
returntrue;}inlinebool_S_is_basic_char_type(wchar_t*){
returntrue;}// Store an eos iff _CharT is a basic character type.// Do not reference _S_eos if it isn't.template<class_CharT>inlinevoid_S_cond_store_eos(_CharT&){
}inlinevoid_S_cond_store_eos(char& __c){
__c =0;}inlinevoid_S_cond_store_eos(wchar_t& __c){
__c =0;}// char_producers are logically functions that generate a section of// a string. These can be converted to ropes. The resulting rope// invokes the char_producer on demand. This allows, for example,// files to be viewed as ropes without reading the entire file.template<class_CharT>classchar_producer{
public:virtual~char_producer(){
};virtualvoidoperator()(size_t __start_pos, size_t __len,
_CharT* __buffer)=0;// Buffer should really be an arbitrary output iterator.// That way we could flatten directly into an ostream, etc.// This is thoroughly impossible, since iterator types don't// have runtime descriptions.};// Sequence buffers://// Sequence must provide an append operation that appends an// array to the sequence. Sequence buffers are useful only if// appending an entire array is cheaper than appending element by element.// This is true for many string representations.// This should perhaps inherit from ostream<sequence::value_type>// and be implemented correspondingly, so that they can be used// for formatted. For the sake of portability, we don't do this yet.//// For now, sequence buffers behave as output iterators. But they also// behave a little like basic_ostringstream<sequence::value_type> and a// little like containers.template<class_Sequence, size_t _Buf_sz =100>classsequence_buffer:public std::iterator<std::output_iterator_tag,void,void,void,void>{
public:typedeftypename _Sequence::value_type value_type;protected:
_Sequence* _M_prefix;
value_type _M_buffer[_Buf_sz];
size_t _M_buf_count;public:voidflush(){
_M_prefix->append(_M_buffer, _M_buffer + _M_buf_count);
_M_buf_count =0;}~sequence_buffer(){
flush();}sequence_buffer():_M_prefix(0),_M_buf_count(0){
}sequence_buffer(const sequence_buffer& __x){
_M_prefix = __x._M_prefix;
_M_buf_count = __x._M_buf_count;
std::copy(__x._M_buffer, __x._M_buffer + __x._M_buf_count, _M_buffer);}sequence_buffer(sequence_buffer& __x){
__x.flush();
_M_prefix = __x._M_prefix;
_M_buf_count =0;}sequence_buffer(_Sequence& __s):_M_prefix(&__s),_M_buf_count(0){
}
sequence_buffer&operator=(sequence_buffer& __x){
__x.flush();
_M_prefix = __x._M_prefix;
_M_buf_count =0;return*this;}
sequence_buffer&operator=(const sequence_buffer& __x){
_M_prefix = __x._M_prefix;
_M_buf_count = __x._M_buf_count;
std::copy(__x._M_buffer, __x._M_buffer + __x._M_buf_count, _M_buffer);return*this;}voidpush_back(value_type __x){
if(_M_buf_count < _Buf_sz){
_M_buffer[_M_buf_count]= __x;++_M_buf_count;}else{
flush();
_M_buffer[0]= __x;
_M_buf_count =1;}}voidappend(value_type* __s, size_t __len){
if(__len + _M_buf_count <= _Buf_sz){
size_t __i = _M_buf_count;for(size_t __j =0; __j < __len; __i++, __j++)
_M_buffer[__i]= __s[__j];
_M_buf_count += __len;}elseif(0== _M_buf_count)
_M_prefix->append(__s, __s + __len);else{
flush();append(__s, __len);}}
sequence_buffer&write(value_type* __s, size_t __len){
append(__s, __len);return*this;}
sequence_buffer&put(value_type __x){
push_back(__x);return*this;}
sequence_buffer&operator=(const value_type& __rhs){
push_back(__rhs);return*this;}
sequence_buffer&operator*(){
return*this;}
sequence_buffer&operator++(){
return*this;}
sequence_buffer
operator++(int){
return*this;}};// The following should be treated as private, at least for now.template<class_CharT>class_Rope_char_consumer{
public:// If we had member templates, these should not be virtual.// For now we need to use run-time parametrization where// compile-time would do. Hence this should all be private// for now.// The symmetry with char_producer is accidental and temporary.virtual~_Rope_char_consumer(){
};virtualbooloperator()(const _CharT* __buffer, size_t __len)=0;};// First a lot of forward declarations. The standard seems to require// much stricter "declaration before use" than many of the implementations// that preceded it.template<class_CharT,class_Alloc= allocator<_CharT>>classrope;template<class_CharT,class_Alloc>struct _Rope_RopeConcatenation;template<class_CharT,class_Alloc>struct _Rope_RopeLeaf;template<class_CharT,class_Alloc>struct _Rope_RopeFunction;template<class_CharT,class_Alloc>struct _Rope_RopeSubstring;template<class_CharT,class_Alloc>class_Rope_iterator;template<class_CharT,class_Alloc>class_Rope_const_iterator;template<class_CharT,class_Alloc>class_Rope_char_ref_proxy;template<class_CharT,class_Alloc>class_Rope_char_ptr_proxy;template<class_CharT,class_Alloc>booloperator==(const _Rope_char_ptr_proxy<_CharT, _Alloc>& __x,const _Rope_char_ptr_proxy<_CharT, _Alloc>& __y);template<class_CharT,class_Alloc>
_Rope_const_iterator<_CharT, _Alloc>operator-(const _Rope_const_iterator<_CharT, _Alloc>& __x,
ptrdiff_t __n);template<class_CharT,class_Alloc>
_Rope_const_iterator<_CharT, _Alloc>operator+(const _Rope_const_iterator<_CharT, _Alloc>& __x,
ptrdiff_t __n);template<class_CharT,class_Alloc>
_Rope_const_iterator<_CharT, _Alloc>operator+(ptrdiff_t __n,const _Rope_const_iterator<_CharT, _Alloc>& __x);template<class_CharT,class_Alloc>booloperator==(const _Rope_const_iterator<_CharT, _Alloc>& __x,const _Rope_const_iterator<_CharT, _Alloc>& __y);template<class_CharT,class_Alloc>booloperator<(const _Rope_const_iterator<_CharT, _Alloc>& __x,const _Rope_const_iterator<_CharT, _Alloc>& __y);template<class_CharT,class_Alloc>
ptrdiff_t
operator-(const _Rope_const_iterator<_CharT, _Alloc>& __x,const _Rope_const_iterator<_CharT, _Alloc>& __y);template<class_CharT,class_Alloc>
_Rope_iterator<_CharT, _Alloc>operator-(const _Rope_iterator<_CharT, _Alloc>& __x, ptrdiff_t __n);template<class_CharT,class_Alloc>
_Rope_iterator<_CharT, _Alloc>operator+(const _Rope_iterator<_CharT, _Alloc>& __x, ptrdiff_t __n);template<class_CharT,class_Alloc>
_Rope_iterator<_CharT, _Alloc>operator+(ptrdiff_t __n,const _Rope_iterator<_CharT, _Alloc>& __x);template<class_CharT,class_Alloc>booloperator==(const _Rope_iterator<_CharT, _Alloc>& __x,const _Rope_iterator<_CharT, _Alloc>& __y);template<class_CharT,class_Alloc>booloperator<(const _Rope_iterator<_CharT, _Alloc>& __x,const _Rope_iterator<_CharT, _Alloc>& __y);template<class_CharT,class_Alloc>
ptrdiff_t
operator-(const _Rope_iterator<_CharT, _Alloc>& __x,const _Rope_iterator<_CharT, _Alloc>& __y);template<class_CharT,class_Alloc>
rope<_CharT, _Alloc>operator+(const rope<_CharT, _Alloc>& __left,const rope<_CharT, _Alloc>& __right);template<class_CharT,class_Alloc>
rope<_CharT, _Alloc>operator+(const rope<_CharT, _Alloc>& __left,const _CharT* __right);template<class_CharT,class_Alloc>
rope<_CharT, _Alloc>operator+(const rope<_CharT, _Alloc>& __left, _CharT __right);// Some helpers, so we can use power on ropes.// See below for why this isn't local to the implementation.// This uses a nonstandard refcount convention.// The result has refcount 0.template<class_CharT,class_Alloc>struct _Rope_Concat_fn
:public std::binary_function<rope<_CharT, _Alloc>, rope<_CharT, _Alloc>,
rope<_CharT, _Alloc>>{
rope<_CharT, _Alloc>operator()(const rope<_CharT, _Alloc>& __x,const rope<_CharT, _Alloc>& __y){
return __x + __y;}};template<class_CharT,class_Alloc>inline rope<_CharT, _Alloc>identity_element(_Rope_Concat_fn<_CharT, _Alloc>){
return rope<_CharT, _Alloc>();}// Class _Refcount_Base provides a type, _RC_t, a data member,// _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_ttypedef size_t _RC_t;// The data member _M_ref_countvolatile _RC_t _M_ref_count;// Constructor#ifdef __GTHREAD_MUTEX_INIT
__gthread_mutex_t _M_ref_count_lock = __GTHREAD_MUTEX_INIT;#else
__gthread_mutex_t _M_ref_count_lock;#endif_Refcount_Base(_RC_t __n):_M_ref_count(__n){
#ifndef __GTHREAD_MUTEX_INIT#ifdef __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#endif}#ifndef __GTHREAD_MUTEX_INIT~_Refcount_Base(){
__gthread_mutex_destroy(&_M_ref_count_lock);}#endifvoid_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);}
allocator_type&_M_get_allocator(){
return*static_cast<_Alloc*>(this);}const allocator_type&_M_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};template<class_CharT,class_Alloc>struct _Rope_RopeRep
:public _Rope_rep_base<_CharT, _Alloc># ifndef __GC, _Refcount_Base
# endif{
public:
__detail::_Tag _M_tag:8;bool _M_is_balanced:8;unsignedchar _M_depth;
__GC_CONST _CharT* _M_c_string;#ifdef __GTHREAD_MUTEX_INIT
__gthread_mutex_t _M_c_string_lock = __GTHREAD_MUTEX_INIT;#else
__gthread_mutex_t _M_c_string_lock;#endif/* 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. */typedeftypename _Rope_rep_base<_CharT, _Alloc>::allocator_type
allocator_type;using _Rope_rep_base<_CharT, _Alloc>::get_allocator;using _Rope_rep_base<_CharT, _Alloc>::_M_get_allocator;_Rope_RopeRep(__detail::_Tag __t,int __d,bool __b, size_t __size,const 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{
}#else{
__GTHREAD_MUTEX_INIT_FUNCTION (&_M_c_string_lock);}~_Rope_RopeRep(){
__gthread_mutex_destroy (&_M_c_string_lock);}#endif#ifdef __GCvoid
_M_incr (){
}#endifstaticvoid_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 __GCvoid_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();}staticvoid_S_unref(_Rope_RopeRep* __t){
if(0!= __t)
__t->_M_unref_nonnil();}staticvoid_S_ref(_Rope_RopeRep* __t){
if(0!= __t)
__t->_M_incr();}staticvoid_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(){
}staticvoid_S_unref(_Rope_RopeRep*){
}staticvoid_S_ref(_Rope_RopeRep*){
}staticvoid_S_free_if_unref(_Rope_RopeRep*){
}# endifprotected:
_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 __GCreturn __size_with_eos;#else