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