epoc32/include/stdapis/stlport/stl/_rope.c
author William Roberts <williamr@symbian.org>
Wed, 31 Mar 2010 12:33:34 +0100
branchSymbian3
changeset 4 837f303aceeb
permissions -rw-r--r--
Current Symbian^3 public API header files (from PDK 3.0.h)
This is the epoc32/include tree with the "platform" subtrees removed, and
all but a selected few mbg and rsg files removed.
     1 /*
     2  * © Portions copyright (c) 2006-2007 Nokia Corporation.  All rights reserved.
     3  * Copyright (c) 1996,1997
     4  * Silicon Graphics Computer Systems, Inc.
     5  *
     6  * Copyright (c) 1999 
     7  * Boris Fomitchev
     8  *
     9  * This material is provided "as is", with absolutely no warranty expressed
    10  * or implied. Any use is at your own risk.
    11  *
    12  * Permission to use or copy this software for any purpose is hereby granted 
    13  * without fee, provided the above notices are retained on all copies.
    14  * Permission to modify the code and to distribute modified code is granted,
    15  * provided the above notices are retained, and a notice that the code was
    16  * modified is included with the above copyright notice.
    17  *
    18  */
    19 
    20 /* NOTE: This is an internal header file, included by other STL headers.
    21  *   You should not attempt to use it directly.
    22  */
    23 
    24 // Set buf_start, buf_end, and buf_ptr appropriately, filling tmp_buf
    25 // if necessary.  Assumes path_end[leaf_index] and leaf_pos are correct.
    26 // Results in a valid buf_ptr if the iterator can be legitimately
    27 // dereferenced.
    28 # ifndef _STLP_ROPEIMPL_H
    29 # define _STLP_ROPEIMPL_H
    30 
    31 #ifndef _STLP_INTERNAL_ROPE_H
    32 # include <stl/_rope.h>
    33 #endif
    34 
    35 # ifndef _STLP_CSTDIO
    36 #  include <cstdio>
    37 # endif
    38 
    39 #ifndef _STLP_IOSTREAM
    40 # include <iostream>
    41 #endif
    42 
    43 # include <stl/_range_errors.h>
    44 
    45 _STLP_BEGIN_NAMESPACE
    46 
    47 # if defined ( _STLP_NESTED_TYPE_PARAM_BUG )
    48 # define __allocator__ _Alloc
    49 # else
    50 # define __allocator__ allocator_type
    51 # endif
    52 
    53 template<class _CharT, class _Alloc>
    54 _Rope_iterator<_CharT, _Alloc>::_Rope_iterator(rope<_CharT,_Alloc>* __r, size_t __pos)
    55   : _Rope_iterator_base<_CharT,_Alloc>(__r->_M_tree_ptr._M_data, __pos),
    56   _M_root_rope(__r) { _RopeRep::_S_ref(this->_M_root); }
    57 
    58 template<class _CharT, class _Alloc>
    59 _Rope_iterator<_CharT, _Alloc>::_Rope_iterator(rope<_CharT,_Alloc>& __r, size_t __pos): 
    60   _Rope_iterator_base<_CharT,_Alloc>(__r._M_tree_ptr._M_data, __pos), 
    61   _M_root_rope(&__r) {
    62   _RopeRep::_S_ref(this->_M_root); if (!(__r.empty()))_S_setcache(*this);
    63 }
    64 
    65 template<class _CharT, class _Alloc>
    66 void 
    67 _Rope_RopeRep<_CharT, _Alloc>::_M_free_c_string()
    68 {
    69   _CharT* __cstr = _M_c_string;
    70   if (0 != __cstr) {
    71     size_t _p_size = _M_size._M_data + 1;
    72     _STLP_STD::_Destroy(__cstr, __cstr + _p_size);
    73     _M_size.deallocate(__cstr, _p_size);
    74   }
    75 }
    76 
    77 
    78 // Set buf_start, buf_end, and buf_ptr appropriately, filling tmp_buf
    79 // if necessary.  Assumes _M_path_end[leaf_index] and leaf_pos are correct.
    80 // Results in a valid buf_ptr if the iterator can be legitimately
    81 // dereferenced.
    82 template <class _CharT, class _Alloc>
    83 void _Rope_iterator_base<_CharT,_Alloc>::_S_setbuf( 
    84   _Rope_iterator_base<_CharT,_Alloc>& __x)
    85 {
    86     const _RopeRep* __leaf = __x._M_path_end[__x._M_leaf_index];
    87     size_t __leaf_pos = __x._M_leaf_pos;
    88     size_t __pos = __x._M_current_pos;
    89 
    90     switch(__leaf->_M_tag) {
    91 	case _RopeRep::_S_leaf:
    92 	    __x._M_buf_start = 
    93 	      ((_Rope_RopeLeaf<_CharT,_Alloc>*)__leaf)->_M_data;
    94 	    __x._M_buf_ptr = __x._M_buf_start + (__pos - __leaf_pos);
    95 	    __x._M_buf_end = __x._M_buf_start + __leaf->_M_size._M_data;
    96 	    break;
    97 	case _RopeRep::_S_function:
    98 	case _RopeRep::_S_substringfn:
    99 	    {
   100 		size_t __len = _S_iterator_buf_len;
   101 		size_t __buf_start_pos = __leaf_pos;
   102 		size_t __leaf_end = __leaf_pos + __leaf->_M_size._M_data;
   103 		char_producer<_CharT>* __fn =
   104 			((_Rope_RopeFunction<_CharT,_Alloc>*)__leaf)->_M_fn;
   105 
   106 		if (__buf_start_pos + __len <= __pos) {
   107 		    __buf_start_pos = __pos - __len/4;
   108 		    if (__buf_start_pos + __len > __leaf_end) {
   109 			__buf_start_pos = __leaf_end - __len;
   110 		    }
   111 		}
   112 		if (__buf_start_pos + __len > __leaf_end) {
   113 		    __len = __leaf_end - __buf_start_pos;
   114 		}
   115 		(*__fn)(__buf_start_pos - __leaf_pos, __len, __x._M_tmp_buf);
   116 		__x._M_buf_ptr = __x._M_tmp_buf + (__pos - __buf_start_pos);
   117 		__x._M_buf_start = __x._M_tmp_buf;
   118 		__x._M_buf_end = __x._M_tmp_buf + __len;
   119 	    }
   120 	    break;
   121 	default:
   122       _STLP_ASSERT(0)
   123         ;
   124     }
   125 }
   126 
   127 // Set path and buffer inside a rope iterator.  We assume that 
   128 // pos and root are already set.
   129 template <class _CharT, class _Alloc>
   130 void _Rope_iterator_base<_CharT,_Alloc>::_S_setcache
   131 (_Rope_iterator_base<_CharT,_Alloc>& __x)
   132 {
   133     const _RopeRep* __path[_RopeRep::_S_max_rope_depth+1];
   134     const _RopeRep* __curr_rope;
   135     int __curr_depth = -1;  /* index into path    */
   136     size_t __curr_start_pos = 0;
   137     size_t __pos = __x._M_current_pos;
   138     unsigned char __dirns = 0; // Bit vector marking right turns in the path
   139 
   140     _STLP_ASSERT(__pos <= __x._M_root->_M_size._M_data)
   141     if (__pos >= __x._M_root->_M_size._M_data) {
   142 	__x._M_buf_ptr = 0;
   143 	return;
   144     }
   145     __curr_rope = __x._M_root;
   146     if (0 != __curr_rope->_M_c_string) {
   147 	/* Treat the root as a leaf. */
   148 	__x._M_buf_start = __curr_rope->_M_c_string;
   149 	__x._M_buf_end = __curr_rope->_M_c_string + __curr_rope->_M_size._M_data;
   150 	__x._M_buf_ptr = __curr_rope->_M_c_string + __pos;
   151 	__x._M_path_end[0] = __curr_rope;
   152 	__x._M_leaf_index = 0;
   153 	__x._M_leaf_pos = 0;
   154 	return;
   155     }
   156     for(;;) {
   157 	++__curr_depth;
   158 	_STLP_ASSERT(__curr_depth <= _RopeRep::_S_max_rope_depth)
   159 	__path[__curr_depth] = __curr_rope;
   160 	switch(__curr_rope->_M_tag) {
   161 	  case _RopeRep::_S_leaf:
   162 	  case _RopeRep::_S_function:
   163 	  case _RopeRep::_S_substringfn:
   164 	    __x._M_leaf_pos = __curr_start_pos;
   165 	    goto done;
   166 	  case _RopeRep::_S_concat:
   167 	    {
   168 		_Rope_RopeConcatenation<_CharT,_Alloc>* __c =
   169 			(_Rope_RopeConcatenation<_CharT,_Alloc>*)__curr_rope;
   170 		_RopeRep* __left = __c->_M_left;
   171 		size_t __left_len = __left->_M_size._M_data;
   172 		
   173 		__dirns <<= 1;
   174 		if (__pos >= __curr_start_pos + __left_len) {
   175 		    __dirns |= 1;
   176 		    __curr_rope = __c->_M_right;
   177 		    __curr_start_pos += __left_len;
   178 		} else {
   179 		    __curr_rope = __left;
   180 		}
   181 	    }
   182 	    break;
   183 	}
   184     }
   185   done:
   186     // Copy last section of path into _M_path_end.
   187       {
   188 	int __i = -1;
   189 	int __j = __curr_depth + 1 - _S_path_cache_len;
   190 
   191 	if (__j < 0) __j = 0;
   192 	while (__j <= __curr_depth) {
   193 	    __x._M_path_end[++__i] = __path[__j++];
   194 	}
   195 	__x._M_leaf_index = __i;
   196       }
   197       __x._M_path_directions = __dirns;
   198       _S_setbuf(__x);
   199 }
   200 
   201 // Specialized version of the above.  Assumes that
   202 // the path cache is valid for the previous position.
   203 template <class _CharT, class _Alloc>
   204 void _Rope_iterator_base<_CharT,_Alloc>::_S_setcache_for_incr
   205 (_Rope_iterator_base<_CharT,_Alloc>& __x)
   206 {
   207     int __current_index = __x._M_leaf_index;
   208     const _RopeRep* __current_node = __x._M_path_end[__current_index];
   209     size_t __len = __current_node->_M_size._M_data;
   210     size_t __node_start_pos = __x._M_leaf_pos;
   211     unsigned char __dirns = __x._M_path_directions;
   212     _Rope_RopeConcatenation<_CharT,_Alloc>* __c;
   213 
   214     _STLP_ASSERT(__x._M_current_pos <= __x._M_root->_M_size._M_data)
   215     if (__x._M_current_pos - __node_start_pos < __len) {
   216 	/* More stuff in this leaf, we just didn't cache it. */
   217 	_S_setbuf(__x);
   218 	return;
   219     }
   220     _STLP_ASSERT(__node_start_pos + __len == __x._M_current_pos)
   221     //  node_start_pos is starting position of last_node.
   222     while (--__current_index >= 0) {
   223 	if (!(__dirns & 1) /* Path turned left */) 
   224 	  break;
   225 	__current_node = __x._M_path_end[__current_index];
   226 	__c = (_Rope_RopeConcatenation<_CharT,_Alloc>*)__current_node;
   227 	// Otherwise we were in the right child.  Thus we should pop
   228 	// the concatenation node.
   229 	__node_start_pos -= __c->_M_left->_M_size._M_data;
   230 	__dirns >>= 1;
   231     }
   232     if (__current_index < 0) {
   233 	// We underflowed the cache. Punt.
   234 	_S_setcache(__x);
   235 	return;
   236     }
   237     __current_node = __x._M_path_end[__current_index];
   238     __c = (_Rope_RopeConcatenation<_CharT,_Alloc>*)__current_node;
   239     // current_node is a concatenation node.  We are positioned on the first
   240     // character in its right child.
   241     // node_start_pos is starting position of current_node.
   242     __node_start_pos += __c->_M_left->_M_size._M_data;
   243     __current_node = __c->_M_right;
   244     __x._M_path_end[++__current_index] = __current_node;
   245     __dirns |= 1;
   246     while (_RopeRep::_S_concat == __current_node->_M_tag) {
   247 	++__current_index;
   248 	if (_S_path_cache_len == __current_index) {
   249 	    int __i;
   250 	    for (__i = 0; __i < _S_path_cache_len-1; __i++) {
   251 		__x._M_path_end[__i] = __x._M_path_end[__i+1];
   252 	    }
   253 	    --__current_index;
   254 	}
   255 	__current_node =
   256 	    ((_Rope_RopeConcatenation<_CharT,_Alloc>*)__current_node)->_M_left;
   257 	__x._M_path_end[__current_index] = __current_node;
   258 	__dirns <<= 1;
   259 	// node_start_pos is unchanged.
   260     }
   261     __x._M_leaf_index = __current_index;
   262     __x._M_leaf_pos = __node_start_pos;
   263     __x._M_path_directions = __dirns;
   264     _S_setbuf(__x);
   265 }
   266 
   267 template <class _CharT, class _Alloc>
   268 void _Rope_iterator_base<_CharT,_Alloc>::_M_incr(size_t __n) {
   269     _M_current_pos += __n;
   270     if (0 != _M_buf_ptr) {
   271         size_t __chars_left = _M_buf_end - _M_buf_ptr;
   272         if (__chars_left > __n) {
   273             _M_buf_ptr += __n;
   274         } else if (__chars_left == __n) {
   275             _M_buf_ptr += __n;
   276             _S_setcache_for_incr(*this);
   277         } else {
   278             _M_buf_ptr = 0;
   279         }
   280     }
   281 }
   282 
   283 template <class _CharT, class _Alloc>
   284 void _Rope_iterator_base<_CharT,_Alloc>::_M_decr(size_t __n) {
   285     if (0 != _M_buf_ptr) {
   286         size_t __chars_left = _M_buf_ptr - _M_buf_start;
   287         if (__chars_left >= __n) {
   288             _M_buf_ptr -= __n;
   289         } else {
   290             _M_buf_ptr = 0;
   291         }
   292     }
   293     _M_current_pos -= __n;
   294 }
   295 
   296 template <class _CharT, class _Alloc>
   297 void _Rope_iterator<_CharT,_Alloc>::_M_check() {
   298     if (_M_root_rope->_M_tree_ptr._M_data != this->_M_root) {
   299         // _Rope was modified.  Get things fixed up.
   300         _RopeRep::_S_unref(this->_M_root);
   301         this->_M_root = _M_root_rope->_M_tree_ptr._M_data;
   302         _RopeRep::_S_ref(this->_M_root);
   303         this->_M_buf_ptr = 0;
   304     }
   305 }
   306 
   307 # ifndef _GC
   308 //  There are several reasons for not doing this with virtual destructors
   309 //  and a class specific delete operator:
   310 //  - A class specific delete operator can't easily get access to
   311 //    allocator instances if we need them.
   312 //  - Any virtual function would need a 4 or byte vtable pointer;
   313 //    this only requires a one byte tag per object.
   314 template <class _CharT, class _Alloc>
   315 void _Rope_RopeRep<_CharT,_Alloc>::_M_free_tree()
   316 {
   317     switch(_M_tag) {
   318 	case _S_leaf:
   319 	    {
   320 	      typedef _Rope_RopeLeaf<_CharT,_Alloc> _Rope_RopeLeaf_T;
   321           _Rope_RopeLeaf_T* __l = (_Rope_RopeLeaf_T*)this;
   322           _STLP_STD::_Destroy(__l); // ->_Rope_RopeLeaf<_CharT,_Alloc>::~_Rope_RopeLeaf();
   323 	      _STLP_CREATE_ALLOCATOR(allocator_type,(const allocator_type&)_M_size, _Rope_RopeLeaf_T).deallocate(__l, 1);
   324 	        break;
   325 	    }
   326 	case _S_concat:
   327 	    {
   328                typedef _Rope_RopeConcatenation<_CharT,_Alloc> _Rope_RopeConcatenation_T;
   329                _Rope_RopeConcatenation_T* __c  = (_Rope_RopeConcatenation_T*)this;
   330                _STLP_STD::_Destroy(__c);
   331                _STLP_CREATE_ALLOCATOR(allocator_type,(const allocator_type&)_M_size, 
   332                                _Rope_RopeConcatenation_T).deallocate(__c, 1);
   333 	        break;
   334 	    }
   335 	case _S_function:
   336 	    {
   337             typedef _Rope_RopeFunction<_CharT,_Alloc> _Rope_RopeFunctionT;
   338               _Rope_RopeFunctionT* __f = (_Rope_RopeFunctionT*)this;
   339               _STLP_STD::_Destroy(__f);
   340               _STLP_CREATE_ALLOCATOR(allocator_type,(const allocator_type&)_M_size, 
   341                                  _Rope_RopeFunctionT).deallocate(__f, 1);
   342 	        break;
   343 	    }
   344 	case _S_substringfn:
   345 	    {
   346             typedef _Rope_RopeSubstring<_CharT,_Alloc> _Rope_RopeSubstring_T;
   347               _Rope_RopeSubstring_T* __ss = (_Rope_RopeSubstring_T*)this;
   348               _STLP_STD::_Destroy(__ss);
   349               _STLP_CREATE_ALLOCATOR(allocator_type,(const allocator_type&)_M_size, 
   350                               _Rope_RopeSubstring_T).deallocate(__ss, 1);
   351 		break;
   352 	    }
   353     }
   354 }
   355 #endif
   356 
   357 # if defined ( _STLP_NESTED_TYPE_PARAM_BUG )
   358 #   define __RopeLeaf__ _Rope_RopeLeaf<_CharT,_Alloc>
   359 #   define __RopeRep__ _Rope_RopeRep<_CharT,_Alloc>
   360 #   define _RopeLeaf _Rope_RopeLeaf<_CharT,_Alloc>
   361 #   define _RopeRep _Rope_RopeRep<_CharT,_Alloc>
   362 #   define size_type size_t
   363 # else
   364 #   define __RopeLeaf__ _STLP_TYPENAME_ON_RETURN_TYPE rope<_CharT,_Alloc>::_RopeLeaf
   365 #   define __RopeRep__ _STLP_TYPENAME_ON_RETURN_TYPE rope<_CharT,_Alloc>::_RopeRep
   366 # endif
   367 
   368 // Concatenate a C string onto a leaf rope by copying the rope data.
   369 // Used for short ropes.
   370 template <class _CharT, class _Alloc>
   371 __RopeLeaf__*
   372 rope<_CharT,_Alloc>::_S_leaf_concat_char_iter
   373 		(_RopeLeaf* __r, const _CharT* __iter, size_t __len)
   374 {
   375     size_t __old_len = __r->_M_size._M_data;
   376     _CharT* __new_data = __r->_M_size.allocate(_S_rounded_up_size(__old_len + __len));
   377     _RopeLeaf* __result;
   378     
   379     uninitialized_copy_n(__r->_M_data, __old_len, __new_data);
   380     uninitialized_copy_n(__iter, __len, __new_data + __old_len);
   381     _S_cond_store_eos(__new_data[__old_len + __len]);
   382     _STLP_TRY {
   383 	__result = _S_new_RopeLeaf(__new_data, __old_len + __len,
   384 				   __r->get_allocator());
   385     }
   386     _STLP_UNWIND(_RopeRep::_S_free_string(__new_data, __old_len + __len,
   387 					     __r->get_allocator()));
   388     return __result;
   389 }
   390 
   391 #ifndef __GC
   392 // As above, but it's OK to clobber original if refcount is 1
   393 template <class _CharT, class _Alloc>
   394 __RopeLeaf__*
   395 rope<_CharT,_Alloc>::_S_destr_leaf_concat_char_iter
   396 		(_RopeLeaf* __r, const _CharT* __iter, size_t __len)
   397 {
   398     _STLP_ASSERT(__r->_M_ref_count >= 1)
   399     if (__r->_M_ref_count > 1)
   400       return _S_leaf_concat_char_iter(__r, __iter, __len);
   401     size_t __old_len = __r->_M_size._M_data;
   402     if (_S_allocated_capacity(__old_len) >= __old_len + __len) {
   403 	// The space has been partially initialized for the standard
   404 	// character types.  But that doesn't matter for those types.
   405 	uninitialized_copy_n(__iter, __len, __r->_M_data + __old_len);
   406 	if (_S_is_basic_char_type((_CharT*)0)) {
   407 	    _S_cond_store_eos(__r->_M_data[__old_len + __len]);
   408 	    _STLP_ASSERT(__r->_M_c_string == __r->_M_data)
   409 	} else if (__r->_M_c_string != __r->_M_data && 0 != __r->_M_c_string) {
   410 	    __r->_M_free_c_string();
   411 	    __r->_M_c_string = 0;
   412 	}
   413 	__r->_M_size._M_data = __old_len + __len;
   414 	_STLP_ASSERT(__r->_M_ref_count == 1)
   415 	__r->_M_ref_count = 2;
   416 	return __r;
   417     } else {
   418 	_RopeLeaf* __result = _S_leaf_concat_char_iter(__r, __iter, __len);
   419 	_STLP_ASSERT(__result->_M_ref_count == 1)
   420 	return __result;
   421     }
   422 }
   423 #endif
   424 
   425 // Assumes left and right are not 0.
   426 // Does not increment (nor decrement on exception) child reference counts.
   427 // Result has ref count 1.
   428 template <class _CharT, class _Alloc>
   429 __RopeRep__*
   430 rope<_CharT,_Alloc>::_S_tree_concat (_RopeRep* __left, _RopeRep* __right)
   431 {
   432     _RopeConcatenation* __result =
   433       _S_new_RopeConcatenation(__left, __right, __left->get_allocator());
   434     size_t __depth = __result->_M_depth;
   435     
   436     _STLP_ASSERT(__left->get_allocator() == __right->get_allocator())
   437     if (__depth > 20 && (__result->_M_size._M_data < 1000 ||
   438 			 __depth > _RopeRep::_S_max_rope_depth)) {
   439         _RopeRep* __balanced;
   440       
   441 	_STLP_TRY {
   442 	   __balanced = _S_balance(__result);
   443 #          ifndef __GC
   444 	     if (__result != __balanced) {
   445 		_STLP_ASSERT(1 == __result->_M_ref_count
   446 			     && 1 == __balanced->_M_ref_count)
   447 	     }
   448 #          endif
   449 	   __result->_M_unref_nonnil();
   450         }
   451       _STLP_UNWIND((_STLP_CREATE_ALLOCATOR(allocator_type,(allocator_type&)__left->_M_size,
   452                                     _RopeConcatenation).deallocate(__result,1)));
   453 		// In case of exception, we need to deallocate
   454 		// otherwise dangling result node.  But caller
   455 		// still owns its children.  Thus unref is
   456 		// inappropriate.
   457 	return __balanced;
   458     } else {
   459 	return __result;
   460     }
   461 }
   462 
   463 template <class _CharT, class _Alloc>
   464 __RopeRep__*
   465 rope<_CharT,_Alloc>::_S_concat_char_iter
   466 		(_RopeRep* __r, const _CharT*__s, size_t __slen)
   467 {
   468     _RopeRep* __result;
   469     if (0 == __slen) {
   470 	_S_ref(__r);
   471 	return __r;
   472     }
   473     if (0 == __r)
   474       return _STLP_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen,
   475 					      /* __r->get_allocator()*/ allocator_type() );
   476     if (_RopeRep::_S_leaf == __r->_M_tag && 
   477           __r->_M_size._M_data + __slen <= _S_copy_max) {
   478 	__result = _S_leaf_concat_char_iter((_RopeLeaf*)__r, __s, __slen);
   479 #       ifndef __GC
   480 	  _STLP_ASSERT(1 == __result->_M_ref_count)
   481 #       endif
   482 	return __result;
   483     }
   484     if (_RopeRep::_S_concat == __r->_M_tag
   485 	&& _RopeRep::_S_leaf == ((_RopeConcatenation*)__r)->_M_right->_M_tag) {
   486 	_RopeLeaf* __right = 
   487 	  (_RopeLeaf* )(((_RopeConcatenation* )__r)->_M_right);
   488 	if (__right->_M_size._M_data + __slen <= _S_copy_max) {
   489 	  _RopeRep* __left = ((_RopeConcatenation*)__r)->_M_left;
   490 	  _RopeRep* __nright = 
   491 	    _S_leaf_concat_char_iter((_RopeLeaf*)__right, __s, __slen);
   492 	  __left->_M_ref_nonnil();
   493 	  _STLP_TRY {
   494 	    __result = _S_tree_concat(__left, __nright);
   495           }
   496 	  _STLP_UNWIND(_S_unref(__left); _S_unref(__nright));
   497 #         ifndef __GC
   498 	    _STLP_ASSERT(1 == __result->_M_ref_count)
   499 #         endif
   500 	  return __result;
   501 	}
   502     }
   503     _RopeRep* __nright =
   504       _STLP_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __r->get_allocator());
   505     _STLP_TRY {
   506       __r->_M_ref_nonnil();
   507       __result = _S_tree_concat(__r, __nright);
   508     }
   509     _STLP_UNWIND(_S_unref(__r); _S_unref(__nright));
   510 #   ifndef __GC
   511       _STLP_ASSERT(1 == __result->_M_ref_count)
   512 #   endif
   513     return __result;
   514 }
   515 
   516 #ifndef __GC
   517 template <class _CharT, class _Alloc>
   518 __RopeRep__* 
   519 rope<_CharT,_Alloc>::_S_destr_concat_char_iter(
   520   _RopeRep* __r, const _CharT* __s, size_t __slen)
   521 {
   522     _RopeRep* __result;
   523     if (0 == __r)
   524       return _STLP_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen,
   525 					      /* __r-> */allocator_type());
   526     size_t __count = __r->_M_ref_count;
   527     size_t __orig_size = __r->_M_size._M_data;
   528     _STLP_ASSERT(__count >= 1)
   529     if (__count > 1) return _S_concat_char_iter(__r, __s, __slen);
   530     if (0 == __slen) {
   531 	__r->_M_ref_count = 2;      // One more than before
   532 	return __r;
   533     }
   534     if (__orig_size + __slen <= _S_copy_max && 
   535           _RopeRep::_S_leaf == __r->_M_tag) {
   536 	__result = _S_destr_leaf_concat_char_iter((_RopeLeaf*)__r, __s, __slen);
   537 	return __result;
   538     }
   539     if (_RopeRep::_S_concat == __r->_M_tag) {
   540 	_RopeLeaf* __right = (_RopeLeaf*)(((_RopeConcatenation*)__r)->_M_right);
   541 	if (_RopeRep::_S_leaf == __right->_M_tag
   542 	    && __right->_M_size._M_data + __slen <= _S_copy_max) {
   543 	  _RopeRep* __new_right = 
   544 	    _S_destr_leaf_concat_char_iter(__right, __s, __slen);
   545 	  if (__right == __new_right) {
   546 	      _STLP_ASSERT(__new_right->_M_ref_count == 2)
   547 	      __new_right->_M_ref_count = 1;
   548 	  } else {
   549 	      _STLP_ASSERT(__new_right->_M_ref_count >= 1)
   550 	      __right->_M_unref_nonnil();
   551 	  }
   552 	  _STLP_ASSERT(__r->_M_ref_count == 1)
   553 	  __r->_M_ref_count = 2;    // One more than before.
   554       ((_RopeConcatenation*)__r)->_M_right = __new_right;
   555       // E.Musser : moved below
   556       //	  __r->_M_size._M_data = __orig_size + __slen;
   557 	  if (0 != __r->_M_c_string) {
   558 	      __r->_M_free_c_string();
   559 	      __r->_M_c_string = 0;
   560 	  }
   561 	  __r->_M_size._M_data = __orig_size + __slen;
   562 	  return __r;
   563 	}
   564     }
   565     _RopeRep* __right =
   566       _STLP_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __r->get_allocator());
   567     __r->_M_ref_nonnil();
   568     _STLP_TRY {
   569       __result = _S_tree_concat(__r, __right);
   570     }
   571     _STLP_UNWIND(_S_unref(__r); _S_unref(__right))
   572     _STLP_ASSERT(1 == __result->_M_ref_count)
   573     return __result;
   574 }
   575 #endif /* !__GC */
   576 
   577 template <class _CharT, class _Alloc>
   578 __RopeRep__*
   579 rope<_CharT,_Alloc>::_S_concat_rep(_RopeRep* __left, _RopeRep* __right)
   580 {
   581     if (0 == __left) {
   582 	_S_ref(__right);
   583 	return __right;
   584     }
   585     if (0 == __right) {
   586 	__left->_M_ref_nonnil();
   587 	return __left;
   588     }
   589     if (_RopeRep::_S_leaf == __right->_M_tag) {
   590 	if (_RopeRep::_S_leaf == __left->_M_tag) {
   591 	  if (__right->_M_size._M_data + __left->_M_size._M_data <= _S_copy_max) {
   592 	    return _S_leaf_concat_char_iter((_RopeLeaf*)__left,
   593 					 ((_RopeLeaf*)__right)->_M_data,
   594 					 __right->_M_size._M_data);
   595 	  }
   596 	} else if (_RopeRep::_S_concat == __left->_M_tag
   597 		   && _RopeRep::_S_leaf ==
   598 		      ((_RopeConcatenation*)__left)->_M_right->_M_tag) {
   599 	  _RopeLeaf* __leftright =
   600 		    (_RopeLeaf*)(((_RopeConcatenation*)__left)->_M_right); 
   601 	  if (__leftright->_M_size._M_data + __right->_M_size._M_data <= _S_copy_max) {
   602 	    _RopeRep* __leftleft = ((_RopeConcatenation*)__left)->_M_left;
   603 	    _RopeRep* __rest = _S_leaf_concat_char_iter(__leftright,
   604 					   ((_RopeLeaf*)__right)->_M_data,
   605 					   __right->_M_size._M_data);
   606 	    __leftleft->_M_ref_nonnil();
   607 	    _STLP_TRY {
   608 	      return(_S_tree_concat(__leftleft, __rest));
   609             }
   610 	    _STLP_UNWIND(_S_unref(__leftleft); _S_unref(__rest))
   611 	  }
   612 	}
   613     }
   614     __left->_M_ref_nonnil();
   615     __right->_M_ref_nonnil();
   616     _STLP_TRY {
   617       return(_S_tree_concat(__left, __right));
   618     }
   619     _STLP_UNWIND(_S_unref(__left); _S_unref(__right));
   620 #ifdef _STLP_THROW_RETURN_BUG
   621 	return 0;
   622 #endif
   623 }
   624 
   625 template <class _CharT, class _Alloc>
   626 __RopeRep__*
   627 rope<_CharT,_Alloc>::_S_substring(_RopeRep* __base, 
   628                                size_t __start, size_t __endp1)
   629 {
   630     if (0 == __base) return 0;
   631     size_t __len = __base->_M_size._M_data;
   632     size_t __adj_endp1;
   633     const size_t __lazy_threshold = 128;
   634     
   635     if (__endp1 >= __len) {
   636 	if (0 == __start) {
   637 	    __base->_M_ref_nonnil();
   638 	    return __base;
   639 	} else {
   640 	    __adj_endp1 = __len;
   641 	}
   642     } else {
   643 	__adj_endp1 = __endp1;
   644     }
   645     switch(__base->_M_tag) {
   646 	case _RopeRep::_S_concat:
   647 	    {
   648 		_RopeConcatenation* __c = (_RopeConcatenation*)__base;
   649 		_RopeRep* __left = __c->_M_left;
   650 		_RopeRep* __right = __c->_M_right;
   651 		size_t __left_len = __left->_M_size._M_data;
   652 		_RopeRep* __result;
   653 
   654 		if (__adj_endp1 <= __left_len) {
   655 		    return _S_substring(__left, __start, __endp1);
   656 		} else if (__start >= __left_len) {
   657 		    return _S_substring(__right, __start - __left_len,
   658 				  __adj_endp1 - __left_len);
   659 		}
   660 		_Self_destruct_ptr __left_result(
   661 		  _S_substring(__left, __start, __left_len));
   662 		_Self_destruct_ptr __right_result(
   663 		  _S_substring(__right, 0, __endp1 - __left_len));
   664 		_STLP_MPWFIX_TRY		//*TY 06/01/2000 - mpw forgets to call dtor on __left_result and __right_result without this try block
   665 		__result = _S_concat_rep(__left_result, __right_result);
   666 #               ifndef __GC
   667 		  _STLP_ASSERT(1 == __result->_M_ref_count)
   668 #               endif
   669 		return __result;
   670 		_STLP_MPWFIX_CATCH		//*TY 06/01/2000 - 
   671 	    }
   672 	case _RopeRep::_S_leaf:
   673 	    {
   674 		_RopeLeaf* __l = (_RopeLeaf*)__base;
   675 		_RopeLeaf* __result;
   676 		size_t __result_len;
   677 		if (__start >= __adj_endp1) return 0;
   678 		__result_len = __adj_endp1 - __start;
   679 		if (__result_len > __lazy_threshold) goto lazy;
   680 #               ifdef __GC
   681 		    const _CharT* __section = __l->_M_data + __start;
   682 		    __result = _S_new_RopeLeaf(__section, __result_len,
   683 					  __base->get_allocator());
   684 		    __result->_M_c_string = 0;  // Not eos terminated.
   685 #               else
   686 		    // We should sometimes create substring node instead.
   687 		    __result = _STLP_ROPE_FROM_UNOWNED_CHAR_PTR(
   688 					__l->_M_data + __start, __result_len,
   689 					__base->get_allocator());
   690 #               endif
   691 		return __result;
   692 	    }
   693 	case _RopeRep::_S_substringfn:
   694 	    // Avoid introducing multiple layers of substring nodes.
   695 	    {
   696 		_RopeSubstring* __old = (_RopeSubstring*)__base;
   697 		size_t __result_len;
   698 		if (__start >= __adj_endp1) return 0;
   699 		__result_len = __adj_endp1 - __start;
   700 		if (__result_len > __lazy_threshold) {
   701 		    _RopeSubstring* __result =
   702 			_S_new_RopeSubstring(__old->_M_base,
   703 					  __start + __old->_M_start,
   704 					  __adj_endp1 - __start,
   705 					  __base->get_allocator());
   706 		    return __result;
   707 
   708 		} // *** else fall through: ***
   709 	    }
   710 	case _RopeRep::_S_function:
   711 	    {
   712 		_RopeFunction* __f = (_RopeFunction*)__base;
   713 		if (__start >= __adj_endp1) return 0;
   714 		size_t __result_len = __adj_endp1 - __start;
   715 
   716 		if (__result_len > __lazy_threshold) goto lazy;
   717 		_CharT* __section = __base->_M_size.allocate(_S_rounded_up_size(__result_len));
   718 		_STLP_TRY {
   719 		  (*(__f->_M_fn))(__start, __result_len, __section);
   720                 }
   721 		_STLP_UNWIND(_RopeRep::_S_free_string(
   722 	               __section, __result_len, __base->get_allocator()));
   723 		_S_cond_store_eos(__section[__result_len]);
   724 		return _S_new_RopeLeaf(__section, __result_len,
   725 				       __base->get_allocator());
   726 	    }
   727     }
   728     /*NOTREACHED*/
   729     _STLP_ASSERT(false)
   730   lazy:
   731     {
   732 	// Create substring node.
   733 	return _S_new_RopeSubstring(__base, __start, __adj_endp1 - __start,
   734 			       __base->get_allocator());
   735     }
   736 }
   737 
   738 template<class _CharT>
   739 class _Rope_flatten_char_consumer : public _Rope_char_consumer<_CharT> {
   740     private:
   741 	_CharT* _M_buf_ptr;
   742     public:
   743 	//  _CharT* _M_buffer;  // XXX not used
   744 
   745 	_Rope_flatten_char_consumer(_CharT* __buffer) {
   746 	    _M_buf_ptr = __buffer;
   747 	};
   748 	~_Rope_flatten_char_consumer() {}
   749 	bool operator() (const _CharT* __leaf, size_t __n) {
   750 	    uninitialized_copy_n(__leaf, __n, _M_buf_ptr);
   751 	    _M_buf_ptr += __n;
   752 	    return true;
   753 	}
   754 };
   755 	    
   756 template<class _CharT>
   757 class _Rope_find_char_char_consumer : public _Rope_char_consumer<_CharT> {
   758     private:
   759 	_CharT _M_pattern;
   760     public:
   761 	size_t _M_count;  // Number of nonmatching characters
   762 	_Rope_find_char_char_consumer(_CharT __p) 
   763 	  : _M_pattern(__p), _M_count(0) {}
   764 	~_Rope_find_char_char_consumer() {}
   765 	bool operator() (const _CharT* __leaf, size_t __n) {
   766 	    size_t __i;
   767 	    for (__i = 0; __i < __n; __i++) {
   768 		if (__leaf[__i] == _M_pattern) {
   769 		    _M_count += __i; return false;
   770 		}
   771 	    }
   772 	    _M_count += __n; return true;
   773 	}
   774 };
   775 
   776 #if !defined (_STLP_USE_NO_IOSTREAMS)	    
   777 #if defined (_STLP_USE_NEW_IOSTREAMS)
   778   template<class _CharT, class _Traits>
   779   // Here _CharT is both the stream and rope character type.
   780 #else
   781  template<class _CharT>
   782   // Here _CharT is the rope character type.  Unlike in the
   783   // above case, we somewhat handle the case in which it doesn't
   784   // match the stream character type, i.e. char.
   785 #endif
   786 class _Rope_insert_char_consumer : public _Rope_char_consumer<_CharT> {
   787     private:
   788 #       if defined (_STLP_USE_NEW_IOSTREAMS)
   789 	  typedef basic_ostream<_CharT,_Traits> _Insert_ostream;
   790 #	else
   791  	typedef ostream _Insert_ostream;
   792 #	endif
   793 	_Insert_ostream& _M_o;
   794     public:
   795 	// _CharT* buffer;    // XXX not used
   796 	_Rope_insert_char_consumer(_Insert_ostream& __writer) 
   797 	  : _M_o(__writer) {};
   798 #if defined(__MRC__)||(defined(__SC__) && !defined(__DMC__))		//*TY 05/23/2000 - added support for mpw compiler's trigger function approach to generate vtable
   799   ~_Rope_insert_char_consumer();		//*TY 05/23/2000 - 
   800 #else		//*TY 05/23/2000 - 
   801   ~_Rope_insert_char_consumer() {}
   802 #endif		//*TY 05/23/2000 - 
   803 		// Caller is presumed to own the ostream
   804 	bool operator() (const _CharT* __leaf, size_t __n);
   805 		// Returns true to continue traversal.
   806 };
   807 	    
   808 # if defined ( _STLP_USE_NEW_IOSTREAMS )
   809 #  if defined(__MRC__)||(defined(__SC__) && !defined(__DMC__))		//*TY 05/23/2000 - added support for mpw compiler's trigger function approach to generate vtable
   810   template<class _CharT, class _Traits>
   811   _Rope_insert_char_consumer<_CharT, _Traits>::  ~_Rope_insert_char_consumer() {}
   812 #  endif		//*TY 05/23/2000 - 
   813 
   814   template<class _CharT, class _Traits>
   815   bool _Rope_insert_char_consumer<_CharT, _Traits>::operator()
   816 					(const _CharT* __leaf, size_t __n)
   817 {
   818     size_t __i;
   819     //  We assume that formatting is set up correctly for each element.
   820     for (__i = 0; __i < __n; __i++) _M_o.put(__leaf[__i]);
   821     return true;
   822 }
   823 # else
   824 #  if defined(__MRC__)||(defined(__SC__) && !defined(__DMC__))		//*TY 05/23/2000 - added support for mpw compiler's trigger function approach to generate vtable
   825   template<class _CharT>
   826   _Rope_insert_char_consumer<_CharT>::  ~_Rope_insert_char_consumer() {}
   827 #  endif		//*TY 05/23/2000 - 
   828 
   829   template<class _CharT>
   830   bool _Rope_insert_char_consumer<_CharT>::operator()
   831 					(const _CharT* __leaf, size_t __n)
   832   {
   833     size_t __i;
   834     //  We assume that formatting is set up correctly for each element.
   835     for (__i = 0; __i < __n; __i++) _M_o << __leaf[__i];
   836     return true;
   837   }
   838 
   839 # if !defined (_STLP_NO_METHOD_SPECIALIZATION)
   840 _STLP_TEMPLATE_NULL
   841 inline bool 
   842 _Rope_insert_char_consumer<char>::operator()
   843 					(const char* __leaf, size_t __n)
   844 {
   845     size_t __i;
   846     for (__i = 0; __i < __n; __i++) _M_o.put(__leaf[__i]);
   847     return true;
   848 }
   849 
   850 #endif /* _STLP_METHOD_SPECIALIZATION */
   851 #endif /* _STLP_USE_NEW_IOSTREAM */
   852 #endif /* if !defined (_STLP_USE_NO_IOSTREAMS) */
   853 
   854 template <class _CharT, class _Alloc>
   855 bool rope<_CharT, _Alloc>::_S_apply_to_pieces(
   856 				_Rope_char_consumer<_CharT>& __c,
   857 				const _RopeRep* __r,
   858 				size_t __begin, size_t __end)
   859 {
   860     if (0 == __r) return true;
   861     switch(__r->_M_tag) {
   862 	case _RopeRep::_S_concat:
   863 	    {
   864 		_RopeConcatenation* __conc = (_RopeConcatenation*)__r;
   865 		_RopeRep* __left =  __conc->_M_left;
   866 		size_t __left_len = __left->_M_size._M_data;
   867 		if (__begin < __left_len) {
   868 		    size_t __left_end = (min) (__left_len, __end);
   869 		    if (!_S_apply_to_pieces(__c, __left, __begin, __left_end))
   870 			return false;
   871 		}
   872 		if (__end > __left_len) {
   873 		    _RopeRep* __right =  __conc->_M_right;
   874 		    size_t __right_start = (max)(__left_len, __begin);
   875 		    if (!_S_apply_to_pieces(__c, __right,
   876 					 __right_start - __left_len,
   877 					 __end - __left_len)) {
   878 			return false;
   879 		    }
   880 		}
   881 	    }
   882 	    return true;
   883 	case _RopeRep::_S_leaf:
   884 	    {
   885 		_RopeLeaf* __l = (_RopeLeaf*)__r;
   886 		return __c.operator()(__l->_M_data + __begin, __end - __begin);
   887 	    }
   888 	case _RopeRep::_S_function:
   889 	case _RopeRep::_S_substringfn:
   890 	    {
   891 		_RopeFunction* __f = (_RopeFunction*)__r;
   892 		size_t __len = __end - __begin;
   893 #ifdef __SYMBIAN32__
   894 		bool __result = false;
   895 #else
   896 		bool __result;
   897 #endif
   898 		_CharT* __buffer =
   899 		  (_CharT*)__sgi_alloc::allocate(__len * sizeof(_CharT));
   900 		_STLP_TRY {
   901 		  (*(__f->_M_fn))(__begin, __len, __buffer);
   902 		  __result = __c.operator()(__buffer, __len);
   903                   __sgi_alloc::deallocate(__buffer, __len * sizeof(_CharT));
   904                 }
   905 		_STLP_UNWIND((__sgi_alloc::deallocate(__buffer,
   906 						      __len * sizeof(_CharT))))
   907 		return __result;
   908 	    }
   909 	default:
   910 	    _STLP_ASSERT(false)
   911 	    /*NOTREACHED*/
   912 	    return false;
   913     }
   914 }
   915 
   916 template <class _CharT> inline bool _Rope_is_simple(_CharT*) { return false; }
   917 inline bool _Rope_is_simple(char*) { return true; }
   918 # ifdef _STLP_HAS_WCHAR_T
   919 inline bool _Rope_is_simple(wchar_t*) { return true; }
   920 # endif
   921 
   922 #if !defined (_STLP_USE_NO_IOSTREAMS)
   923 #if defined (_STLP_USE_NEW_IOSTREAMS)
   924   template<class _CharT, class _Traits>
   925   inline void _Rope_fill(basic_ostream<_CharT, _Traits>& __o, size_t __n)
   926 #else
   927 inline void _Rope_fill(ostream& __o, size_t __n)
   928 #endif
   929 {
   930     char __f = __o.fill();
   931     size_t __i;
   932 
   933     for (__i = 0; __i < __n; __i++) __o.put(__f);
   934 }
   935     
   936 #if defined (_STLP_USE_NEW_IOSTREAMS)
   937   template<class _CharT, class _Traits, class _Alloc>
   938   basic_ostream<_CharT, _Traits>& operator<<
   939 					(basic_ostream<_CharT, _Traits>& __o,
   940 					 const rope<_CharT, _Alloc>& __r)
   941 # else
   942 template<class _CharT, class _Alloc>
   943 ostream& operator<< (ostream& __o, const rope<_CharT, _Alloc>& __r)
   944 #endif
   945 {
   946     size_t __w = __o.width();
   947     bool __left = bool(__o.flags() & ios::left);
   948     size_t __pad_len;
   949     size_t __rope_len = __r.size();
   950 #   if defined (_STLP_USE_NEW_IOSTREAMS)
   951       _Rope_insert_char_consumer<_CharT, _Traits> __c(__o);
   952 #   else
   953     _Rope_insert_char_consumer<_CharT> __c(__o);
   954 #   endif
   955     bool __is_simple = _Rope_is_simple((_CharT*)0);
   956     
   957     if (__rope_len < __w) {
   958 	__pad_len = __w - __rope_len;
   959     } else {
   960 	__pad_len = 0;
   961     }
   962     if (!__is_simple) __o.width(__w/__rope_len);
   963     _STLP_TRY {
   964       if (__is_simple && !__left && __pad_len > 0) {
   965 	_Rope_fill(__o, __pad_len);
   966       }
   967       __r.apply_to_pieces(0, __r.size(), __c);
   968       if (__is_simple && __left && __pad_len > 0) {
   969 	_Rope_fill(__o, __pad_len);
   970       }
   971       if (!__is_simple)
   972         __o.width(__w);
   973     }
   974     _STLP_UNWIND(if (!__is_simple) __o.width(__w))
   975     return __o;
   976 }
   977 
   978 #endif /* NO_IOSTREAMS */
   979 
   980 template <class _CharT, class _Alloc>
   981 _CharT*
   982 rope<_CharT,_Alloc>::_S_flatten(_RopeRep* __r,
   983 				 size_t __start, size_t __len,
   984 				 _CharT* __buffer)
   985 {
   986     _Rope_flatten_char_consumer<_CharT> __c(__buffer);
   987     _S_apply_to_pieces(__c, __r, __start, __start + __len);
   988     return(__buffer + __len);
   989 }
   990 
   991 template <class _CharT, class _Alloc>
   992 size_t
   993 rope<_CharT,_Alloc>::find(_CharT __pattern, size_t __start) const
   994 {
   995     _Rope_find_char_char_consumer<_CharT> __c(__pattern);
   996     _S_apply_to_pieces(__c, _M_tree_ptr._M_data, __start, size());
   997     size_type __result_pos = __start + __c._M_count;
   998 #   ifndef _STLP_OLD_ROPE_SEMANTICS
   999 	if (__result_pos == size()) __result_pos = npos;
  1000 #   endif
  1001     return __result_pos;
  1002 }
  1003 
  1004 template <class _CharT, class _Alloc>
  1005 _CharT*
  1006 rope<_CharT,_Alloc>::_S_flatten(_Rope_RopeRep<_CharT, _Alloc>* __r, _CharT* __buffer)
  1007 {
  1008     if (0 == __r) return __buffer;
  1009     switch(__r->_M_tag) {
  1010 	case _RopeRep::_S_concat:
  1011 	    {
  1012 		_RopeConcatenation* __c = (_RopeConcatenation*)__r;
  1013 		_RopeRep* __left = __c->_M_left;
  1014 		_RopeRep* __right = __c->_M_right;
  1015 		_CharT* __rest = _S_flatten(__left, __buffer);
  1016 		return _S_flatten(__right, __rest);
  1017 	    }
  1018 	case _RopeRep::_S_leaf:
  1019 	    {
  1020 		_RopeLeaf* __l = (_RopeLeaf*)__r;
  1021 		return copy_n(__l->_M_data, __l->_M_size._M_data, __buffer).second;
  1022 	    }
  1023 	case _RopeRep::_S_function:
  1024 	case _RopeRep::_S_substringfn:
  1025 	    // We dont yet do anything with substring nodes.
  1026 	    // This needs to be fixed before ropefiles will work well.
  1027 	    {
  1028 		_RopeFunction* __f = (_RopeFunction*)__r;
  1029 		(*(__f->_M_fn))(0, __f->_M_size._M_data, __buffer);
  1030 		return __buffer + __f->_M_size._M_data;
  1031 	    }
  1032 	default:
  1033 	    _STLP_ASSERT(false)
  1034 	    /*NOTREACHED*/
  1035 	    return 0;
  1036     }
  1037 }
  1038 
  1039 
  1040 // This needs work for _CharT != char
  1041 template <class _CharT, class _Alloc>
  1042 void
  1043 rope<_CharT,_Alloc>::_S_dump(_RopeRep* __r, int __indent)
  1044 {
  1045     for (int __i = 0; __i < __indent; __i++) putchar(' ');
  1046     if (0 == __r) {
  1047       printf("NULL\n"); return;
  1048     }
  1049     if (_RopeRep::_S_concat == __r->_M_tag) {
  1050 	_RopeConcatenation* __c = (_RopeConcatenation*)__r;
  1051 	_RopeRep* __left = __c->_M_left;
  1052 	_RopeRep* __right = __c->_M_right;
  1053 
  1054 #       ifdef __GC
  1055 	  printf("Concatenation %p (depth = %d, len = %ld, %s balanced)\n",
  1056 	    __r, __r->_M_depth, __r->_M_size._M_data, __r->_M_is_balanced? "" : "not");
  1057 #       else
  1058 	  printf("Concatenation %p (rc = %ld, depth = %d, "
  1059 	           "len = %ld, %s balanced)\n",
  1060 		 __r, __r->_M_ref_count, __r->_M_depth, __r->_M_size._M_data,
  1061 		 __r->_M_is_balanced? "" : "not");
  1062 #       endif
  1063 	_S_dump(__left, __indent + 2);
  1064 	_S_dump(__right, __indent + 2);
  1065 	return;
  1066     } else {
  1067 	const char* __kind;
  1068 
  1069 	switch (__r->_M_tag) {
  1070 	    case _RopeRep::_S_leaf:
  1071 		__kind = "Leaf";
  1072 		break;
  1073 	    case _RopeRep::_S_function:
  1074 		__kind = "Function";
  1075 		break;
  1076 	    case _RopeRep::_S_substringfn:
  1077 		__kind = "Function representing substring";
  1078 		break;
  1079 	    default:
  1080 		__kind = "(corrupted kind field!)";
  1081 	}
  1082 #       ifdef __GC
  1083 	  printf("%s %p (depth = %d, len = %ld) ",
  1084 		 __kind, __r, __r->_M_depth, __r->_M_size._M_data);
  1085 #       else
  1086 	  printf("%s %p (rc = %ld, depth = %d, len = %ld) ",
  1087 		 __kind, __r, __r->_M_ref_count, __r->_M_depth, __r->_M_size._M_data);
  1088 #       endif
  1089 	if (_S_is_one_byte_char_type((_CharT*)0)) {
  1090 	    const int __max_len = 40;
  1091 	    _Self_destruct_ptr __prefix(_S_substring(__r, 0, __max_len));
  1092 	    _CharT __buffer[__max_len + 1];
  1093 	    bool __too_big = __r->_M_size._M_data > __prefix->_M_size._M_data;
  1094 
  1095 	    _S_flatten(__prefix, __buffer);
  1096 	    __buffer[__prefix->_M_size._M_data] = _S_eos((_CharT*)0); 
  1097 	    printf("%s%s\n", 
  1098 	           (char*)__buffer, __too_big? "...\n" : "\n");
  1099 	} else {
  1100 	    printf("\n");
  1101 	}
  1102     }
  1103 }
  1104 
  1105 # define __ROPE_TABLE_BODY  = { \
  1106 /* 0 */1, /* 1 */2, /* 2 */3, /* 3 */5, /* 4 */8, /* 5 */13, /* 6 */21,         \
  1107 /* 7 */34, /* 8 */55, /* 9 */89, /* 10 */144, /* 11 */233, /* 12 */377,         \
  1108 /* 13 */610, /* 14 */987, /* 15 */1597, /* 16 */2584, /* 17 */4181,             \
  1109 /* 18 */6765ul, /* 19 */10946ul, /* 20 */17711ul, /* 21 */28657ul, /* 22 */46368ul,   \
  1110 /* 23 */75025ul, /* 24 */121393ul, /* 25 */196418ul, /* 26 */317811ul,                \
  1111 /* 27 */514229ul, /* 28 */832040ul, /* 29 */1346269ul, /* 30 */2178309ul,             \
  1112 /* 31 */3524578ul, /* 32 */5702887ul, /* 33 */9227465ul, /* 34 */14930352ul,          \
  1113 /* 35 */24157817ul, /* 36 */39088169ul, /* 37 */63245986ul, /* 38 */102334155ul,      \
  1114 /* 39 */165580141ul, /* 40 */267914296ul, /* 41 */433494437ul,                        \
  1115 /* 42 */701408733ul, /* 43 */1134903170ul, /* 44 */1836311903ul,                      \
  1116 /* 45 */2971215073ul }
  1117 
  1118 # if ( _STLP_STATIC_TEMPLATE_DATA > 0 )
  1119 template <class _CharT, class _Alloc>
  1120 const unsigned long
  1121 rope<_CharT,_Alloc>::_S_min_len[__ROPE_DEPTH_SIZE] __ROPE_TABLE_BODY ;
  1122 # else 
  1123 __DECLARE_INSTANCE(const unsigned long, 
  1124                    crope::_S_min_len[__ROPE_DEPTH_SIZE],
  1125                    __ROPE_TABLE_BODY);
  1126 #  ifndef _STLP_NO_WCHAR_T
  1127 __DECLARE_INSTANCE(const unsigned long, 
  1128                    wrope::_S_min_len[__ROPE_DEPTH_SIZE],
  1129                    __ROPE_TABLE_BODY);
  1130 #  endif
  1131 # endif
  1132 # undef __ROPE_DEPTH_SIZE
  1133 # undef __ROPE_MAX_DEPTH
  1134 # undef __ROPE_TABLE_BODY
  1135 
  1136 // These are Fibonacci numbers < 2**32.
  1137 
  1138 template <class _CharT, class _Alloc>
  1139 __RopeRep__*
  1140 rope<_CharT,_Alloc>::_S_balance(_RopeRep* __r)
  1141 {
  1142     _RopeRep* __forest[_RopeRep::_S_max_rope_depth + 1];
  1143     _RopeRep* __result = 0;
  1144     int __i;
  1145     // Invariant:
  1146     // The concatenation of forest in descending order is equal to __r.
  1147     // __forest[__i]._M_size._M_data >= _S_min_len[__i]
  1148     // __forest[__i]._M_depth = __i
  1149     // References from forest are included in refcount.
  1150 
  1151     for (__i = 0; __i <= _RopeRep::_S_max_rope_depth; ++__i) 
  1152       __forest[__i] = 0;
  1153     _STLP_TRY {
  1154       _S_add_to_forest(__r, __forest);
  1155       for (__i = 0; __i <= _RopeRep::_S_max_rope_depth; ++__i) 
  1156         if (0 != __forest[__i]) {
  1157 #	ifndef __GC
  1158 	  _Self_destruct_ptr __old(__result);
  1159 #	endif
  1160 	  __result = _S_concat_rep(__forest[__i], __result);
  1161 	__forest[__i]->_M_unref_nonnil();
  1162 #	if !defined(__GC) && defined(_STLP_USE_EXCEPTIONS)
  1163 	  __forest[__i] = 0;
  1164 #	endif
  1165       }
  1166     }
  1167     _STLP_UNWIND(for(__i = 0; __i <= _RopeRep::_S_max_rope_depth; __i++)
  1168 		 _S_unref(__forest[__i]))
  1169     if (__result->_M_depth > _RopeRep::_S_max_rope_depth) {
  1170 	__stl_throw_range_error("rope too long");
  1171     }
  1172     return(__result);
  1173 }
  1174 
  1175 
  1176 template <class _CharT, class _Alloc>
  1177 void
  1178 rope<_CharT,_Alloc>::_S_add_to_forest(_RopeRep* __r, _RopeRep** __forest)
  1179 {
  1180     if (__r -> _M_is_balanced) {
  1181 	_S_add_leaf_to_forest(__r, __forest);
  1182 	return;
  1183     }
  1184     _STLP_ASSERT(__r->_M_tag == _RopeRep::_S_concat)
  1185     {
  1186 	_RopeConcatenation* __c = (_RopeConcatenation*)__r;
  1187 
  1188 	_S_add_to_forest(__c->_M_left, __forest);
  1189 	_S_add_to_forest(__c->_M_right, __forest);
  1190     }
  1191 }
  1192 
  1193 
  1194 template <class _CharT, class _Alloc>
  1195 void
  1196 rope<_CharT,_Alloc>::_S_add_leaf_to_forest(_RopeRep* __r, _RopeRep** __forest)
  1197 {
  1198     _RopeRep* __insertee;   		// included in refcount
  1199     _RopeRep* __too_tiny = 0;    	// included in refcount
  1200     int __i;  				// forest[0..__i-1] is empty
  1201     size_t __s = __r->_M_size._M_data;
  1202 
  1203     for (__i = 0; __s >= _S_min_len[__i+1]/* not this bucket */; ++__i) {
  1204 	if (0 != __forest[__i]) {
  1205 #	    ifndef __GC
  1206 	      _Self_destruct_ptr __old(__too_tiny);
  1207 #	    endif
  1208 	    __too_tiny = _S_concat_and_set_balanced(__forest[__i], __too_tiny);
  1209 	    __forest[__i]->_M_unref_nonnil();
  1210 	    __forest[__i] = 0;
  1211 	}
  1212     }
  1213     {
  1214 #	ifndef __GC
  1215 	  _Self_destruct_ptr __old(__too_tiny);
  1216 #	endif
  1217 	__insertee = _S_concat_and_set_balanced(__too_tiny, __r);
  1218     }
  1219     // Too_tiny dead, and no longer included in refcount.
  1220     // Insertee is live and included.
  1221     _STLP_ASSERT(_S_is_almost_balanced(__insertee))
  1222     _STLP_ASSERT(__insertee->_M_depth <= __r->_M_depth + 1)
  1223     for (;; ++__i) {
  1224 	if (0 != __forest[__i]) {
  1225 #	    ifndef __GC
  1226 	      _Self_destruct_ptr __old(__insertee);
  1227 #	    endif
  1228 	    __insertee = _S_concat_and_set_balanced(__forest[__i], __insertee);
  1229 	    __forest[__i]->_M_unref_nonnil();
  1230 	    __forest[__i] = 0;
  1231 	    _STLP_ASSERT(_S_is_almost_balanced(__insertee))
  1232 	}
  1233 	_STLP_ASSERT(_S_min_len[__i] <= __insertee->_M_size._M_data)
  1234 	_STLP_ASSERT(__forest[__i] == 0)
  1235 	if (__i == _RopeRep::_S_max_rope_depth || 
  1236 	      __insertee->_M_size._M_data < _S_min_len[__i+1]) {
  1237 	    __forest[__i] = __insertee;
  1238 	    // refcount is OK since __insertee is now dead.
  1239 	    return;
  1240 	}
  1241     }
  1242 }
  1243 
  1244 template <class _CharT, class _Alloc>
  1245 _CharT
  1246 rope<_CharT,_Alloc>::_S_fetch(_RopeRep* __r, size_type __i)
  1247 {
  1248     __GC_CONST _CharT* __cstr = __r->_M_c_string;
  1249 
  1250     _STLP_ASSERT(__i < __r->_M_size._M_data)
  1251     if (0 != __cstr) return __cstr[__i]; 
  1252     for(;;) {
  1253       switch(__r->_M_tag) {
  1254 	case _RopeRep::_S_concat:
  1255 	    {
  1256 		_RopeConcatenation* __c = (_RopeConcatenation*)__r;
  1257 		_RopeRep* __left = __c->_M_left;
  1258 		size_t __left_len = __left->_M_size._M_data;
  1259 
  1260 		if (__i >= __left_len) {
  1261 		    __i -= __left_len;
  1262 		    __r = __c->_M_right;
  1263 		} else {
  1264 		    __r = __left;
  1265 		}
  1266 	    }
  1267 	    break;
  1268 	case _RopeRep::_S_leaf:
  1269 	    {
  1270 		_RopeLeaf* __l = (_RopeLeaf*)__r;
  1271 		return __l->_M_data[__i];
  1272 	    }
  1273 	case _RopeRep::_S_function:
  1274 	case _RopeRep::_S_substringfn:
  1275 	    {
  1276 		_RopeFunction* __f = (_RopeFunction*)__r;
  1277 		_CharT __result;
  1278 
  1279 		(*(__f->_M_fn))(__i, 1, &__result);
  1280 		return __result;
  1281 	    }
  1282       }
  1283     }
  1284 #if defined(_STLP_NEED_UNREACHABLE_RETURN)
  1285     return 0;
  1286 #endif
  1287 }
  1288 
  1289 # ifndef __GC
  1290 // Return a uniquely referenced character slot for the given
  1291 // position, or 0 if that's not possible.
  1292 template <class _CharT, class _Alloc>
  1293 _CharT*
  1294 rope<_CharT,_Alloc>::_S_fetch_ptr(_RopeRep* __r, size_type __i)
  1295 {
  1296     _RopeRep* __clrstack[_RopeRep::_S_max_rope_depth];
  1297     size_t __csptr = 0;
  1298 
  1299     for(;;) {
  1300       if (__r->_M_ref_count > 1) return 0;
  1301       switch(__r->_M_tag) {
  1302 	case _RopeRep::_S_concat:
  1303 	    {
  1304 		_RopeConcatenation* __c = (_RopeConcatenation*)__r;
  1305 		_RopeRep* __left = __c->_M_left;
  1306 		size_t __left_len = __left->_M_size._M_data;
  1307 
  1308 		if (__c->_M_c_string != 0) __clrstack[__csptr++] = __c;
  1309 		if (__i >= __left_len) {
  1310 		    __i -= __left_len;
  1311 		    __r = __c->_M_right;
  1312 		} else {
  1313 		    __r = __left;
  1314 		}
  1315 	    }
  1316 	    break;
  1317 	case _RopeRep::_S_leaf:
  1318 	    {
  1319 		_RopeLeaf* __l = (_RopeLeaf*)__r;
  1320 		if (__l->_M_c_string != __l->_M_data && __l->_M_c_string != 0)
  1321 		    __clrstack[__csptr++] = __l;
  1322 		while (__csptr > 0) {
  1323 		    -- __csptr;
  1324 		    _RopeRep* __d = __clrstack[__csptr];
  1325 		    __d->_M_free_c_string();
  1326 		    __d->_M_c_string = 0;
  1327 		}
  1328 		return __l->_M_data + __i;
  1329 	    }
  1330 	case _RopeRep::_S_function:
  1331 	case _RopeRep::_S_substringfn:
  1332 	    return 0;
  1333       }
  1334     }
  1335 #if defined(_STLP_NEED_UNREACHABLE_RETURN)
  1336     return 0;
  1337 #endif
  1338 
  1339 }
  1340 # endif /* __GC */
  1341 
  1342 // The following could be implemented trivially using
  1343 // lexicographical_compare_3way.
  1344 // We do a little more work to avoid dealing with rope iterators for
  1345 // flat strings.
  1346 template <class _CharT, class _Alloc>
  1347 int
  1348 rope<_CharT,_Alloc>::_S_compare (const _RopeRep* __left, 
  1349                                  const _RopeRep* __right)
  1350 {
  1351     size_t __left_len;
  1352     size_t __right_len;
  1353 
  1354     if (0 == __right) return 0 != __left;
  1355     if (0 == __left) return -1;
  1356     __left_len = __left->_M_size._M_data;
  1357     __right_len = __right->_M_size._M_data;
  1358     if (_RopeRep::_S_leaf == __left->_M_tag) {
  1359 	_RopeLeaf* __l = (_RopeLeaf*) __left;
  1360 	if (_RopeRep::_S_leaf == __right->_M_tag) {
  1361 	    _RopeLeaf* __r = (_RopeLeaf*) __right;
  1362 	    return lexicographical_compare_3way(
  1363 			__l->_M_data, __l->_M_data + __left_len,
  1364 			__r->_M_data, __r->_M_data + __right_len);
  1365 	} else {
  1366 	    const_iterator __rstart(__right, 0);
  1367 	    const_iterator __rend(__right, __right_len);
  1368 	    return lexicographical_compare_3way(
  1369 			__l->_M_data, __l->_M_data + __left_len,
  1370 			__rstart, __rend);
  1371 	}
  1372     } else {
  1373 	const_iterator __lstart(__left, 0);
  1374 	const_iterator __lend(__left, __left_len);
  1375 	if (_RopeRep::_S_leaf == __right->_M_tag) {
  1376 	    _RopeLeaf* __r = (_RopeLeaf*) __right;
  1377 	    return lexicographical_compare_3way(
  1378 				   __lstart, __lend,
  1379 				   __r->_M_data, __r->_M_data + __right_len);
  1380 	} else {
  1381 	    const_iterator __rstart(__right, 0);
  1382 	    const_iterator __rend(__right, __right_len);
  1383 	    return lexicographical_compare_3way(
  1384 				   __lstart, __lend,
  1385 				   __rstart, __rend);
  1386 	}
  1387     }
  1388 }
  1389 
  1390 // Assignment to reference proxies.
  1391 template <class _CharT, class _Alloc>
  1392 _Rope_char_ref_proxy<_CharT, _Alloc>&
  1393 _Rope_char_ref_proxy<_CharT, _Alloc>::operator= (_CharT __c) {
  1394     _RopeRep* __old = _M_root->_M_tree_ptr._M_data;
  1395 #   ifndef __GC
  1396 	// First check for the case in which everything is uniquely
  1397 	// referenced.  In that case we can do this destructively.
  1398 	_CharT* __ptr = _My_rope::_S_fetch_ptr(__old, _M_pos);
  1399 	if (0 != __ptr) {
  1400 	    *__ptr = __c;
  1401 	    return *this;
  1402 	}
  1403 #   endif
  1404     _Self_destruct_ptr __left(
  1405       _My_rope::_S_substring(__old, 0, _M_pos));
  1406     _Self_destruct_ptr __right(
  1407       _My_rope::_S_substring(__old, _M_pos+1, __old->_M_size._M_data));
  1408     _Self_destruct_ptr __result_left(
  1409       _My_rope::_S_destr_concat_char_iter(__left, &__c, 1));
  1410 
  1411 #   ifndef __GC
  1412       _STLP_ASSERT(__left == __result_left || 1 == __result_left->_M_ref_count)
  1413 #   endif
  1414     _RopeRep* __result =
  1415       _My_rope::_S_concat_rep(__result_left, __right);
  1416 #   ifndef __GC
  1417       _STLP_ASSERT(1 <= __result->_M_ref_count)
  1418       _RopeRep::_S_unref(__old);
  1419 #   endif
  1420     _M_root->_M_tree_ptr._M_data = __result;
  1421     return *this;
  1422 }
  1423 
  1424 template <class _CharT, class _Alloc>
  1425 _Rope_char_ptr_proxy<_CharT, _Alloc>
  1426 _Rope_char_ref_proxy<_CharT, _Alloc>::operator& () const {
  1427     return _Rope_char_ptr_proxy<_CharT, _Alloc>(*this);
  1428 }
  1429 
  1430 # if ( _STLP_STATIC_TEMPLATE_DATA > 0 )
  1431 template<class _CharT, class _Alloc>
  1432 _CharT rope<_CharT,_Alloc>::_S_empty_c_str[1] = { _CharT() };
  1433 # else
  1434 __DECLARE_INSTANCE(char, crope::_S_empty_c_str[1], ={0});
  1435 # ifdef _STLP_HAS_WCHAR_T
  1436 __DECLARE_INSTANCE(wchar_t, wrope::_S_empty_c_str[1], ={0});
  1437 # endif /* _STLP_HAS_WCHAR_T */
  1438 # endif /* _STLP_STATIC_TEMPLATE_DATA */
  1439 // # endif
  1440 
  1441 template<class _CharT, class _Alloc>
  1442 const _CharT* rope<_CharT,_Alloc>::c_str() const {
  1443     if (0 == _M_tree_ptr._M_data) {
  1444         _S_empty_c_str[0] = _S_eos((_CharT*)0);  // Possibly redundant,
  1445 					     // but probably fast.
  1446         return _S_empty_c_str;
  1447     }
  1448     __GC_CONST _CharT* __old_c_string = _M_tree_ptr._M_data->_M_c_string;
  1449     if (0 != __old_c_string) return(__old_c_string);
  1450     size_t __s = size();
  1451    _CharT* __result = _STLP_CREATE_ALLOCATOR(allocator_type,(const allocator_type&)_M_tree_ptr, _CharT).allocate(__s + 1);
  1452     _S_flatten(_M_tree_ptr._M_data, __result);
  1453     __result[__s] = _S_eos((_CharT*)0);
  1454 #   ifdef __GC
  1455 	_M_tree_ptr._M_data->_M_c_string = __result;
  1456 #   else
  1457       if ((__old_c_string = (__GC_CONST _CharT*)
  1458 	   _Atomic_swap((__stl_atomic_t *)(&(_M_tree_ptr._M_data->_M_c_string)),
  1459 			(__stl_atomic_t)__result)) != 0) {
  1460 	// It must have been added in the interim.  Hence it had to have been
  1461 	// separately allocated.  Deallocate the old copy, since we just
  1462 	// replaced it.
  1463 	_STLP_STD::_Destroy(__old_c_string, __old_c_string + __s + 1);
  1464       _STLP_CREATE_ALLOCATOR(allocator_type,(const allocator_type&)_M_tree_ptr, _CharT).deallocate(__old_c_string, __s + 1);
  1465       }
  1466 #   endif
  1467     return(__result);
  1468 }
  1469 
  1470 template<class _CharT, class _Alloc>
  1471 const _CharT* rope<_CharT,_Alloc>::replace_with_c_str() {
  1472     if (0 == _M_tree_ptr._M_data) {
  1473         _S_empty_c_str[0] = _S_eos((_CharT*)0);
  1474         return _S_empty_c_str;
  1475     }
  1476     __GC_CONST _CharT* __old_c_string = _M_tree_ptr._M_data->_M_c_string;
  1477     if (_RopeRep::_S_leaf == _M_tree_ptr._M_data->_M_tag && 0 != __old_c_string) {
  1478 	return(__old_c_string);
  1479     }
  1480     size_t __s = size();
  1481     _CharT* __result = _M_tree_ptr.allocate(_S_rounded_up_size(__s));
  1482     _S_flatten(_M_tree_ptr._M_data, __result);
  1483     __result[__s] = _S_eos((_CharT*)0);
  1484     _M_tree_ptr._M_data->_M_unref_nonnil();
  1485     _M_tree_ptr._M_data = _S_new_RopeLeaf(__result, __s, get_allocator());
  1486     return(__result);
  1487 }
  1488 
  1489 // Algorithm specializations.  More should be added.
  1490 
  1491 #ifndef _STLP_MSVC
  1492 // I couldn't get this to work with VC++
  1493 template<class _CharT,class _Alloc>
  1494 void
  1495 _Rope_rotate(_Rope_iterator<_CharT,_Alloc> __first,
  1496               _Rope_iterator<_CharT,_Alloc> __middle,
  1497               _Rope_iterator<_CharT,_Alloc> __last)
  1498 {
  1499     _STLP_ASSERT(__first.container() == __middle.container()
  1500                  && __middle.container() == __last.container())
  1501     rope<_CharT,_Alloc>& __r(__first.container());
  1502     rope<_CharT,_Alloc> __prefix = __r.substr(0, __first.index());
  1503     rope<_CharT,_Alloc> __suffix = 
  1504       __r.substr(__last.index(), __r.size() - __last.index());
  1505     rope<_CharT,_Alloc> __part1 = 
  1506       __r.substr(__middle.index(), __last.index() - __middle.index());
  1507     rope<_CharT,_Alloc> __part2 = 
  1508       __r.substr(__first.index(), __middle.index() - __first.index());
  1509     __r = __prefix;
  1510     __r += __part1;
  1511     __r += __part2;
  1512     __r += __suffix;
  1513 }
  1514 
  1515 
  1516 # if 0
  1517 // Probably not useful for several reasons:
  1518 // - for SGIs 7.1 compiler and probably some others,
  1519 //   this forces lots of rope<wchar_t, ...> instantiations, creating a
  1520 //   code bloat and compile time problem.  (Fixed in 7.2.)
  1521 // - wchar_t is 4 bytes wide on most UNIX platforms, making it unattractive
  1522 //   for unicode strings.  Unsigned short may be a better character
  1523 //   type.
  1524 inline void rotate(
  1525 		_Rope_iterator<wchar_t,_STLP_DEFAULT_ALLOCATOR(char) > __first,
  1526                 _Rope_iterator<wchar_t,_STLP_DEFAULT_ALLOCATOR(char) > __middle,
  1527                 _Rope_iterator<wchar_t,_STLP_DEFAULT_ALLOCATOR(char) > __last) {
  1528     _Rope_rotate(__first, __middle, __last);
  1529 }
  1530 # endif
  1531 #endif /* _STLP_MSVC */
  1532 
  1533 #   undef __RopeLeaf__ 
  1534 #   undef __RopeRep__ 
  1535 #   undef __RopeLeaf 
  1536 #   undef __RopeRep 
  1537 #   undef size_type
  1538 
  1539 _STLP_END_NAMESPACE
  1540 
  1541 # endif /* ROPEIMPL_H */
  1542 
  1543 // Local Variables:
  1544 // mode:C++
  1545 // End: