mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-20 09:35:05 +08:00
de196e5dd8
There are a lot of things in the C++ standard library which were deprecated in C++11, and more in C++17. Some of them were removed after deprecation and are no longer present in the standard at all. We have not removed these from libstdc++ because keeping them as non-standard extensions is conforming, and avoids gratuitously breaking user code, and in some cases we need to keep using them to avoid ABI changes. But we should at least give a warning for using them. That has not been done previously because of the library's own uses of them (e.g. the std::iterator class template used as a base class). This adds deprecated attributes to the relevant components, and then goes through the whole library to add diagnostic pragmas where needed to suppress warnings about our internal uses of them. The tests are updated to either expect the additional warnings, or to suppress them where we aren't interested in them. libstdc++-v3/ChangeLog: PR libstdc++/91260 PR libstdc++/91383 PR libstdc++/95065 * include/backward/binders.h (bind1st, bind2nd): Add deprecated attribute. * include/bits/refwrap.h (_Maybe_unary_or_binary_function): Disable deprecated warnings for base classes. (_Reference_wrapper_base): Likewise. * include/bits/shared_ptr_base.h (_Sp_owner_less): Likewise. * include/bits/stl_bvector.h (_Bit_iterator_base): Likewise. * include/bits/stl_function.h (unary_function, binary_function): Add deprecated attribute. (unary_negate, not1, binary_negate, not2, ptr_fun) (pointer_to_unary_function, pointer_to_binary_function) (mem_fun_t, const_mem_fun_t, mem_fun_ref_t, const_mem_fun_ref_t) (mem_fun1_t, const_mem_fun1_t, mem_fun_ref1_t) (const_mem_fun1_ref_t, mem_fun, mem_fun_ref): Add deprecated attributes. * include/bits/stl_iterator.h: Disable deprecated warnings for std::iterator base classes. * include/bits/stl_iterator_base_types.h (iterator): Add deprecated attribute. * include/bits/stl_map.h (map::value_compare): Disable deprecated warnings for base class. * include/bits/stl_multimap.h (multimap::value_compare): Likewise. * include/bits/stl_raw_storage_iter.h (raw_storage_iterator): Add deprecated attribute. * include/bits/stl_tempbuf.h (get_temporary_buffer): Likewise. * include/bits/stream_iterator.h: Disable deprecated warnings. * include/bits/streambuf_iterator.h: Likewise. * include/ext/bitmap_allocator.h: Remove unary_function base classes. * include/ext/functional: Disable deprecated warnings. * include/ext/rope: Likewise. * include/ext/throw_allocator.h: Likewise. * include/std/type_traits (result_of): Add deprecated attribute. * include/tr1/functional: Disable deprecated warnings. * include/tr1/functional_hash.h: Likewise. * testsuite/20_util/function_objects/binders/1.cc: Add -Wno-disable-deprecations. * testsuite/20_util/function_objects/binders/3113.cc: Likewise. * testsuite/20_util/function_objects/constexpr.cc: Add dg-warning. * testsuite/20_util/raw_storage_iterator/base.cc: Likewise. * testsuite/20_util/raw_storage_iterator/dr2127.cc: Likewise. * testsuite/20_util/raw_storage_iterator/requirements/base_classes.cc: Likewise. * testsuite/20_util/raw_storage_iterator/requirements/explicit_instantiation/1.cc: Likewise. * testsuite/20_util/raw_storage_iterator/requirements/typedefs.cc: Likewise. * testsuite/20_util/reference_wrapper/24803.cc: Likewise. * testsuite/20_util/reference_wrapper/typedefs.cc: Enable for C++20 and check for absence of nested types. * testsuite/20_util/shared_ptr/comparison/less.cc: Remove std::binary_function base class. * testsuite/20_util/temporary_buffer.cc: Add dg-warning. * testsuite/21_strings/basic_string/cons/char/69092.cc: Remove std::iterator base class. * testsuite/24_iterators/back_insert_iterator/requirements/base_classes.cc: Likewise. * testsuite/24_iterators/front_insert_iterator/requirements/base_classes.cc: Likewise. * testsuite/24_iterators/insert_iterator/requirements/base_classes.cc: Likewise. * testsuite/24_iterators/istream_iterator/requirements/base_classes.cc: Likewise. * testsuite/24_iterators/istreambuf_iterator/92285.cc: Likewise. * testsuite/24_iterators/istreambuf_iterator/requirements/base_classes.cc: Likewise. * testsuite/24_iterators/ostream_iterator/requirements/base_classes.cc: Likewise. * testsuite/24_iterators/ostreambuf_iterator/requirements/base_classes.cc: Likewise. * testsuite/24_iterators/reverse_iterator/requirements/base_classes.cc: Likewise. * testsuite/25_algorithms/copy/34595.cc: Likewise. * testsuite/25_algorithms/minmax/3.cc: Remove std::binary_function base class. * testsuite/25_algorithms/all_of/requirements/explicit_instantiation/2.cc: Disable deprecated warnings. * testsuite/25_algorithms/all_of/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/any_of/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/any_of/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/copy_if/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/copy_if/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/count_if/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/count_if/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/find_end/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/find_end/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/find_first_of/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/find_first_of/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/find_if/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/find_if/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/find_if_not/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/find_if_not/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/for_each/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/for_each/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/is_partitioned/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/is_partitioned/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/is_permutation/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/is_permutation/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/none_of/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/none_of/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/partition/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/partition/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/partition_copy/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/partition_copy/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/partition_point/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/partition_point/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/random_shuffle/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/random_shuffle/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/remove_copy_if/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/remove_copy_if/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/remove_if/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/remove_if/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/replace_copy_if/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/replace_copy_if/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/replace_if/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/replace_if/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/search/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/search/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/search_n/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/search_n/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/stable_partition/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/stable_partition/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/25_algorithms/transform/requirements/explicit_instantiation/2.cc: Likewise. * testsuite/25_algorithms/transform/requirements/explicit_instantiation/pod.cc: Likewise. * testsuite/27_io/basic_filebuf/underflow/wchar_t/9178.cc: Add dg-warning. * testsuite/ext/pb_ds/example/priority_queue_erase_if.cc: Likewise. * testsuite/ext/pb_ds/example/priority_queue_split_join.cc: Likewise. * testsuite/tr1/3_function_objects/reference_wrapper/typedefs.cc: Disable deprecated warnings. * testsuite/tr1/6_containers/hash/requirements/base_classes.cc: Likewise. * testsuite/util/regression/trait/erase_if_fn.hpp: Remove std::unary_function base classes. * testsuite/util/testsuite_iterators.h (output_iterator_wrapper): Remove std::iterator base classes.
3013 lines
88 KiB
C++
3013 lines
88 KiB
C++
// SGI's rope class -*- C++ -*-
|
|
|
|
// Copyright (C) 2001-2022 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 <ext/alloc_traits.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_n
|
|
|
|
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
namespace __detail
|
|
{
|
|
enum { _S_max_rope_depth = 45 };
|
|
enum _Tag {_S_leaf, _S_concat, _S_substringfn, _S_function};
|
|
} // namespace __detail
|
|
|
|
// 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>
|
|
inline void
|
|
_Destroy_const(_ForwardIterator __first,
|
|
_ForwardIterator __last, std::allocator<_Tp>)
|
|
{ std::_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>
|
|
inline bool
|
|
_S_is_basic_char_type(_CharT*)
|
|
{ return false; }
|
|
|
|
template <class _CharT>
|
|
inline bool
|
|
_S_is_one_byte_char_type(_CharT*)
|
|
{ return false; }
|
|
|
|
inline bool
|
|
_S_is_basic_char_type(char*)
|
|
{ return true; }
|
|
|
|
inline bool
|
|
_S_is_one_byte_char_type(char*)
|
|
{ return true; }
|
|
|
|
inline bool
|
|
_S_is_basic_char_type(wchar_t*)
|
|
{ return true; }
|
|
|
|
// Store an eos iff _CharT is a basic character type.
|
|
// Do not reference _S_eos if it isn't.
|
|
template <class _CharT>
|
|
inline void
|
|
_S_cond_store_eos(_CharT&) { }
|
|
|
|
inline void
|
|
_S_cond_store_eos(char& __c)
|
|
{ __c = 0; }
|
|
|
|
inline void
|
|
_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>
|
|
class char_producer
|
|
{
|
|
public:
|
|
virtual ~char_producer() { }
|
|
|
|
virtual void
|
|
operator()(std::size_t __start_pos, std::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.
|
|
|
|
// Ignore warnings about std::iterator.
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
template<class _Sequence, std::size_t _Buf_sz = 100>
|
|
class sequence_buffer
|
|
: public std::iterator<std::output_iterator_tag, void, void, void, void>
|
|
{
|
|
public:
|
|
typedef typename _Sequence::value_type value_type;
|
|
protected:
|
|
_Sequence* _M_prefix;
|
|
value_type _M_buffer[_Buf_sz];
|
|
std::size_t _M_buf_count;
|
|
public:
|
|
|
|
void
|
|
flush()
|
|
{
|
|
_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);
|
|
}
|
|
|
|
// Non-const "copy" modifies the parameter - yuck
|
|
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) { }
|
|
|
|
// Non-const "copy" modifies the parameter - yuck
|
|
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;
|
|
}
|
|
|
|
#if __cplusplus >= 201103L
|
|
sequence_buffer(sequence_buffer&& __x) : sequence_buffer(__x) { }
|
|
sequence_buffer& operator=(sequence_buffer&& __x) { return *this = __x; }
|
|
#endif
|
|
|
|
void
|
|
push_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;
|
|
}
|
|
}
|
|
|
|
void
|
|
append(value_type* __s, std::size_t __len)
|
|
{
|
|
if (__len + _M_buf_count <= _Buf_sz)
|
|
{
|
|
std::size_t __i = _M_buf_count;
|
|
for (std::size_t __j = 0; __j < __len; __i++, __j++)
|
|
_M_buffer[__i] = __s[__j];
|
|
_M_buf_count += __len;
|
|
}
|
|
else if (0 == _M_buf_count)
|
|
_M_prefix->append(__s, __s + __len);
|
|
else
|
|
{
|
|
flush();
|
|
append(__s, __len);
|
|
}
|
|
}
|
|
|
|
sequence_buffer&
|
|
write(value_type* __s, std::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; }
|
|
};
|
|
#pragma GCC diagnostic pop
|
|
|
|
// 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() { }
|
|
|
|
virtual bool
|
|
operator()(const _CharT* __buffer, std::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 = std::allocator<_CharT> >
|
|
class rope;
|
|
|
|
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>
|
|
bool
|
|
operator==(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,
|
|
std::ptrdiff_t __n);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
_Rope_const_iterator<_CharT, _Alloc>
|
|
operator+(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
std::ptrdiff_t __n);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
_Rope_const_iterator<_CharT, _Alloc>
|
|
operator+(std::ptrdiff_t __n,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __x);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
bool
|
|
operator==(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __y);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
bool
|
|
operator<(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __y);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
std::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, std::ptrdiff_t __n);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
_Rope_iterator<_CharT, _Alloc>
|
|
operator+(const _Rope_iterator<_CharT, _Alloc>& __x, std::ptrdiff_t __n);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
_Rope_iterator<_CharT, _Alloc>
|
|
operator+(std::ptrdiff_t __n, const _Rope_iterator<_CharT, _Alloc>& __x);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
bool
|
|
operator==(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_iterator<_CharT, _Alloc>& __y);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
bool
|
|
operator<(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_iterator<_CharT, _Alloc>& __y);
|
|
|
|
template<class _CharT, class _Alloc>
|
|
std::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.
|
|
|
|
// Ignore warnings about std::binary_function.
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
// 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; }
|
|
};
|
|
#pragma GCC diagnostic pop
|
|
|
|
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_t
|
|
typedef std::size_t _RC_t;
|
|
|
|
// The data member _M_ref_count
|
|
_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); }
|
|
#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);
|
|
_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 std::size_t size_type;
|
|
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_type __size, const allocator_type&)
|
|
: _M_size(__size) { }
|
|
|
|
size_type _M_size;
|
|
|
|
# define __ROPE_DEFINE_ALLOC(_Tp, __name) \
|
|
typedef typename \
|
|
__alloc_traits<_Alloc>::template rebind<_Tp>::other __name##Alloc; \
|
|
static _Tp* __name##_allocate(size_type __n) \
|
|
{ return __name##Alloc().allocate(__n); } \
|
|
static void __name##_deallocate(_Tp *__p, size_type __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;
|
|
unsigned char _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. */
|
|
typedef typename _Rope_rep_base<_CharT, _Alloc>::allocator_type
|
|
allocator_type;
|
|
typedef std::size_t size_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_type __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 __GC
|
|
void
|
|
_M_incr () { }
|
|
#endif
|
|
static void
|
|
_S_free_string(__GC_CONST _CharT*, size_type __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>
|
|
{
|
|
typedef std::size_t size_type;
|
|
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_type
|
|
_S_rounded_up_size(size_type __n)
|
|
{
|
|
size_type __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 + size_type(_S_alloc_granularity) - 1)
|
|
&~ (size_type(_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_type __size,
|
|
const allocator_type& __a)
|
|
: _Rope_RopeRep<_CharT, _Alloc>(__detail::_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();
|
|
|
|
this->__STL_FREE_STRING(_M_data, this->_M_size, this->_M_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,
|
|
const allocator_type& __a)
|
|
: _Rope_RopeRep<_CharT, _Alloc>(__detail::_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, std::size_t __size,
|
|
bool __d, const allocator_type& __a)
|
|
: _Rope_RopeRep<_CharT, _Alloc>(__detail::_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&);
|
|
};
|
|
// Substring results are usually represented using just
|
|
// concatenation nodes. But in the case of very long flat ropes
|
|
// or ropes with a functional representation that isn't practical.
|
|
// In that case, we represent the __result as a special case of
|
|
// RopeFunction, whose char_producer points back to the rope itself.
|
|
// In all cases except repeated substring operations and
|
|
// deallocation, we treat the __result as a RopeFunction.
|
|
template<class _CharT, class _Alloc>
|
|
struct _Rope_RopeSubstring
|
|
: public _Rope_RopeFunction<_CharT, _Alloc>,
|
|
public char_producer<_CharT>
|
|
{
|
|
typedef std::size_t size_type;
|
|
public:
|
|
// XXX this whole class should be rewritten.
|
|
_Rope_RopeRep<_CharT,_Alloc>* _M_base; // not 0
|
|
size_type _M_start;
|
|
|
|
virtual void
|
|
operator()(size_type __start_pos, size_type __req_len,
|
|
_CharT* __buffer)
|
|
{
|
|
switch(_M_base->_M_tag)
|
|
{
|
|
case __detail::_S_function:
|
|
case __detail::_S_substringfn:
|
|
{
|
|
char_producer<_CharT>* __fn =
|
|
((_Rope_RopeFunction<_CharT,_Alloc>*)_M_base)->_M_fn;
|
|
(*__fn)(__start_pos + _M_start, __req_len, __buffer);
|
|
}
|
|
break;
|
|
case __detail::_S_leaf:
|
|
{
|
|
__GC_CONST _CharT* __s =
|
|
((_Rope_RopeLeaf<_CharT,_Alloc>*)_M_base)->_M_data;
|
|
uninitialized_copy_n(__s + __start_pos + _M_start, __req_len,
|
|
__buffer);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
typedef typename _Rope_rep_base<_CharT, _Alloc>::allocator_type
|
|
allocator_type;
|
|
|
|
_Rope_RopeSubstring(_Rope_RopeRep<_CharT, _Alloc>* __b, size_type __s,
|
|
size_type __l, const allocator_type& __a)
|
|
: _Rope_RopeFunction<_CharT, _Alloc>(this, __l, false, __a),
|
|
char_producer<_CharT>(), _M_base(__b), _M_start(__s)
|
|
{
|
|
#ifndef __GC
|
|
_M_base->_M_ref_nonnil();
|
|
#endif
|
|
this->_M_tag = __detail::_S_substringfn;
|
|
}
|
|
virtual ~_Rope_RopeSubstring() throw()
|
|
{
|
|
#ifndef __GC
|
|
_M_base->_M_unref_nonnil();
|
|
// _M_free_c_string(); -- done by parent class
|
|
#endif
|
|
}
|
|
};
|
|
|
|
// Self-destructing pointers to Rope_rep.
|
|
// These are not conventional smart pointers. Their
|
|
// only purpose in life is to ensure that unref is called
|
|
// on the pointer either at normal exit or if an exception
|
|
// is raised. It is the caller's responsibility to
|
|
// adjust reference counts when these pointers are initialized
|
|
// or assigned to. (This convention significantly reduces
|
|
// the number of potentially expensive reference count
|
|
// updates.)
|
|
#ifndef __GC
|
|
template<class _CharT, class _Alloc>
|
|
struct _Rope_self_destruct_ptr
|
|
{
|
|
_Rope_RopeRep<_CharT, _Alloc>* _M_ptr;
|
|
|
|
~_Rope_self_destruct_ptr()
|
|
{ _Rope_RopeRep<_CharT, _Alloc>::_S_unref(_M_ptr); }
|
|
#if __cpp_exceptions
|
|
_Rope_self_destruct_ptr() : _M_ptr(0) { }
|
|
#else
|
|
_Rope_self_destruct_ptr() { }
|
|
#endif
|
|
_Rope_self_destruct_ptr(_Rope_RopeRep<_CharT, _Alloc>* __p)
|
|
: _M_ptr(__p) { }
|
|
|
|
_Rope_RopeRep<_CharT, _Alloc>&
|
|
operator*()
|
|
{ return *_M_ptr; }
|
|
|
|
_Rope_RopeRep<_CharT, _Alloc>*
|
|
operator->()
|
|
{ return _M_ptr; }
|
|
|
|
operator _Rope_RopeRep<_CharT, _Alloc>*()
|
|
{ return _M_ptr; }
|
|
|
|
_Rope_self_destruct_ptr&
|
|
operator=(_Rope_RopeRep<_CharT, _Alloc>* __x)
|
|
{ _M_ptr = __x; return *this; }
|
|
};
|
|
#endif
|
|
|
|
// Dereferencing a nonconst iterator has to return something
|
|
// that behaves almost like a reference. It's not possible to
|
|
// return an actual reference since assignment requires extra
|
|
// work. And we would get into the same problems as with the
|
|
// CD2 version of basic_string.
|
|
template<class _CharT, class _Alloc>
|
|
class _Rope_char_ref_proxy
|
|
{
|
|
friend class rope<_CharT, _Alloc>;
|
|
friend class _Rope_iterator<_CharT, _Alloc>;
|
|
friend class _Rope_char_ptr_proxy<_CharT, _Alloc>;
|
|
#ifdef __GC
|
|
typedef _Rope_RopeRep<_CharT, _Alloc>* _Self_destruct_ptr;
|
|
#else
|
|
typedef _Rope_self_destruct_ptr<_CharT, _Alloc> _Self_destruct_ptr;
|
|
#endif
|
|
typedef _Rope_RopeRep<_CharT, _Alloc> _RopeRep;
|
|
typedef rope<_CharT, _Alloc> _My_rope;
|
|
std::size_t _M_pos;
|
|
_CharT _M_current;
|
|
bool _M_current_valid;
|
|
_My_rope* _M_root; // The whole rope.
|
|
public:
|
|
_Rope_char_ref_proxy(_My_rope* __r, std::size_t __p)
|
|
: _M_pos(__p), _M_current(), _M_current_valid(false), _M_root(__r) { }
|
|
|
|
_Rope_char_ref_proxy(const _Rope_char_ref_proxy& __x)
|
|
: _M_pos(__x._M_pos), _M_current(__x._M_current),
|
|
_M_current_valid(false), _M_root(__x._M_root) { }
|
|
|
|
// Don't preserve cache if the reference can outlive the
|
|
// expression. We claim that's not possible without calling
|
|
// a copy constructor or generating reference to a proxy
|
|
// reference. We declare the latter to have undefined semantics.
|
|
_Rope_char_ref_proxy(_My_rope* __r, std::size_t __p, _CharT __c)
|
|
: _M_pos(__p), _M_current(__c), _M_current_valid(true), _M_root(__r) { }
|
|
|
|
inline operator _CharT () const;
|
|
|
|
_Rope_char_ref_proxy&
|
|
operator=(_CharT __c);
|
|
|
|
_Rope_char_ptr_proxy<_CharT, _Alloc> operator&() const;
|
|
|
|
_Rope_char_ref_proxy&
|
|
operator=(const _Rope_char_ref_proxy& __c)
|
|
{ return operator=((_CharT)__c); }
|
|
};
|
|
|
|
template<class _CharT, class __Alloc>
|
|
inline void
|
|
swap(_Rope_char_ref_proxy <_CharT, __Alloc > __a,
|
|
_Rope_char_ref_proxy <_CharT, __Alloc > __b)
|
|
{
|
|
_CharT __tmp = __a;
|
|
__a = __b;
|
|
__b = __tmp;
|
|
}
|
|
|
|
template<class _CharT, class _Alloc>
|
|
class _Rope_char_ptr_proxy
|
|
{
|
|
// XXX this class should be rewritten.
|
|
friend class _Rope_char_ref_proxy<_CharT, _Alloc>;
|
|
std::size_t _M_pos;
|
|
rope<_CharT,_Alloc>* _M_root; // The whole rope.
|
|
public:
|
|
_Rope_char_ptr_proxy(const _Rope_char_ref_proxy<_CharT,_Alloc>& __x)
|
|
: _M_pos(__x._M_pos), _M_root(__x._M_root) { }
|
|
|
|
_Rope_char_ptr_proxy(const _Rope_char_ptr_proxy& __x)
|
|
: _M_pos(__x._M_pos), _M_root(__x._M_root) { }
|
|
|
|
_Rope_char_ptr_proxy() { }
|
|
|
|
_Rope_char_ptr_proxy(_CharT* __x)
|
|
: _M_root(0), _M_pos(0) { }
|
|
|
|
_Rope_char_ptr_proxy&
|
|
operator=(const _Rope_char_ptr_proxy& __x)
|
|
{
|
|
_M_pos = __x._M_pos;
|
|
_M_root = __x._M_root;
|
|
return *this;
|
|
}
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend bool
|
|
operator==(const _Rope_char_ptr_proxy<_CharT2, _Alloc2>& __x,
|
|
const _Rope_char_ptr_proxy<_CharT2, _Alloc2>& __y);
|
|
|
|
_Rope_char_ref_proxy<_CharT, _Alloc> operator*() const
|
|
{ return _Rope_char_ref_proxy<_CharT, _Alloc>(_M_root, _M_pos); }
|
|
};
|
|
|
|
// Rope iterators:
|
|
// Unlike in the C version, we cache only part of the stack
|
|
// for rope iterators, since they must be efficiently copyable.
|
|
// When we run out of cache, we have to reconstruct the iterator
|
|
// value.
|
|
// Pointers from iterators are not included in reference counts.
|
|
// Iterators are assumed to be thread private. Ropes can
|
|
// be shared.
|
|
|
|
// Ignore warnings about std::iterator
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
template<class _CharT, class _Alloc>
|
|
class _Rope_iterator_base
|
|
: public std::iterator<std::random_access_iterator_tag, _CharT>
|
|
{
|
|
friend class rope<_CharT, _Alloc>;
|
|
public:
|
|
typedef _Alloc _allocator_type; // used in _Rope_rotate, VC++ workaround
|
|
typedef _Rope_RopeRep<_CharT, _Alloc> _RopeRep;
|
|
// Borland doesn't want this to be protected.
|
|
protected:
|
|
enum { _S_path_cache_len = 4 }; // Must be <= 9.
|
|
enum { _S_iterator_buf_len = 15 };
|
|
std::size_t _M_current_pos;
|
|
_RopeRep* _M_root; // The whole rope.
|
|
std::size_t _M_leaf_pos; // Starting position for current leaf
|
|
__GC_CONST _CharT* _M_buf_start;
|
|
// Buffer possibly
|
|
// containing current char.
|
|
__GC_CONST _CharT* _M_buf_ptr;
|
|
// Pointer to current char in buffer.
|
|
// != 0 ==> buffer valid.
|
|
__GC_CONST _CharT* _M_buf_end;
|
|
// One past __last valid char in buffer.
|
|
// What follows is the path cache. We go out of our
|
|
// way to make this compact.
|
|
// Path_end contains the bottom section of the path from
|
|
// the root to the current leaf.
|
|
const _RopeRep* _M_path_end[_S_path_cache_len];
|
|
int _M_leaf_index; // Last valid __pos in path_end;
|
|
// _M_path_end[0] ... _M_path_end[leaf_index-1]
|
|
// point to concatenation nodes.
|
|
unsigned char _M_path_directions;
|
|
// (path_directions >> __i) & 1 is 1
|
|
// iff we got from _M_path_end[leaf_index - __i - 1]
|
|
// to _M_path_end[leaf_index - __i] by going to the
|
|
// __right. Assumes path_cache_len <= 9.
|
|
_CharT _M_tmp_buf[_S_iterator_buf_len];
|
|
// Short buffer for surrounding chars.
|
|
// This is useful primarily for
|
|
// RopeFunctions. We put the buffer
|
|
// here to avoid locking in the
|
|
// multithreaded case.
|
|
// The cached path is generally assumed to be valid
|
|
// only if the buffer is valid.
|
|
static void _S_setbuf(_Rope_iterator_base& __x);
|
|
// Set buffer contents given
|
|
// path cache.
|
|
static void _S_setcache(_Rope_iterator_base& __x);
|
|
// Set buffer contents and
|
|
// path cache.
|
|
static void _S_setcache_for_incr(_Rope_iterator_base& __x);
|
|
// As above, but assumes path
|
|
// cache is valid for previous posn.
|
|
_Rope_iterator_base() { }
|
|
|
|
_Rope_iterator_base(_RopeRep* __root, std::size_t __pos)
|
|
: _M_current_pos(__pos), _M_root(__root), _M_buf_ptr(0) { }
|
|
|
|
void _M_incr(std::size_t __n);
|
|
void _M_decr(std::size_t __n);
|
|
public:
|
|
std::size_t
|
|
index() const
|
|
{ return _M_current_pos; }
|
|
|
|
_Rope_iterator_base(const _Rope_iterator_base& __x)
|
|
{
|
|
if (0 != __x._M_buf_ptr && __x._M_buf_start != __x._M_tmp_buf)
|
|
*this = __x;
|
|
else
|
|
{
|
|
_M_current_pos = __x._M_current_pos;
|
|
_M_root = __x._M_root;
|
|
_M_buf_ptr = 0;
|
|
}
|
|
}
|
|
};
|
|
#pragma GCC diagnostic pop
|
|
|
|
template<class _CharT, class _Alloc>
|
|
class _Rope_iterator;
|
|
|
|
template<class _CharT, class _Alloc>
|
|
class _Rope_const_iterator
|
|
: public _Rope_iterator_base<_CharT, _Alloc>
|
|
{
|
|
friend class rope<_CharT, _Alloc>;
|
|
protected:
|
|
typedef _Rope_RopeRep<_CharT, _Alloc> _RopeRep;
|
|
// The one from the base class may not be directly visible.
|
|
_Rope_const_iterator(const _RopeRep* __root, std::size_t __pos)
|
|
: _Rope_iterator_base<_CharT, _Alloc>(const_cast<_RopeRep*>(__root),
|
|
__pos)
|
|
// Only nonconst iterators modify root ref count
|
|
{ }
|
|
public:
|
|
typedef _CharT reference; // Really a value. Returning a reference
|
|
// Would be a mess, since it would have
|
|
// to be included in refcount.
|
|
typedef const _CharT* pointer;
|
|
|
|
public:
|
|
_Rope_const_iterator() { }
|
|
|
|
_Rope_const_iterator(const _Rope_const_iterator& __x)
|
|
: _Rope_iterator_base<_CharT,_Alloc>(__x) { }
|
|
|
|
_Rope_const_iterator(const _Rope_iterator<_CharT,_Alloc>& __x);
|
|
|
|
_Rope_const_iterator(const rope<_CharT, _Alloc>& __r, std::size_t __pos)
|
|
: _Rope_iterator_base<_CharT,_Alloc>(__r._M_tree_ptr, __pos) { }
|
|
|
|
_Rope_const_iterator&
|
|
operator=(const _Rope_const_iterator& __x)
|
|
{
|
|
if (0 != __x._M_buf_ptr && __x._M_buf_start != __x._M_tmp_buf)
|
|
*(static_cast<_Rope_iterator_base<_CharT, _Alloc>*>(this)) = __x;
|
|
else
|
|
{
|
|
this->_M_current_pos = __x._M_current_pos;
|
|
this->_M_root = __x._M_root;
|
|
this->_M_buf_ptr = 0;
|
|
}
|
|
return(*this);
|
|
}
|
|
|
|
reference
|
|
operator*()
|
|
{
|
|
if (0 == this->_M_buf_ptr)
|
|
this->_S_setcache(*this);
|
|
return *this->_M_buf_ptr;
|
|
}
|
|
|
|
// Without this const version, Rope iterators do not meet the
|
|
// requirements of an Input Iterator.
|
|
reference
|
|
operator*() const
|
|
{
|
|
return *const_cast<_Rope_const_iterator&>(*this);
|
|
}
|
|
|
|
_Rope_const_iterator&
|
|
operator++()
|
|
{
|
|
__GC_CONST _CharT* __next;
|
|
if (0 != this->_M_buf_ptr
|
|
&& (__next = this->_M_buf_ptr + 1) < this->_M_buf_end)
|
|
{
|
|
this->_M_buf_ptr = __next;
|
|
++this->_M_current_pos;
|
|
}
|
|
else
|
|
this->_M_incr(1);
|
|
return *this;
|
|
}
|
|
|
|
_Rope_const_iterator&
|
|
operator+=(std::ptrdiff_t __n)
|
|
{
|
|
if (__n >= 0)
|
|
this->_M_incr(__n);
|
|
else
|
|
this->_M_decr(-__n);
|
|
return *this;
|
|
}
|
|
|
|
_Rope_const_iterator&
|
|
operator--()
|
|
{
|
|
this->_M_decr(1);
|
|
return *this;
|
|
}
|
|
|
|
_Rope_const_iterator&
|
|
operator-=(std::ptrdiff_t __n)
|
|
{
|
|
if (__n >= 0)
|
|
this->_M_decr(__n);
|
|
else
|
|
this->_M_incr(-__n);
|
|
return *this;
|
|
}
|
|
|
|
_Rope_const_iterator
|
|
operator++(int)
|
|
{
|
|
std::size_t __old_pos = this->_M_current_pos;
|
|
this->_M_incr(1);
|
|
return _Rope_const_iterator<_CharT,_Alloc>(this->_M_root, __old_pos);
|
|
// This makes a subsequent dereference expensive.
|
|
// Perhaps we should instead copy the iterator
|
|
// if it has a valid cache?
|
|
}
|
|
|
|
_Rope_const_iterator
|
|
operator--(int)
|
|
{
|
|
std::size_t __old_pos = this->_M_current_pos;
|
|
this->_M_decr(1);
|
|
return _Rope_const_iterator<_CharT,_Alloc>(this->_M_root, __old_pos);
|
|
}
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend _Rope_const_iterator<_CharT2, _Alloc2>
|
|
operator-(const _Rope_const_iterator<_CharT2, _Alloc2>& __x,
|
|
std::ptrdiff_t __n);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend _Rope_const_iterator<_CharT2, _Alloc2>
|
|
operator+(const _Rope_const_iterator<_CharT2, _Alloc2>& __x,
|
|
std::ptrdiff_t __n);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend _Rope_const_iterator<_CharT2, _Alloc2>
|
|
operator+(std::ptrdiff_t __n,
|
|
const _Rope_const_iterator<_CharT2, _Alloc2>& __x);
|
|
|
|
reference
|
|
operator[](std::size_t __n)
|
|
{ return rope<_CharT, _Alloc>::_S_fetch(this->_M_root,
|
|
this->_M_current_pos + __n); }
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend bool
|
|
operator==(const _Rope_const_iterator<_CharT2, _Alloc2>& __x,
|
|
const _Rope_const_iterator<_CharT2, _Alloc2>& __y);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend bool
|
|
operator<(const _Rope_const_iterator<_CharT2, _Alloc2>& __x,
|
|
const _Rope_const_iterator<_CharT2, _Alloc2>& __y);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend std::ptrdiff_t
|
|
operator-(const _Rope_const_iterator<_CharT2, _Alloc2>& __x,
|
|
const _Rope_const_iterator<_CharT2, _Alloc2>& __y);
|
|
};
|
|
|
|
template<class _CharT, class _Alloc>
|
|
class _Rope_iterator
|
|
: public _Rope_iterator_base<_CharT, _Alloc>
|
|
{
|
|
friend class rope<_CharT, _Alloc>;
|
|
protected:
|
|
typedef typename _Rope_iterator_base<_CharT, _Alloc>::_RopeRep _RopeRep;
|
|
rope<_CharT, _Alloc>* _M_root_rope;
|
|
|
|
// root is treated as a cached version of this, and is used to
|
|
// detect changes to the underlying rope.
|
|
|
|
// Root is included in the reference count. This is necessary
|
|
// so that we can detect changes reliably. Unfortunately, it
|
|
// requires careful bookkeeping for the nonGC case.
|
|
_Rope_iterator(rope<_CharT, _Alloc>* __r, std::size_t __pos)
|
|
: _Rope_iterator_base<_CharT, _Alloc>(__r->_M_tree_ptr, __pos),
|
|
_M_root_rope(__r)
|
|
{ _RopeRep::_S_ref(this->_M_root);
|
|
if (!(__r -> empty()))
|
|
this->_S_setcache(*this);
|
|
}
|
|
|
|
void _M_check();
|
|
public:
|
|
typedef _Rope_char_ref_proxy<_CharT, _Alloc> reference;
|
|
typedef _Rope_char_ref_proxy<_CharT, _Alloc>* pointer;
|
|
|
|
rope<_CharT, _Alloc>&
|
|
container()
|
|
{ return *_M_root_rope; }
|
|
|
|
_Rope_iterator()
|
|
{
|
|
this->_M_root = 0; // Needed for reference counting.
|
|
}
|
|
|
|
_Rope_iterator(const _Rope_iterator& __x)
|
|
: _Rope_iterator_base<_CharT, _Alloc>(__x)
|
|
{
|
|
_M_root_rope = __x._M_root_rope;
|
|
_RopeRep::_S_ref(this->_M_root);
|
|
}
|
|
|
|
_Rope_iterator(rope<_CharT, _Alloc>& __r, std::size_t __pos);
|
|
|
|
~_Rope_iterator()
|
|
{ _RopeRep::_S_unref(this->_M_root); }
|
|
|
|
_Rope_iterator&
|
|
operator=(const _Rope_iterator& __x)
|
|
{
|
|
_RopeRep* __old = this->_M_root;
|
|
|
|
_RopeRep::_S_ref(__x._M_root);
|
|
if (0 != __x._M_buf_ptr && __x._M_buf_start != __x._M_tmp_buf)
|
|
{
|
|
_M_root_rope = __x._M_root_rope;
|
|
*(static_cast<_Rope_iterator_base<_CharT, _Alloc>*>(this)) = __x;
|
|
}
|
|
else
|
|
{
|
|
this->_M_current_pos = __x._M_current_pos;
|
|
this->_M_root = __x._M_root;
|
|
_M_root_rope = __x._M_root_rope;
|
|
this->_M_buf_ptr = 0;
|
|
}
|
|
_RopeRep::_S_unref(__old);
|
|
return(*this);
|
|
}
|
|
|
|
reference
|
|
operator*()
|
|
{
|
|
_M_check();
|
|
if (0 == this->_M_buf_ptr)
|
|
return _Rope_char_ref_proxy<_CharT, _Alloc>(_M_root_rope,
|
|
this->_M_current_pos);
|
|
else
|
|
return _Rope_char_ref_proxy<_CharT, _Alloc>(_M_root_rope,
|
|
this->_M_current_pos,
|
|
*this->_M_buf_ptr);
|
|
}
|
|
|
|
// See above comment.
|
|
reference
|
|
operator*() const
|
|
{
|
|
return *const_cast<_Rope_iterator&>(*this);
|
|
}
|
|
|
|
_Rope_iterator&
|
|
operator++()
|
|
{
|
|
this->_M_incr(1);
|
|
return *this;
|
|
}
|
|
|
|
_Rope_iterator&
|
|
operator+=(std::ptrdiff_t __n)
|
|
{
|
|
if (__n >= 0)
|
|
this->_M_incr(__n);
|
|
else
|
|
this->_M_decr(-__n);
|
|
return *this;
|
|
}
|
|
|
|
_Rope_iterator&
|
|
operator--()
|
|
{
|
|
this->_M_decr(1);
|
|
return *this;
|
|
}
|
|
|
|
_Rope_iterator&
|
|
operator-=(std::ptrdiff_t __n)
|
|
{
|
|
if (__n >= 0)
|
|
this->_M_decr(__n);
|
|
else
|
|
this->_M_incr(-__n);
|
|
return *this;
|
|
}
|
|
|
|
_Rope_iterator
|
|
operator++(int)
|
|
{
|
|
std::size_t __old_pos = this->_M_current_pos;
|
|
this->_M_incr(1);
|
|
return _Rope_iterator<_CharT,_Alloc>(_M_root_rope, __old_pos);
|
|
}
|
|
|
|
_Rope_iterator
|
|
operator--(int)
|
|
{
|
|
std::size_t __old_pos = this->_M_current_pos;
|
|
this->_M_decr(1);
|
|
return _Rope_iterator<_CharT,_Alloc>(_M_root_rope, __old_pos);
|
|
}
|
|
|
|
reference
|
|
operator[](std::ptrdiff_t __n)
|
|
{ return _Rope_char_ref_proxy<_CharT, _Alloc>(_M_root_rope,
|
|
this->_M_current_pos
|
|
+ __n); }
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend bool
|
|
operator==(const _Rope_iterator<_CharT2, _Alloc2>& __x,
|
|
const _Rope_iterator<_CharT2, _Alloc2>& __y);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend bool
|
|
operator<(const _Rope_iterator<_CharT2, _Alloc2>& __x,
|
|
const _Rope_iterator<_CharT2, _Alloc2>& __y);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend std::ptrdiff_t
|
|
operator-(const _Rope_iterator<_CharT2, _Alloc2>& __x,
|
|
const _Rope_iterator<_CharT2, _Alloc2>& __y);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend _Rope_iterator<_CharT2, _Alloc2>
|
|
operator-(const _Rope_iterator<_CharT2, _Alloc2>& __x,
|
|
std::ptrdiff_t __n);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend _Rope_iterator<_CharT2, _Alloc2>
|
|
operator+(const _Rope_iterator<_CharT2, _Alloc2>& __x,
|
|
std::ptrdiff_t __n);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend _Rope_iterator<_CharT2, _Alloc2>
|
|
operator+(std::ptrdiff_t __n,
|
|
const _Rope_iterator<_CharT2, _Alloc2>& __x);
|
|
};
|
|
|
|
|
|
template <class _CharT, class _Alloc>
|
|
struct _Rope_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); }
|
|
|
|
typedef _Rope_RopeRep<_CharT, _Alloc> _RopeRep;
|
|
// The one in _Base may not be visible due to template rules.
|
|
|
|
_Rope_base(_RopeRep* __t, const allocator_type&)
|
|
: _M_tree_ptr(__t) { }
|
|
|
|
_Rope_base(const allocator_type&) { }
|
|
|
|
// The only data member of a rope:
|
|
_RopeRep *_M_tree_ptr;
|
|
|
|
#define __ROPE_DEFINE_ALLOC(_Tp, __name) \
|
|
typedef typename \
|
|
__alloc_traits<_Alloc>::template rebind<_Tp>::other __name##Alloc; \
|
|
static _Tp* __name##_allocate(std::size_t __n) \
|
|
{ return __name##Alloc().allocate(__n); } \
|
|
static void __name##_deallocate(_Tp *__p, std::size_t __n) \
|
|
{ __name##Alloc().deallocate(__p, __n); }
|
|
__ROPE_DEFINE_ALLOCS(_Alloc)
|
|
#undef __ROPE_DEFINE_ALLOC
|
|
|
|
protected:
|
|
_Rope_base&
|
|
operator=(const _Rope_base&);
|
|
|
|
_Rope_base(const _Rope_base&);
|
|
};
|
|
|
|
/**
|
|
* This is an SGI extension.
|
|
* @ingroup SGIextensions
|
|
* @doctodo
|
|
*/
|
|
template <class _CharT, class _Alloc>
|
|
class rope : public _Rope_base<_CharT, _Alloc>
|
|
{
|
|
public:
|
|
typedef _CharT value_type;
|
|
typedef std::ptrdiff_t difference_type;
|
|
typedef std::size_t size_type;
|
|
typedef _CharT const_reference;
|
|
typedef const _CharT* const_pointer;
|
|
typedef _Rope_iterator<_CharT, _Alloc> iterator;
|
|
typedef _Rope_const_iterator<_CharT, _Alloc> const_iterator;
|
|
typedef _Rope_char_ref_proxy<_CharT, _Alloc> reference;
|
|
typedef _Rope_char_ptr_proxy<_CharT, _Alloc> pointer;
|
|
|
|
friend class _Rope_iterator<_CharT, _Alloc>;
|
|
friend class _Rope_const_iterator<_CharT, _Alloc>;
|
|
friend struct _Rope_RopeRep<_CharT, _Alloc>;
|
|
friend class _Rope_iterator_base<_CharT, _Alloc>;
|
|
friend class _Rope_char_ptr_proxy<_CharT, _Alloc>;
|
|
friend class _Rope_char_ref_proxy<_CharT, _Alloc>;
|
|
friend struct _Rope_RopeSubstring<_CharT, _Alloc>;
|
|
|
|
protected:
|
|
typedef _Rope_base<_CharT, _Alloc> _Base;
|
|
typedef typename _Base::allocator_type allocator_type;
|
|
using _Base::_M_tree_ptr;
|
|
using _Base::get_allocator;
|
|
using _Base::_M_get_allocator;
|
|
typedef __GC_CONST _CharT* _Cstrptr;
|
|
|
|
static _CharT _S_empty_c_str[1];
|
|
|
|
static bool
|
|
_S_is0(_CharT __c)
|
|
{ return __c == _S_eos((_CharT*)0); }
|
|
|
|
enum { _S_copy_max = 23 };
|
|
// For strings shorter than _S_copy_max, we copy to
|
|
// concatenate.
|
|
|
|
typedef _Rope_RopeRep<_CharT, _Alloc> _RopeRep;
|
|
typedef _Rope_RopeConcatenation<_CharT, _Alloc> _RopeConcatenation;
|
|
typedef _Rope_RopeLeaf<_CharT, _Alloc> _RopeLeaf;
|
|
typedef _Rope_RopeFunction<_CharT, _Alloc> _RopeFunction;
|
|
typedef _Rope_RopeSubstring<_CharT, _Alloc> _RopeSubstring;
|
|
|
|
// Retrieve a character at the indicated position.
|
|
static _CharT _S_fetch(_RopeRep* __r, size_type __pos);
|
|
|
|
#ifndef __GC
|
|
// Obtain a pointer to the character at the indicated position.
|
|
// The pointer can be used to change the character.
|
|
// If such a pointer cannot be produced, as is frequently the
|
|
// case, 0 is returned instead.
|
|
// (Returns nonzero only if all nodes in the path have a refcount
|
|
// of 1.)
|
|
static _CharT* _S_fetch_ptr(_RopeRep* __r, size_type __pos);
|
|
#endif
|
|
|
|
static bool
|
|
_S_apply_to_pieces(// should be template parameter
|
|
_Rope_char_consumer<_CharT>& __c,
|
|
const _RopeRep* __r,
|
|
size_type __begin, size_type __end);
|
|
// begin and end are assumed to be in range.
|
|
|
|
#ifndef __GC
|
|
static void
|
|
_S_unref(_RopeRep* __t)
|
|
{ _RopeRep::_S_unref(__t); }
|
|
|
|
static void
|
|
_S_ref(_RopeRep* __t)
|
|
{ _RopeRep::_S_ref(__t); }
|
|
|
|
#else /* __GC */
|
|
static void _S_unref(_RopeRep*) { }
|
|
static void _S_ref(_RopeRep*) { }
|
|
#endif
|
|
|
|
#ifdef __GC
|
|
typedef _Rope_RopeRep<_CharT, _Alloc>* _Self_destruct_ptr;
|
|
#else
|
|
typedef _Rope_self_destruct_ptr<_CharT, _Alloc> _Self_destruct_ptr;
|
|
#endif
|
|
|
|
// _Result is counted in refcount.
|
|
static _RopeRep* _S_substring(_RopeRep* __base,
|
|
size_type __start, size_type __endp1);
|
|
|
|
static _RopeRep* _S_concat_char_iter(_RopeRep* __r,
|
|
const _CharT* __iter,
|
|
size_type __slen,
|
|
allocator_type& __a);
|
|
// Concatenate rope and char ptr, copying __iter.
|
|
// Should really take an arbitrary iterator.
|
|
// Result is counted in refcount.
|
|
static _RopeRep* _S_destr_concat_char_iter(_RopeRep* __r,
|
|
const _CharT* __iter,
|
|
size_type __slen,
|
|
allocator_type& __a)
|
|
// As above, but one reference to __r is about to be
|
|
// destroyed. Thus the pieces may be recycled if all
|
|
// relevant reference counts are 1.
|
|
#ifdef __GC
|
|
// We can't really do anything since refcounts are unavailable.
|
|
{ return _S_concat_char_iter(__r, __iter, __slen, __a); }
|
|
#else
|
|
;
|
|
#endif
|
|
|
|
static _RopeRep* _S_concat(_RopeRep* __left, _RopeRep* __right);
|
|
// General concatenation on _RopeRep. _Result
|
|
// has refcount of 1. Adjusts argument refcounts.
|
|
|
|
public:
|
|
void
|
|
apply_to_pieces(size_type __begin, size_type __end,
|
|
_Rope_char_consumer<_CharT>& __c) const
|
|
{ _S_apply_to_pieces(__c, this->_M_tree_ptr, __begin, __end); }
|
|
|
|
protected:
|
|
|
|
static size_type
|
|
_S_rounded_up_size(size_type __n)
|
|
{ return _RopeLeaf::_S_rounded_up_size(__n); }
|
|
|
|
static size_type
|
|
_S_allocated_capacity(size_type __n)
|
|
{
|
|
if (_S_is_basic_char_type((_CharT*)0))
|
|
return _S_rounded_up_size(__n) - 1;
|
|
else
|
|
return _S_rounded_up_size(__n);
|
|
|
|
}
|
|
|
|
// Allocate and construct a RopeLeaf using the supplied allocator
|
|
// Takes ownership of s instead of copying.
|
|
static _RopeLeaf*
|
|
_S_new_RopeLeaf(__GC_CONST _CharT *__s,
|
|
size_type __size, allocator_type& __a)
|
|
{
|
|
_RopeLeaf* __space = typename _Base::_LAlloc(__a).allocate(1);
|
|
return new(__space) _RopeLeaf(__s, __size, __a);
|
|
}
|
|
|
|
static _RopeConcatenation*
|
|
_S_new_RopeConcatenation(_RopeRep* __left, _RopeRep* __right,
|
|
allocator_type& __a)
|
|
{
|
|
_RopeConcatenation* __space = typename _Base::_CAlloc(__a).allocate(1);
|
|
return new(__space) _RopeConcatenation(__left, __right, __a);
|
|
}
|
|
|
|
static _RopeFunction*
|
|
_S_new_RopeFunction(char_producer<_CharT>* __f,
|
|
size_type __size, bool __d, allocator_type& __a)
|
|
{
|
|
_RopeFunction* __space = typename _Base::_FAlloc(__a).allocate(1);
|
|
return new(__space) _RopeFunction(__f, __size, __d, __a);
|
|
}
|
|
|
|
static _RopeSubstring*
|
|
_S_new_RopeSubstring(_Rope_RopeRep<_CharT,_Alloc>* __b, size_type __s,
|
|
size_type __l, allocator_type& __a)
|
|
{
|
|
_RopeSubstring* __space = typename _Base::_SAlloc(__a).allocate(1);
|
|
return new(__space) _RopeSubstring(__b, __s, __l, __a);
|
|
}
|
|
|
|
static _RopeLeaf*
|
|
_S_RopeLeaf_from_unowned_char_ptr(const _CharT *__s,
|
|
size_type __size, allocator_type& __a)
|
|
#define __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __size, __a) \
|
|
_S_RopeLeaf_from_unowned_char_ptr(__s, __size, __a)
|
|
{
|
|
if (0 == __size)
|
|
return 0;
|
|
_CharT* __buf = __a.allocate(_S_rounded_up_size(__size));
|
|
|
|
__uninitialized_copy_n_a(__s, __size, __buf, __a);
|
|
_S_cond_store_eos(__buf[__size]);
|
|
__try
|
|
{ return _S_new_RopeLeaf(__buf, __size, __a); }
|
|
__catch(...)
|
|
{
|
|
_RopeRep::__STL_FREE_STRING(__buf, __size, __a);
|
|
__throw_exception_again;
|
|
}
|
|
}
|
|
|
|
// Concatenation of nonempty strings.
|
|
// Always builds a concatenation node.
|
|
// Rebalances if the result is too deep.
|
|
// Result has refcount 1.
|
|
// Does not increment left and right ref counts even though
|
|
// they are referenced.
|
|
static _RopeRep*
|
|
_S_tree_concat(_RopeRep* __left, _RopeRep* __right);
|
|
|
|
// Concatenation helper functions
|
|
static _RopeLeaf*
|
|
_S_leaf_concat_char_iter(_RopeLeaf* __r,
|
|
const _CharT* __iter, size_type __slen);
|
|
// Concatenate by copying leaf.
|
|
// should take an arbitrary iterator
|
|
// result has refcount 1.
|
|
#ifndef __GC
|
|
static _RopeLeaf*
|
|
_S_destr_leaf_concat_char_iter(_RopeLeaf* __r,
|
|
const _CharT* __iter, size_type __slen);
|
|
// A version that potentially clobbers __r if __r->_M_ref_count == 1.
|
|
#endif
|
|
|
|
private:
|
|
|
|
static size_type _S_char_ptr_len(const _CharT* __s);
|
|
// slightly generalized strlen
|
|
|
|
rope(_RopeRep* __t, const allocator_type& __a = allocator_type())
|
|
: _Base(__t, __a) { }
|
|
|
|
|
|
// Copy __r to the _CharT buffer.
|
|
// Returns __buffer + __r->_M_size.
|
|
// Assumes that buffer is uninitialized.
|
|
static _CharT* _S_flatten(_RopeRep* __r, _CharT* __buffer);
|
|
|
|
// Again, with explicit starting position and length.
|
|
// Assumes that buffer is uninitialized.
|
|
static _CharT* _S_flatten(_RopeRep* __r,
|
|
size_type __start, size_type __len,
|
|
_CharT* __buffer);
|
|
|
|
static const unsigned long
|
|
_S_min_len[__detail::_S_max_rope_depth + 1];
|
|
|
|
static bool
|
|
_S_is_balanced(_RopeRep* __r)
|
|
{ return (__r->_M_size >= _S_min_len[__r->_M_depth]); }
|
|
|
|
static bool
|
|
_S_is_almost_balanced(_RopeRep* __r)
|
|
{ return (__r->_M_depth == 0
|
|
|| __r->_M_size >= _S_min_len[__r->_M_depth - 1]); }
|
|
|
|
static bool
|
|
_S_is_roughly_balanced(_RopeRep* __r)
|
|
{ return (__r->_M_depth <= 1
|
|
|| __r->_M_size >= _S_min_len[__r->_M_depth - 2]); }
|
|
|
|
// Assumes the result is not empty.
|
|
static _RopeRep*
|
|
_S_concat_and_set_balanced(_RopeRep* __left, _RopeRep* __right)
|
|
{
|
|
_RopeRep* __result = _S_concat(__left, __right);
|
|
if (_S_is_balanced(__result))
|
|
__result->_M_is_balanced = true;
|
|
return __result;
|
|
}
|
|
|
|
// The basic rebalancing operation. Logically copies the
|
|
// rope. The result has refcount of 1. The client will
|
|
// usually decrement the reference count of __r.
|
|
// The result is within height 2 of balanced by the above
|
|
// definition.
|
|
static _RopeRep* _S_balance(_RopeRep* __r);
|
|
|
|
// Add all unbalanced subtrees to the forest of balanced trees.
|
|
// Used only by balance.
|
|
static void _S_add_to_forest(_RopeRep*__r, _RopeRep** __forest);
|
|
|
|
// Add __r to forest, assuming __r is already balanced.
|
|
static void _S_add_leaf_to_forest(_RopeRep* __r, _RopeRep** __forest);
|
|
|
|
// Print to stdout, exposing structure
|
|
static void _S_dump(_RopeRep* __r, int __indent = 0);
|
|
|
|
// Return -1, 0, or 1 if __x < __y, __x == __y, or __x > __y resp.
|
|
static int _S_compare(const _RopeRep* __x, const _RopeRep* __y);
|
|
|
|
public:
|
|
_GLIBCXX_NODISCARD bool
|
|
empty() const
|
|
{ return 0 == this->_M_tree_ptr; }
|
|
|
|
// Comparison member function. This is public only for those
|
|
// clients that need a ternary comparison. Others
|
|
// should use the comparison operators below.
|
|
int
|
|
compare(const rope& __y) const
|
|
{ return _S_compare(this->_M_tree_ptr, __y._M_tree_ptr); }
|
|
|
|
rope(const _CharT* __s, const allocator_type& __a = allocator_type())
|
|
: _Base(__a)
|
|
{
|
|
this->_M_tree_ptr =
|
|
__STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, _S_char_ptr_len(__s),
|
|
_M_get_allocator());
|
|
}
|
|
|
|
rope(const _CharT* __s, size_type __len,
|
|
const allocator_type& __a = allocator_type())
|
|
: _Base(__a)
|
|
{
|
|
this->_M_tree_ptr =
|
|
__STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __len, _M_get_allocator());
|
|
}
|
|
|
|
// Should perhaps be templatized with respect to the iterator type
|
|
// and use Sequence_buffer. (It should perhaps use sequence_buffer
|
|
// even now.)
|
|
rope(const _CharT* __s, const _CharT* __e,
|
|
const allocator_type& __a = allocator_type())
|
|
: _Base(__a)
|
|
{
|
|
this->_M_tree_ptr =
|
|
__STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __e - __s, _M_get_allocator());
|
|
}
|
|
|
|
rope(const const_iterator& __s, const const_iterator& __e,
|
|
const allocator_type& __a = allocator_type())
|
|
: _Base(_S_substring(__s._M_root, __s._M_current_pos,
|
|
__e._M_current_pos), __a)
|
|
{ }
|
|
|
|
rope(const iterator& __s, const iterator& __e,
|
|
const allocator_type& __a = allocator_type())
|
|
: _Base(_S_substring(__s._M_root, __s._M_current_pos,
|
|
__e._M_current_pos), __a)
|
|
{ }
|
|
|
|
rope(_CharT __c, const allocator_type& __a = allocator_type())
|
|
: _Base(__a)
|
|
{
|
|
_CharT* __buf = this->_Data_allocate(_S_rounded_up_size(1));
|
|
|
|
__alloc_traits<allocator_type>::construct(_M_get_allocator(),
|
|
__buf, __c);
|
|
__try
|
|
{
|
|
this->_M_tree_ptr = _S_new_RopeLeaf(__buf, 1,
|
|
_M_get_allocator());
|
|
}
|
|
__catch(...)
|
|
{
|
|
_RopeRep::__STL_FREE_STRING(__buf, 1, _M_get_allocator());
|
|
__throw_exception_again;
|
|
}
|
|
}
|
|
|
|
rope(size_type __n, _CharT __c,
|
|
const allocator_type& __a = allocator_type());
|
|
|
|
rope(const allocator_type& __a = allocator_type())
|
|
: _Base(0, __a) { }
|
|
|
|
// Construct a rope from a function that can compute its members
|
|
rope(char_producer<_CharT> *__fn, size_type __len, bool __delete_fn,
|
|
const allocator_type& __a = allocator_type())
|
|
: _Base(__a)
|
|
{
|
|
this->_M_tree_ptr = (0 == __len)
|
|
? 0
|
|
: _S_new_RopeFunction(__fn, __len, __delete_fn, _M_get_allocator());
|
|
}
|
|
|
|
rope(const rope& __x, const allocator_type& __a = allocator_type())
|
|
: _Base(__x._M_tree_ptr, __a)
|
|
{ _S_ref(this->_M_tree_ptr); }
|
|
|
|
~rope() throw()
|
|
{ _S_unref(this->_M_tree_ptr); }
|
|
|
|
rope&
|
|
operator=(const rope& __x)
|
|
{
|
|
_RopeRep* __old = this->_M_tree_ptr;
|
|
this->_M_tree_ptr = __x._M_tree_ptr;
|
|
_S_ref(this->_M_tree_ptr);
|
|
_S_unref(__old);
|
|
return *this;
|
|
}
|
|
|
|
void
|
|
clear()
|
|
{
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = 0;
|
|
}
|
|
|
|
void
|
|
push_back(_CharT __x)
|
|
{
|
|
allocator_type __a = _M_get_allocator();
|
|
_RopeRep* __old = this->_M_tree_ptr;
|
|
this->_M_tree_ptr
|
|
= _S_destr_concat_char_iter(this->_M_tree_ptr, &__x, 1, __a);
|
|
_S_unref(__old);
|
|
}
|
|
|
|
void
|
|
pop_back()
|
|
{
|
|
_RopeRep* __old = this->_M_tree_ptr;
|
|
this->_M_tree_ptr = _S_substring(this->_M_tree_ptr,
|
|
0, this->_M_tree_ptr->_M_size - 1);
|
|
_S_unref(__old);
|
|
}
|
|
|
|
_CharT
|
|
back() const
|
|
{ return _S_fetch(this->_M_tree_ptr, this->_M_tree_ptr->_M_size - 1); }
|
|
|
|
void
|
|
push_front(_CharT __x)
|
|
{
|
|
_RopeRep* __old = this->_M_tree_ptr;
|
|
_RopeRep* __left =
|
|
__STL_ROPE_FROM_UNOWNED_CHAR_PTR(&__x, 1, _M_get_allocator());
|
|
__try
|
|
{
|
|
this->_M_tree_ptr = _S_concat(__left, this->_M_tree_ptr);
|
|
_S_unref(__old);
|
|
_S_unref(__left);
|
|
}
|
|
__catch(...)
|
|
{
|
|
_S_unref(__left);
|
|
__throw_exception_again;
|
|
}
|
|
}
|
|
|
|
void
|
|
pop_front()
|
|
{
|
|
_RopeRep* __old = this->_M_tree_ptr;
|
|
this->_M_tree_ptr
|
|
= _S_substring(this->_M_tree_ptr, 1, this->_M_tree_ptr->_M_size);
|
|
_S_unref(__old);
|
|
}
|
|
|
|
_CharT
|
|
front() const
|
|
{ return _S_fetch(this->_M_tree_ptr, 0); }
|
|
|
|
void
|
|
balance()
|
|
{
|
|
_RopeRep* __old = this->_M_tree_ptr;
|
|
this->_M_tree_ptr = _S_balance(this->_M_tree_ptr);
|
|
_S_unref(__old);
|
|
}
|
|
|
|
void
|
|
copy(_CharT* __buffer) const
|
|
{
|
|
_Destroy_const(__buffer, __buffer + size(), _M_get_allocator());
|
|
_S_flatten(this->_M_tree_ptr, __buffer);
|
|
}
|
|
|
|
// This is the copy function from the standard, but
|
|
// with the arguments reordered to make it consistent with the
|
|
// rest of the interface.
|
|
// Note that this guaranteed not to compile if the draft standard
|
|
// order is assumed.
|
|
size_type
|
|
copy(size_type __pos, size_type __n, _CharT* __buffer) const
|
|
{
|
|
size_type __size = size();
|
|
size_type __len = (__pos + __n > __size? __size - __pos : __n);
|
|
|
|
_Destroy_const(__buffer, __buffer + __len, _M_get_allocator());
|
|
_S_flatten(this->_M_tree_ptr, __pos, __len, __buffer);
|
|
return __len;
|
|
}
|
|
|
|
// Print to stdout, exposing structure. May be useful for
|
|
// performance debugging.
|
|
void
|
|
dump()
|
|
{ _S_dump(this->_M_tree_ptr); }
|
|
|
|
// Convert to 0 terminated string in new allocated memory.
|
|
// Embedded 0s in the input do not terminate the copy.
|
|
const _CharT* c_str() const;
|
|
|
|
// As above, but also use the flattened representation as
|
|
// the new rope representation.
|
|
const _CharT* replace_with_c_str();
|
|
|
|
// Reclaim memory for the c_str generated flattened string.
|
|
// Intentionally undocumented, since it's hard to say when this
|
|
// is safe for multiple threads.
|
|
void
|
|
delete_c_str ()
|
|
{
|
|
if (0 == this->_M_tree_ptr)
|
|
return;
|
|
if (__detail::_S_leaf == this->_M_tree_ptr->_M_tag &&
|
|
((_RopeLeaf*)this->_M_tree_ptr)->_M_data ==
|
|
this->_M_tree_ptr->_M_c_string)
|
|
{
|
|
// Representation shared
|
|
return;
|
|
}
|
|
#ifndef __GC
|
|
this->_M_tree_ptr->_M_free_c_string();
|
|
#endif
|
|
this->_M_tree_ptr->_M_c_string = 0;
|
|
}
|
|
|
|
_CharT
|
|
operator[] (size_type __pos) const
|
|
{ return _S_fetch(this->_M_tree_ptr, __pos); }
|
|
|
|
_CharT
|
|
at(size_type __pos) const
|
|
{
|
|
// if (__pos >= size()) throw out_of_range; // XXX
|
|
return (*this)[__pos];
|
|
}
|
|
|
|
const_iterator
|
|
begin() const
|
|
{ return(const_iterator(this->_M_tree_ptr, 0)); }
|
|
|
|
// An easy way to get a const iterator from a non-const container.
|
|
const_iterator
|
|
const_begin() const
|
|
{ return(const_iterator(this->_M_tree_ptr, 0)); }
|
|
|
|
const_iterator
|
|
end() const
|
|
{ return(const_iterator(this->_M_tree_ptr, size())); }
|
|
|
|
const_iterator
|
|
const_end() const
|
|
{ return(const_iterator(this->_M_tree_ptr, size())); }
|
|
|
|
size_type
|
|
size() const
|
|
{ return(0 == this->_M_tree_ptr? 0 : this->_M_tree_ptr->_M_size); }
|
|
|
|
size_type
|
|
length() const
|
|
{ return size(); }
|
|
|
|
size_type
|
|
max_size() const
|
|
{
|
|
return _S_min_len[int(__detail::_S_max_rope_depth) - 1] - 1;
|
|
// Guarantees that the result can be sufficiently
|
|
// balanced. Longer ropes will probably still work,
|
|
// but it's harder to make guarantees.
|
|
}
|
|
|
|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
|
|
|
const_reverse_iterator
|
|
rbegin() const
|
|
{ return const_reverse_iterator(end()); }
|
|
|
|
const_reverse_iterator
|
|
const_rbegin() const
|
|
{ return const_reverse_iterator(end()); }
|
|
|
|
const_reverse_iterator
|
|
rend() const
|
|
{ return const_reverse_iterator(begin()); }
|
|
|
|
const_reverse_iterator
|
|
const_rend() const
|
|
{ return const_reverse_iterator(begin()); }
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend rope<_CharT2, _Alloc2>
|
|
operator+(const rope<_CharT2, _Alloc2>& __left,
|
|
const rope<_CharT2, _Alloc2>& __right);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend rope<_CharT2, _Alloc2>
|
|
operator+(const rope<_CharT2, _Alloc2>& __left, const _CharT2* __right);
|
|
|
|
template<class _CharT2, class _Alloc2>
|
|
friend rope<_CharT2, _Alloc2>
|
|
operator+(const rope<_CharT2, _Alloc2>& __left, _CharT2 __right);
|
|
|
|
// The symmetric cases are intentionally omitted, since they're
|
|
// presumed to be less common, and we don't handle them as well.
|
|
|
|
// The following should really be templatized. The first
|
|
// argument should be an input iterator or forward iterator with
|
|
// value_type _CharT.
|
|
rope&
|
|
append(const _CharT* __iter, size_type __n)
|
|
{
|
|
allocator_type __a = _M_get_allocator();
|
|
_RopeRep* __result =
|
|
_S_destr_concat_char_iter(this->_M_tree_ptr, __iter, __n, __a);
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = __result;
|
|
return *this;
|
|
}
|
|
|
|
rope&
|
|
append(const _CharT* __c_string)
|
|
{
|
|
size_type __len = _S_char_ptr_len(__c_string);
|
|
append(__c_string, __len);
|
|
return(*this);
|
|
}
|
|
|
|
rope&
|
|
append(const _CharT* __s, const _CharT* __e)
|
|
{
|
|
allocator_type __a = _M_get_allocator();
|
|
_RopeRep* __result =
|
|
_S_destr_concat_char_iter(this->_M_tree_ptr, __s, __e - __s, __a);
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = __result;
|
|
return *this;
|
|
}
|
|
|
|
rope&
|
|
append(const_iterator __s, const_iterator __e)
|
|
{
|
|
_Self_destruct_ptr __appendee(_S_substring(__s._M_root,
|
|
__s._M_current_pos,
|
|
__e._M_current_pos));
|
|
_RopeRep* __result = _S_concat(this->_M_tree_ptr,
|
|
(_RopeRep*)__appendee);
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = __result;
|
|
return *this;
|
|
}
|
|
|
|
rope&
|
|
append(_CharT __c)
|
|
{
|
|
allocator_type __a = _M_get_allocator();
|
|
_RopeRep* __result =
|
|
_S_destr_concat_char_iter(this->_M_tree_ptr, &__c, 1, __a);
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = __result;
|
|
return *this;
|
|
}
|
|
|
|
rope&
|
|
append()
|
|
{ return append(_CharT()); } // XXX why?
|
|
|
|
rope&
|
|
append(const rope& __y)
|
|
{
|
|
_RopeRep* __result = _S_concat(this->_M_tree_ptr, __y._M_tree_ptr);
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = __result;
|
|
return *this;
|
|
}
|
|
|
|
rope&
|
|
append(size_type __n, _CharT __c)
|
|
{
|
|
rope<_CharT,_Alloc> __last(__n, __c);
|
|
return append(__last);
|
|
}
|
|
|
|
void
|
|
swap(rope& __b)
|
|
{
|
|
_RopeRep* __tmp = this->_M_tree_ptr;
|
|
this->_M_tree_ptr = __b._M_tree_ptr;
|
|
__b._M_tree_ptr = __tmp;
|
|
}
|
|
|
|
protected:
|
|
// Result is included in refcount.
|
|
static _RopeRep*
|
|
replace(_RopeRep* __old, size_type __pos1,
|
|
size_type __pos2, _RopeRep* __r)
|
|
{
|
|
if (0 == __old)
|
|
{
|
|
_S_ref(__r);
|
|
return __r;
|
|
}
|
|
_Self_destruct_ptr __left(_S_substring(__old, 0, __pos1));
|
|
_Self_destruct_ptr __right(_S_substring(__old, __pos2, __old->_M_size));
|
|
_RopeRep* __result;
|
|
|
|
if (0 == __r)
|
|
__result = _S_concat(__left, __right);
|
|
else
|
|
{
|
|
_Self_destruct_ptr __left_result(_S_concat(__left, __r));
|
|
__result = _S_concat(__left_result, __right);
|
|
}
|
|
return __result;
|
|
}
|
|
|
|
public:
|
|
void
|
|
insert(size_type __p, const rope& __r)
|
|
{
|
|
_RopeRep* __result =
|
|
replace(this->_M_tree_ptr, __p, __p, __r._M_tree_ptr);
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = __result;
|
|
}
|
|
|
|
void
|
|
insert(size_type __p, size_type __n, _CharT __c)
|
|
{
|
|
rope<_CharT,_Alloc> __r(__n,__c);
|
|
insert(__p, __r);
|
|
}
|
|
|
|
void
|
|
insert(size_type __p, const _CharT* __i, size_type __n)
|
|
{
|
|
_Self_destruct_ptr __left(_S_substring(this->_M_tree_ptr, 0, __p));
|
|
_Self_destruct_ptr __right(_S_substring(this->_M_tree_ptr,
|
|
__p, size()));
|
|
_Self_destruct_ptr __left_result(_S_concat_char_iter(__left, __i, __n,
|
|
_M_get_allocator()));
|
|
// _S_ destr_concat_char_iter should be safe here.
|
|
// But as it stands it's probably not a win, since __left
|
|
// is likely to have additional references.
|
|
_RopeRep* __result = _S_concat(__left_result, __right);
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = __result;
|
|
}
|
|
|
|
void
|
|
insert(size_type __p, const _CharT* __c_string)
|
|
{ insert(__p, __c_string, _S_char_ptr_len(__c_string)); }
|
|
|
|
void
|
|
insert(size_type __p, _CharT __c)
|
|
{ insert(__p, &__c, 1); }
|
|
|
|
void
|
|
insert(size_type __p)
|
|
{
|
|
_CharT __c = _CharT();
|
|
insert(__p, &__c, 1);
|
|
}
|
|
|
|
void
|
|
insert(size_type __p, const _CharT* __i, const _CharT* __j)
|
|
{
|
|
rope __r(__i, __j);
|
|
insert(__p, __r);
|
|
}
|
|
|
|
void
|
|
insert(size_type __p, const const_iterator& __i,
|
|
const const_iterator& __j)
|
|
{
|
|
rope __r(__i, __j);
|
|
insert(__p, __r);
|
|
}
|
|
|
|
void
|
|
insert(size_type __p, const iterator& __i,
|
|
const iterator& __j)
|
|
{
|
|
rope __r(__i, __j);
|
|
insert(__p, __r);
|
|
}
|
|
|
|
// (position, length) versions of replace operations:
|
|
|
|
void
|
|
replace(size_type __p, size_type __n, const rope& __r)
|
|
{
|
|
_RopeRep* __result =
|
|
replace(this->_M_tree_ptr, __p, __p + __n, __r._M_tree_ptr);
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = __result;
|
|
}
|
|
|
|
void
|
|
replace(size_type __p, size_type __n,
|
|
const _CharT* __i, size_type __i_len)
|
|
{
|
|
rope __r(__i, __i_len);
|
|
replace(__p, __n, __r);
|
|
}
|
|
|
|
void
|
|
replace(size_type __p, size_type __n, _CharT __c)
|
|
{
|
|
rope __r(__c);
|
|
replace(__p, __n, __r);
|
|
}
|
|
|
|
void
|
|
replace(size_type __p, size_type __n, const _CharT* __c_string)
|
|
{
|
|
rope __r(__c_string);
|
|
replace(__p, __n, __r);
|
|
}
|
|
|
|
void
|
|
replace(size_type __p, size_type __n,
|
|
const _CharT* __i, const _CharT* __j)
|
|
{
|
|
rope __r(__i, __j);
|
|
replace(__p, __n, __r);
|
|
}
|
|
|
|
void
|
|
replace(size_type __p, size_type __n,
|
|
const const_iterator& __i, const const_iterator& __j)
|
|
{
|
|
rope __r(__i, __j);
|
|
replace(__p, __n, __r);
|
|
}
|
|
|
|
void
|
|
replace(size_type __p, size_type __n,
|
|
const iterator& __i, const iterator& __j)
|
|
{
|
|
rope __r(__i, __j);
|
|
replace(__p, __n, __r);
|
|
}
|
|
|
|
// Single character variants:
|
|
void
|
|
replace(size_type __p, _CharT __c)
|
|
{
|
|
iterator __i(this, __p);
|
|
*__i = __c;
|
|
}
|
|
|
|
void
|
|
replace(size_type __p, const rope& __r)
|
|
{ replace(__p, 1, __r); }
|
|
|
|
void
|
|
replace(size_type __p, const _CharT* __i, size_type __i_len)
|
|
{ replace(__p, 1, __i, __i_len); }
|
|
|
|
void
|
|
replace(size_type __p, const _CharT* __c_string)
|
|
{ replace(__p, 1, __c_string); }
|
|
|
|
void
|
|
replace(size_type __p, const _CharT* __i, const _CharT* __j)
|
|
{ replace(__p, 1, __i, __j); }
|
|
|
|
void
|
|
replace(size_type __p, const const_iterator& __i,
|
|
const const_iterator& __j)
|
|
{ replace(__p, 1, __i, __j); }
|
|
|
|
void
|
|
replace(size_type __p, const iterator& __i,
|
|
const iterator& __j)
|
|
{ replace(__p, 1, __i, __j); }
|
|
|
|
// Erase, (position, size) variant.
|
|
void
|
|
erase(size_type __p, size_type __n)
|
|
{
|
|
_RopeRep* __result = replace(this->_M_tree_ptr, __p,
|
|
__p + __n, 0);
|
|
_S_unref(this->_M_tree_ptr);
|
|
this->_M_tree_ptr = __result;
|
|
}
|
|
|
|
// Insert, iterator variants.
|
|
iterator
|
|
insert(const iterator& __p, const rope& __r)
|
|
{
|
|
insert(__p.index(), __r);
|
|
return __p;
|
|
}
|
|
|
|
iterator
|
|
insert(const iterator& __p, size_type __n, _CharT __c)
|
|
{
|
|
insert(__p.index(), __n, __c);
|
|
return __p;
|
|
}
|
|
|
|
iterator insert(const iterator& __p, _CharT __c)
|
|
{
|
|
insert(__p.index(), __c);
|
|
return __p;
|
|
}
|
|
|
|
iterator
|
|
insert(const iterator& __p )
|
|
{
|
|
insert(__p.index());
|
|
return __p;
|
|
}
|
|
|
|
iterator
|
|
insert(const iterator& __p, const _CharT* c_string)
|
|
{
|
|
insert(__p.index(), c_string);
|
|
return __p;
|
|
}
|
|
|
|
iterator
|
|
insert(const iterator& __p, const _CharT* __i, size_type __n)
|
|
{
|
|
insert(__p.index(), __i, __n);
|
|
return __p;
|
|
}
|
|
|
|
iterator
|
|
insert(const iterator& __p, const _CharT* __i,
|
|
const _CharT* __j)
|
|
{
|
|
insert(__p.index(), __i, __j);
|
|
return __p;
|
|
}
|
|
|
|
iterator
|
|
insert(const iterator& __p,
|
|
const const_iterator& __i, const const_iterator& __j)
|
|
{
|
|
insert(__p.index(), __i, __j);
|
|
return __p;
|
|
}
|
|
|
|
iterator
|
|
insert(const iterator& __p,
|
|
const iterator& __i, const iterator& __j)
|
|
{
|
|
insert(__p.index(), __i, __j);
|
|
return __p;
|
|
}
|
|
|
|
// Replace, range variants.
|
|
void
|
|
replace(const iterator& __p, const iterator& __q, const rope& __r)
|
|
{ replace(__p.index(), __q.index() - __p.index(), __r); }
|
|
|
|
void
|
|
replace(const iterator& __p, const iterator& __q, _CharT __c)
|
|
{ replace(__p.index(), __q.index() - __p.index(), __c); }
|
|
|
|
void
|
|
replace(const iterator& __p, const iterator& __q,
|
|
const _CharT* __c_string)
|
|
{ replace(__p.index(), __q.index() - __p.index(), __c_string); }
|
|
|
|
void
|
|
replace(const iterator& __p, const iterator& __q,
|
|
const _CharT* __i, size_type __n)
|
|
{ replace(__p.index(), __q.index() - __p.index(), __i, __n); }
|
|
|
|
void
|
|
replace(const iterator& __p, const iterator& __q,
|
|
const _CharT* __i, const _CharT* __j)
|
|
{ replace(__p.index(), __q.index() - __p.index(), __i, __j); }
|
|
|
|
void
|
|
replace(const iterator& __p, const iterator& __q,
|
|
const const_iterator& __i, const const_iterator& __j)
|
|
{ replace(__p.index(), __q.index() - __p.index(), __i, __j); }
|
|
|
|
void
|
|
replace(const iterator& __p, const iterator& __q,
|
|
const iterator& __i, const iterator& __j)
|
|
{ replace(__p.index(), __q.index() - __p.index(), __i, __j); }
|
|
|
|
// Replace, iterator variants.
|
|
void
|
|
replace(const iterator& __p, const rope& __r)
|
|
{ replace(__p.index(), __r); }
|
|
|
|
void
|
|
replace(const iterator& __p, _CharT __c)
|
|
{ replace(__p.index(), __c); }
|
|
|
|
void
|
|
replace(const iterator& __p, const _CharT* __c_string)
|
|
{ replace(__p.index(), __c_string); }
|
|
|
|
void
|
|
replace(const iterator& __p, const _CharT* __i, size_type __n)
|
|
{ replace(__p.index(), __i, __n); }
|
|
|
|
void
|
|
replace(const iterator& __p, const _CharT* __i, const _CharT* __j)
|
|
{ replace(__p.index(), __i, __j); }
|
|
|
|
void
|
|
replace(const iterator& __p, const_iterator __i, const_iterator __j)
|
|
{ replace(__p.index(), __i, __j); }
|
|
|
|
void
|
|
replace(const iterator& __p, iterator __i, iterator __j)
|
|
{ replace(__p.index(), __i, __j); }
|
|
|
|
// Iterator and range variants of erase
|
|
iterator
|
|
erase(const iterator& __p, const iterator& __q)
|
|
{
|
|
size_type __p_index = __p.index();
|
|
erase(__p_index, __q.index() - __p_index);
|
|
return iterator(this, __p_index);
|
|
}
|
|
|
|
iterator
|
|
erase(const iterator& __p)
|
|
{
|
|
size_type __p_index = __p.index();
|
|
erase(__p_index, 1);
|
|
return iterator(this, __p_index);
|
|
}
|
|
|
|
rope
|
|
substr(size_type __start, size_type __len = 1) const
|
|
{
|
|
return rope<_CharT, _Alloc>(_S_substring(this->_M_tree_ptr,
|
|
__start,
|
|
__start + __len));
|
|
}
|
|
|
|
rope
|
|
substr(iterator __start, iterator __end) const
|
|
{
|
|
return rope<_CharT, _Alloc>(_S_substring(this->_M_tree_ptr,
|
|
__start.index(),
|
|
__end.index()));
|
|
}
|
|
|
|
rope
|
|
substr(iterator __start) const
|
|
{
|
|
size_type __pos = __start.index();
|
|
return rope<_CharT, _Alloc>(_S_substring(this->_M_tree_ptr,
|
|
__pos, __pos + 1));
|
|
}
|
|
|
|
rope
|
|
substr(const_iterator __start, const_iterator __end) const
|
|
{
|
|
// This might eventually take advantage of the cache in the
|
|
// iterator.
|
|
return rope<_CharT, _Alloc>(_S_substring(this->_M_tree_ptr,
|
|
__start.index(),
|
|
__end.index()));
|
|
}
|
|
|
|
rope<_CharT, _Alloc>
|
|
substr(const_iterator __start)
|
|
{
|
|
size_type __pos = __start.index();
|
|
return rope<_CharT, _Alloc>(_S_substring(this->_M_tree_ptr,
|
|
__pos, __pos + 1));
|
|
}
|
|
|
|
static const size_type npos;
|
|
|
|
size_type find(_CharT __c, size_type __pos = 0) const;
|
|
|
|
size_type
|
|
find(const _CharT* __s, size_type __pos = 0) const
|
|
{
|
|
size_type __result_pos;
|
|
const_iterator __result =
|
|
std::search(const_begin() + __pos, const_end(),
|
|
__s, __s + _S_char_ptr_len(__s));
|
|
__result_pos = __result.index();
|
|
#ifndef __STL_OLD_ROPE_SEMANTICS
|
|
if (__result_pos == size())
|
|
__result_pos = npos;
|
|
#endif
|
|
return __result_pos;
|
|
}
|
|
|
|
iterator
|
|
mutable_begin()
|
|
{ return(iterator(this, 0)); }
|
|
|
|
iterator
|
|
mutable_end()
|
|
{ return(iterator(this, size())); }
|
|
|
|
typedef std::reverse_iterator<iterator> reverse_iterator;
|
|
|
|
reverse_iterator
|
|
mutable_rbegin()
|
|
{ return reverse_iterator(mutable_end()); }
|
|
|
|
reverse_iterator
|
|
mutable_rend()
|
|
{ return reverse_iterator(mutable_begin()); }
|
|
|
|
reference
|
|
mutable_reference_at(size_type __pos)
|
|
{ return reference(this, __pos); }
|
|
|
|
#ifdef __STD_STUFF
|
|
reference
|
|
operator[] (size_type __pos)
|
|
{ return _char_ref_proxy(this, __pos); }
|
|
|
|
reference
|
|
at(size_type __pos)
|
|
{
|
|
// if (__pos >= size()) throw out_of_range; // XXX
|
|
return (*this)[__pos];
|
|
}
|
|
|
|
void resize(size_type __n, _CharT __c) { }
|
|
void resize(size_type __n) { }
|
|
void reserve(size_type __res_arg = 0) { }
|
|
|
|
size_type
|
|
capacity() const
|
|
{ return max_size(); }
|
|
|
|
// Stuff below this line is dangerous because it's error prone.
|
|
// I would really like to get rid of it.
|
|
// copy function with funny arg ordering.
|
|
size_type
|
|
copy(_CharT* __buffer, size_type __n,
|
|
size_type __pos = 0) const
|
|
{ return copy(__pos, __n, __buffer); }
|
|
|
|
iterator
|
|
end()
|
|
{ return mutable_end(); }
|
|
|
|
iterator
|
|
begin()
|
|
{ return mutable_begin(); }
|
|
|
|
reverse_iterator
|
|
rend()
|
|
{ return mutable_rend(); }
|
|
|
|
reverse_iterator
|
|
rbegin()
|
|
{ return mutable_rbegin(); }
|
|
|
|
#else
|
|
const_iterator
|
|
end()
|
|
{ return const_end(); }
|
|
|
|
const_iterator
|
|
begin()
|
|
{ return const_begin(); }
|
|
|
|
const_reverse_iterator
|
|
rend()
|
|
{ return const_rend(); }
|
|
|
|
const_reverse_iterator
|
|
rbegin()
|
|
{ return const_rbegin(); }
|
|
|
|
#endif
|
|
};
|
|
|
|
template <class _CharT, class _Alloc>
|
|
const typename rope<_CharT, _Alloc>::size_type
|
|
rope<_CharT, _Alloc>::npos = (size_type)(-1);
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool operator==(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __y)
|
|
{ return (__x._M_current_pos == __y._M_current_pos
|
|
&& __x._M_root == __y._M_root); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool operator<(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __y)
|
|
{ return (__x._M_current_pos < __y._M_current_pos); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool operator!=(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __y)
|
|
{ return !(__x == __y); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool operator>(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __y)
|
|
{ return __y < __x; }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator<=(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __y)
|
|
{ return !(__y < __x); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator>=(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __y)
|
|
{ return !(__x < __y); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline std::ptrdiff_t
|
|
operator-(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __y)
|
|
{
|
|
return (std::ptrdiff_t)__x._M_current_pos
|
|
- (std::ptrdiff_t)__y._M_current_pos;
|
|
}
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline _Rope_const_iterator<_CharT, _Alloc>
|
|
operator-(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
std::ptrdiff_t __n)
|
|
{ return _Rope_const_iterator<_CharT, _Alloc>(__x._M_root,
|
|
__x._M_current_pos - __n); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline _Rope_const_iterator<_CharT, _Alloc>
|
|
operator+(const _Rope_const_iterator<_CharT, _Alloc>& __x,
|
|
std::ptrdiff_t __n)
|
|
{ return _Rope_const_iterator<_CharT, _Alloc>(__x._M_root,
|
|
__x._M_current_pos + __n); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline _Rope_const_iterator<_CharT, _Alloc>
|
|
operator+(std::ptrdiff_t __n,
|
|
const _Rope_const_iterator<_CharT, _Alloc>& __x)
|
|
{ return _Rope_const_iterator<_CharT, _Alloc>(__x._M_root,
|
|
__x._M_current_pos + __n); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator==(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_iterator<_CharT, _Alloc>& __y)
|
|
{return (__x._M_current_pos == __y._M_current_pos
|
|
&& __x._M_root_rope == __y._M_root_rope); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator<(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_iterator<_CharT, _Alloc>& __y)
|
|
{ return (__x._M_current_pos < __y._M_current_pos); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator!=(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_iterator<_CharT, _Alloc>& __y)
|
|
{ return !(__x == __y); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator>(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_iterator<_CharT, _Alloc>& __y)
|
|
{ return __y < __x; }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator<=(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_iterator<_CharT, _Alloc>& __y)
|
|
{ return !(__y < __x); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator>=(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_iterator<_CharT, _Alloc>& __y)
|
|
{ return !(__x < __y); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline std::ptrdiff_t
|
|
operator-(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
const _Rope_iterator<_CharT, _Alloc>& __y)
|
|
{ return ((std::ptrdiff_t)__x._M_current_pos
|
|
- (std::ptrdiff_t)__y._M_current_pos); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline _Rope_iterator<_CharT, _Alloc>
|
|
operator-(const _Rope_iterator<_CharT, _Alloc>& __x,
|
|
std::ptrdiff_t __n)
|
|
{ return _Rope_iterator<_CharT, _Alloc>(__x._M_root_rope,
|
|
__x._M_current_pos - __n); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline _Rope_iterator<_CharT, _Alloc>
|
|
operator+(const _Rope_iterator<_CharT, _Alloc>& __x, std::ptrdiff_t __n)
|
|
{ return _Rope_iterator<_CharT, _Alloc>(__x._M_root_rope,
|
|
__x._M_current_pos + __n); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline _Rope_iterator<_CharT, _Alloc>
|
|
operator+(std::ptrdiff_t __n, const _Rope_iterator<_CharT, _Alloc>& __x)
|
|
{ return _Rope_iterator<_CharT, _Alloc>(__x._M_root_rope,
|
|
__x._M_current_pos + __n); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline rope<_CharT, _Alloc>
|
|
operator+(const rope<_CharT, _Alloc>& __left,
|
|
const rope<_CharT, _Alloc>& __right)
|
|
{
|
|
// Inlining this should make it possible to keep __left and
|
|
// __right in registers.
|
|
typedef rope<_CharT, _Alloc> rope_type;
|
|
return rope_type(rope_type::_S_concat(__left._M_tree_ptr,
|
|
__right._M_tree_ptr));
|
|
}
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline rope<_CharT, _Alloc>&
|
|
operator+=(rope<_CharT, _Alloc>& __left,
|
|
const rope<_CharT, _Alloc>& __right)
|
|
{
|
|
__left.append(__right);
|
|
return __left;
|
|
}
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline rope<_CharT, _Alloc>
|
|
operator+(const rope<_CharT, _Alloc>& __left,
|
|
const _CharT* __right)
|
|
{
|
|
typedef rope<_CharT, _Alloc> rope_type;
|
|
std::size_t __rlen = rope_type::_S_char_ptr_len(__right);
|
|
_Alloc __a = __left.get_allocator();
|
|
return rope_type(rope_type::_S_concat_char_iter(__left._M_tree_ptr,
|
|
__right, __rlen, __a));
|
|
}
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline rope<_CharT, _Alloc>&
|
|
operator+=(rope<_CharT, _Alloc>& __left,
|
|
const _CharT* __right)
|
|
{
|
|
__left.append(__right);
|
|
return __left;
|
|
}
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline rope<_CharT, _Alloc>
|
|
operator+(const rope<_CharT, _Alloc>& __left, _CharT __right)
|
|
{
|
|
typedef rope<_CharT, _Alloc> rope_type;
|
|
_Alloc __a = __left.get_allocator();
|
|
return rope_type(rope_type::_S_concat_char_iter(__left._M_tree_ptr,
|
|
&__right, 1, __a));
|
|
}
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline rope<_CharT, _Alloc>&
|
|
operator+=(rope<_CharT, _Alloc>& __left, _CharT __right)
|
|
{
|
|
__left.append(__right);
|
|
return __left;
|
|
}
|
|
|
|
template <class _CharT, class _Alloc>
|
|
bool
|
|
operator<(const rope<_CharT, _Alloc>& __left,
|
|
const rope<_CharT, _Alloc>& __right)
|
|
{ return __left.compare(__right) < 0; }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
bool
|
|
operator==(const rope<_CharT, _Alloc>& __left,
|
|
const rope<_CharT, _Alloc>& __right)
|
|
{ return __left.compare(__right) == 0; }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator==(const _Rope_char_ptr_proxy<_CharT, _Alloc>& __x,
|
|
const _Rope_char_ptr_proxy<_CharT, _Alloc>& __y)
|
|
{ return (__x._M_pos == __y._M_pos && __x._M_root == __y._M_root); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator!=(const rope<_CharT, _Alloc>& __x,
|
|
const rope<_CharT, _Alloc>& __y)
|
|
{ return !(__x == __y); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator>(const rope<_CharT, _Alloc>& __x,
|
|
const rope<_CharT, _Alloc>& __y)
|
|
{ return __y < __x; }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator<=(const rope<_CharT, _Alloc>& __x,
|
|
const rope<_CharT, _Alloc>& __y)
|
|
{ return !(__y < __x); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator>=(const rope<_CharT, _Alloc>& __x,
|
|
const rope<_CharT, _Alloc>& __y)
|
|
{ return !(__x < __y); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline bool
|
|
operator!=(const _Rope_char_ptr_proxy<_CharT, _Alloc>& __x,
|
|
const _Rope_char_ptr_proxy<_CharT, _Alloc>& __y)
|
|
{ return !(__x == __y); }
|
|
|
|
template<class _CharT, class _Traits, class _Alloc>
|
|
std::basic_ostream<_CharT, _Traits>&
|
|
operator<<(std::basic_ostream<_CharT, _Traits>& __o,
|
|
const rope<_CharT, _Alloc>& __r);
|
|
|
|
typedef rope<char> crope;
|
|
typedef rope<wchar_t> wrope;
|
|
|
|
inline crope::reference
|
|
__mutable_reference_at(crope& __c, std::size_t __i)
|
|
{ return __c.mutable_reference_at(__i); }
|
|
|
|
inline wrope::reference
|
|
__mutable_reference_at(wrope& __c, std::size_t __i)
|
|
{ return __c.mutable_reference_at(__i); }
|
|
|
|
template <class _CharT, class _Alloc>
|
|
inline void
|
|
swap(rope<_CharT, _Alloc>& __x, rope<_CharT, _Alloc>& __y)
|
|
{ __x.swap(__y); }
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace
|
|
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
namespace tr1
|
|
{
|
|
template<>
|
|
struct hash<__gnu_cxx::crope>
|
|
{
|
|
size_t
|
|
operator()(const __gnu_cxx::crope& __str) const
|
|
{
|
|
size_t __size = __str.size();
|
|
if (0 == __size)
|
|
return 0;
|
|
return 13 * __str[0] + 5 * __str[__size - 1] + __size;
|
|
}
|
|
};
|
|
|
|
|
|
template<>
|
|
struct hash<__gnu_cxx::wrope>
|
|
{
|
|
size_t
|
|
operator()(const __gnu_cxx::wrope& __str) const
|
|
{
|
|
size_t __size = __str.size();
|
|
if (0 == __size)
|
|
return 0;
|
|
return 13 * __str[0] + 5 * __str[__size - 1] + __size;
|
|
}
|
|
};
|
|
} // namespace tr1
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace std
|
|
|
|
# include <ext/ropeimpl.h>
|
|
|
|
#endif
|