Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

ropeimpl.h

Go to the documentation of this file.
00001 // SGI's rope class implementation -*- C++ -*-
00002 
00003 // Copyright (C) 2001 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 2, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // You should have received a copy of the GNU General Public License along
00017 // with this library; see the file COPYING.  If not, write to the Free
00018 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00019 // USA.
00020 
00021 // As a special exception, you may use this file as part of a free software
00022 // library without restriction.  Specifically, if other files instantiate
00023 // templates or use macros or inline functions from this file, or you compile
00024 // this file and link it with other files to produce an executable, this
00025 // file does not by itself cause the resulting executable to be covered by
00026 // the GNU General Public License.  This exception does not however
00027 // invalidate any other reasons why the executable file might be covered by
00028 // the GNU General Public License.
00029 
00030 /*
00031  * Copyright (c) 1997
00032  * Silicon Graphics Computer Systems, Inc.
00033  *
00034  * Permission to use, copy, modify, distribute and sell this software
00035  * and its documentation for any purpose is hereby granted without fee,
00036  * provided that the above copyright notice appear in all copies and
00037  * that both that copyright notice and this permission notice appear
00038  * in supporting documentation.  Silicon Graphics makes no
00039  * representations about the suitability of this software for any
00040  * purpose.  It is provided "as is" without express or implied warranty.
00041  */
00042 
00043 /* NOTE: This is an internal header file, included by other STL headers.
00044  *   You should not attempt to use it directly.
00045  */
00046 
00047 #include <bits/std_cstdio.h>     
00048 #include <bits/std_iostream.h>
00049 
00050 #ifdef __STL_USE_EXCEPTIONS
00051 # include <bits/std_stdexcept.h>
00052 #endif
00053 
00054 namespace std
00055 {
00056 
00057 // Set buf_start, buf_end, and buf_ptr appropriately, filling tmp_buf
00058 // if necessary.  Assumes _M_path_end[leaf_index] and leaf_pos are correct.
00059 // Results in a valid buf_ptr if the iterator can be legitimately
00060 // dereferenced.
00061 template <class _CharT, class _Alloc>
00062 void _Rope_iterator_base<_CharT,_Alloc>::_S_setbuf( 
00063   _Rope_iterator_base<_CharT,_Alloc>& __x)
00064 {
00065     const _RopeRep* __leaf = __x._M_path_end[__x._M_leaf_index];
00066     size_t __leaf_pos = __x._M_leaf_pos;
00067     size_t __pos = __x._M_current_pos;
00068 
00069     switch(__leaf->_M_tag) {
00070     case _RopeRep::_S_leaf:
00071         __x._M_buf_start = 
00072           ((_Rope_RopeLeaf<_CharT,_Alloc>*)__leaf)->_M_data;
00073         __x._M_buf_ptr = __x._M_buf_start + (__pos - __leaf_pos);
00074         __x._M_buf_end = __x._M_buf_start + __leaf->_M_size;
00075         break;
00076     case _RopeRep::_S_function:
00077     case _RopeRep::_S_substringfn:
00078         {
00079         size_t __len = _S_iterator_buf_len;
00080         size_t __buf_start_pos = __leaf_pos;
00081         size_t __leaf_end = __leaf_pos + __leaf->_M_size;
00082         char_producer<_CharT>* __fn =
00083             ((_Rope_RopeFunction<_CharT,_Alloc>*)__leaf)->_M_fn;
00084 
00085         if (__buf_start_pos + __len <= __pos) {
00086             __buf_start_pos = __pos - __len/4;
00087             if (__buf_start_pos + __len > __leaf_end) {
00088             __buf_start_pos = __leaf_end - __len;
00089             }
00090         }
00091         if (__buf_start_pos + __len > __leaf_end) {
00092             __len = __leaf_end - __buf_start_pos;
00093         }
00094         (*__fn)(__buf_start_pos - __leaf_pos, __len, __x._M_tmp_buf);
00095         __x._M_buf_ptr = __x._M_tmp_buf + (__pos - __buf_start_pos);
00096         __x._M_buf_start = __x._M_tmp_buf;
00097         __x._M_buf_end = __x._M_tmp_buf + __len;
00098         }
00099         break;
00100     default:
00101         __stl_assert(0);
00102     }
00103 }
00104 
00105 // Set path and buffer inside a rope iterator.  We assume that 
00106 // pos and root are already set.
00107 template <class _CharT, class _Alloc>
00108 void _Rope_iterator_base<_CharT,_Alloc>::_S_setcache
00109 (_Rope_iterator_base<_CharT,_Alloc>& __x)
00110 {
00111     const _RopeRep* __path[_RopeRep::_S_max_rope_depth+1];
00112     const _RopeRep* __curr_rope;
00113     int __curr_depth = -1;  /* index into path    */
00114     size_t __curr_start_pos = 0;
00115     size_t __pos = __x._M_current_pos;
00116     unsigned char __dirns = 0; // Bit vector marking right turns in the path
00117 
00118     __stl_assert(__pos <= __x._M_root->_M_size);
00119     if (__pos >= __x._M_root->_M_size) {
00120     __x._M_buf_ptr = 0;
00121     return;
00122     }
00123     __curr_rope = __x._M_root;
00124     if (0 != __curr_rope->_M_c_string) {
00125     /* Treat the root as a leaf. */
00126     __x._M_buf_start = __curr_rope->_M_c_string;
00127     __x._M_buf_end = __curr_rope->_M_c_string + __curr_rope->_M_size;
00128     __x._M_buf_ptr = __curr_rope->_M_c_string + __pos;
00129     __x._M_path_end[0] = __curr_rope;
00130     __x._M_leaf_index = 0;
00131     __x._M_leaf_pos = 0;
00132     return;
00133     }
00134     for(;;) {
00135     ++__curr_depth;
00136     __stl_assert(__curr_depth <= _RopeRep::_S_max_rope_depth);
00137     __path[__curr_depth] = __curr_rope;
00138     switch(__curr_rope->_M_tag) {
00139       case _RopeRep::_S_leaf:
00140       case _RopeRep::_S_function:
00141       case _RopeRep::_S_substringfn:
00142         __x._M_leaf_pos = __curr_start_pos;
00143         goto done;
00144       case _RopeRep::_S_concat:
00145         {
00146         _Rope_RopeConcatenation<_CharT,_Alloc>* __c =
00147             (_Rope_RopeConcatenation<_CharT,_Alloc>*)__curr_rope;
00148         _RopeRep* __left = __c->_M_left;
00149         size_t __left_len = __left->_M_size;
00150         
00151         __dirns <<= 1;
00152         if (__pos >= __curr_start_pos + __left_len) {
00153             __dirns |= 1;
00154             __curr_rope = __c->_M_right;
00155             __curr_start_pos += __left_len;
00156         } else {
00157             __curr_rope = __left;
00158         }
00159         }
00160         break;
00161     }
00162     }
00163   done:
00164     // Copy last section of path into _M_path_end.
00165       {
00166     int __i = -1;
00167     int __j = __curr_depth + 1 - _S_path_cache_len;
00168 
00169     if (__j < 0) __j = 0;
00170     while (__j <= __curr_depth) {
00171         __x._M_path_end[++__i] = __path[__j++];
00172     }
00173     __x._M_leaf_index = __i;
00174       }
00175       __x._M_path_directions = __dirns;
00176       _S_setbuf(__x);
00177 }
00178 
00179 // Specialized version of the above.  Assumes that
00180 // the path cache is valid for the previous position.
00181 template <class _CharT, class _Alloc>
00182 void _Rope_iterator_base<_CharT,_Alloc>::_S_setcache_for_incr
00183 (_Rope_iterator_base<_CharT,_Alloc>& __x)
00184 {
00185     int __current_index = __x._M_leaf_index;
00186     const _RopeRep* __current_node = __x._M_path_end[__current_index];
00187     size_t __len = __current_node->_M_size;
00188     size_t __node_start_pos = __x._M_leaf_pos;
00189     unsigned char __dirns = __x._M_path_directions;
00190     _Rope_RopeConcatenation<_CharT,_Alloc>* __c;
00191 
00192     __stl_assert(__x._M_current_pos <= __x._M_root->_M_size);
00193     if (__x._M_current_pos - __node_start_pos < __len) {
00194     /* More stuff in this leaf, we just didn't cache it. */
00195     _S_setbuf(__x);
00196     return;
00197     }
00198     __stl_assert(__node_start_pos + __len == __x._M_current_pos);
00199     //  node_start_pos is starting position of last_node.
00200     while (--__current_index >= 0) {
00201     if (!(__dirns & 1) /* Path turned left */) 
00202       break;
00203     __current_node = __x._M_path_end[__current_index];
00204     __c = (_Rope_RopeConcatenation<_CharT,_Alloc>*)__current_node;
00205     // Otherwise we were in the right child.  Thus we should pop
00206     // the concatenation node.
00207     __node_start_pos -= __c->_M_left->_M_size;
00208     __dirns >>= 1;
00209     }
00210     if (__current_index < 0) {
00211     // We underflowed the cache. Punt.
00212     _S_setcache(__x);
00213     return;
00214     }
00215     __current_node = __x._M_path_end[__current_index];
00216     __c = (_Rope_RopeConcatenation<_CharT,_Alloc>*)__current_node;
00217     // current_node is a concatenation node.  We are positioned on the first
00218     // character in its right child.
00219     // node_start_pos is starting position of current_node.
00220     __node_start_pos += __c->_M_left->_M_size;
00221     __current_node = __c->_M_right;
00222     __x._M_path_end[++__current_index] = __current_node;
00223     __dirns |= 1;
00224     while (_RopeRep::_S_concat == __current_node->_M_tag) {
00225     ++__current_index;
00226     if (_S_path_cache_len == __current_index) {
00227         int __i;
00228         for (__i = 0; __i < _S_path_cache_len-1; __i++) {
00229         __x._M_path_end[__i] = __x._M_path_end[__i+1];
00230         }
00231         --__current_index;
00232     }
00233     __current_node =
00234         ((_Rope_RopeConcatenation<_CharT,_Alloc>*)__current_node)->_M_left;
00235     __x._M_path_end[__current_index] = __current_node;
00236     __dirns <<= 1;
00237     // node_start_pos is unchanged.
00238     }
00239     __x._M_leaf_index = __current_index;
00240     __x._M_leaf_pos = __node_start_pos;
00241     __x._M_path_directions = __dirns;
00242     _S_setbuf(__x);
00243 }
00244 
00245 template <class _CharT, class _Alloc>
00246 void _Rope_iterator_base<_CharT,_Alloc>::_M_incr(size_t __n) {
00247     _M_current_pos += __n;
00248     if (0 != _M_buf_ptr) {
00249         size_t __chars_left = _M_buf_end - _M_buf_ptr;
00250         if (__chars_left > __n) {
00251             _M_buf_ptr += __n;
00252         } else if (__chars_left == __n) {
00253             _M_buf_ptr += __n;
00254             _S_setcache_for_incr(*this);
00255         } else {
00256             _M_buf_ptr = 0;
00257         }
00258     }
00259 }
00260 
00261 template <class _CharT, class _Alloc>
00262 void _Rope_iterator_base<_CharT,_Alloc>::_M_decr(size_t __n) {
00263     if (0 != _M_buf_ptr) {
00264         size_t __chars_left = _M_buf_ptr - _M_buf_start;
00265         if (__chars_left >= __n) {
00266             _M_buf_ptr -= __n;
00267         } else {
00268             _M_buf_ptr = 0;
00269         }
00270     }
00271     _M_current_pos -= __n;
00272 }
00273 
00274 template <class _CharT, class _Alloc>
00275 void _Rope_iterator<_CharT,_Alloc>::_M_check() {
00276     if (_M_root_rope->_M_tree_ptr != _M_root) {
00277         // _Rope was modified.  Get things fixed up.
00278         _RopeRep::_S_unref(_M_root);
00279         _M_root = _M_root_rope->_M_tree_ptr;
00280         _RopeRep::_S_ref(_M_root);
00281         _M_buf_ptr = 0;
00282     }
00283 }
00284 
00285 template <class _CharT, class _Alloc>
00286 inline 
00287 _Rope_const_iterator<_CharT, _Alloc>::_Rope_const_iterator(
00288   const _Rope_iterator<_CharT,_Alloc>& __x)
00289 : _Rope_iterator_base<_CharT,_Alloc>(__x) 
00290 { }
00291 
00292 template <class _CharT, class _Alloc>
00293 inline _Rope_iterator<_CharT,_Alloc>::_Rope_iterator(
00294   rope<_CharT,_Alloc>& __r, size_t __pos)
00295 : _Rope_iterator_base<_CharT,_Alloc>(__r._M_tree_ptr, __pos), 
00296   _M_root_rope(&__r)
00297 {
00298     _RopeRep::_S_ref(_M_root);
00299 }
00300 
00301 template <class _CharT, class _Alloc>
00302 inline size_t 
00303 rope<_CharT,_Alloc>::_S_char_ptr_len(const _CharT* __s)
00304 {
00305     const _CharT* __p = __s;
00306 
00307     while (!_S_is0(*__p)) { ++__p; }
00308     return (__p - __s);
00309 }
00310 
00311 
00312 #ifndef __GC
00313 
00314 template <class _CharT, class _Alloc>
00315 inline void _Rope_RopeRep<_CharT,_Alloc>::_M_free_c_string()
00316 {
00317     _CharT* __cstr = _M_c_string;
00318     if (0 != __cstr) {
00319     size_t __size = _M_size + 1;
00320     destroy(__cstr, __cstr + __size);
00321     _Data_deallocate(__cstr, __size);
00322     }
00323 }
00324 
00325 
00326 template <class _CharT, class _Alloc>
00327   inline void _Rope_RopeRep<_CharT,_Alloc>::_S_free_string(_CharT* __s,
00328                                size_t __n,
00329                                    allocator_type __a)
00330 {
00331     if (!_S_is_basic_char_type((_CharT*)0)) {
00332     destroy(__s, __s + __n);
00333     }
00334 //  This has to be a static member, so this gets a bit messy
00335         __a.deallocate(
00336         __s, _Rope_RopeLeaf<_CharT,_Alloc>::_S_rounded_up_size(__n));
00337 }
00338 
00339 
00340 //  There are several reasons for not doing this with virtual destructors
00341 //  and a class specific delete operator:
00342 //  - A class specific delete operator can't easily get access to
00343 //    allocator instances if we need them.
00344 //  - Any virtual function would need a 4 or byte vtable pointer;
00345 //    this only requires a one byte tag per object.
00346 template <class _CharT, class _Alloc>
00347 void _Rope_RopeRep<_CharT,_Alloc>::_M_free_tree()
00348 {
00349     switch(_M_tag) {
00350     case _S_leaf:
00351         {
00352             _Rope_RopeLeaf<_CharT,_Alloc>* __l
00353             = (_Rope_RopeLeaf<_CharT,_Alloc>*)this;
00354             __l->_Rope_RopeLeaf<_CharT,_Alloc>::~_Rope_RopeLeaf();
00355             _L_deallocate(__l, 1);
00356             break;
00357         }
00358     case _S_concat:
00359         {
00360             _Rope_RopeConcatenation<_CharT,_Alloc>* __c
00361             = (_Rope_RopeConcatenation<_CharT,_Alloc>*)this;
00362             __c->_Rope_RopeConcatenation<_CharT,_Alloc>::
               ~_Rope_RopeConcatenation();
00363             _C_deallocate(__c, 1);
00364             break;
00365         }
00366     case _S_function:
00367         {
00368             _Rope_RopeFunction<_CharT,_Alloc>* __f
00369             = (_Rope_RopeFunction<_CharT,_Alloc>*)this;
00370             __f->_Rope_RopeFunction<_CharT,_Alloc>::~_Rope_RopeFunction();
00371             _F_deallocate(__f, 1);
00372             break;
00373         }
00374     case _S_substringfn:
00375         {
00376             _Rope_RopeSubstring<_CharT,_Alloc>* __ss =
00377             (_Rope_RopeSubstring<_CharT,_Alloc>*)this;
00378         __ss->_Rope_RopeSubstring<_CharT,_Alloc>::
                ~_Rope_RopeSubstring();
00379         _S_deallocate(__ss, 1);
00380         break;
00381         }
00382     }
00383 }
00384 #else
00385 
00386 template <class _CharT, class _Alloc>
00387   inline void _Rope_RopeRep<_CharT,_Alloc>::_S_free_string
00388         (const _CharT*, size_t, allocator_type)
00389 {}
00390 
00391 #endif
00392 
00393 
00394 // Concatenate a C string onto a leaf rope by copying the rope data.
00395 // Used for short ropes.
00396 template <class _CharT, class _Alloc>
00397 rope<_CharT,_Alloc>::_RopeLeaf*
00398 rope<_CharT,_Alloc>::_S_leaf_concat_char_iter
00399         (_RopeLeaf* __r, const _CharT* __iter, size_t __len)
00400 {
00401     size_t __old_len = __r->_M_size;
00402     _CharT* __new_data = (_CharT*)
00403     _Data_allocate(_S_rounded_up_size(__old_len + __len));
00404     _RopeLeaf* __result;
00405     
00406     uninitialized_copy_n(__r->_M_data, __old_len, __new_data);
00407     uninitialized_copy_n(__iter, __len, __new_data + __old_len);
00408     _S_cond_store_eos(__new_data[__old_len + __len]);
00409     __STL_TRY {
00410     __result = _S_new_RopeLeaf(__new_data, __old_len + __len,
00411                    __r->get_allocator());
00412     }
00413     __STL_UNWIND(_RopeRep::__STL_FREE_STRING(__new_data, __old_len + __len,
00414                          __r->get_allocator()));
00415     return __result;
00416 }
00417 
00418 #ifndef __GC
00419 // As above, but it's OK to clobber original if refcount is 1
00420 template <class _CharT, class _Alloc>
00421 rope<_CharT,_Alloc>::_RopeLeaf*
00422 rope<_CharT,_Alloc>::_S_destr_leaf_concat_char_iter
00423         (_RopeLeaf* __r, const _CharT* __iter, size_t __len)
00424 {
00425     __stl_assert(__r->_M_ref_count >= 1);
00426     if (__r->_M_ref_count > 1)
00427       return _S_leaf_concat_char_iter(__r, __iter, __len);
00428     size_t __old_len = __r->_M_size;
00429     if (_S_allocated_capacity(__old_len) >= __old_len + __len) {
00430     // The space has been partially initialized for the standard
00431     // character types.  But that doesn't matter for those types.
00432     uninitialized_copy_n(__iter, __len, __r->_M_data + __old_len);
00433     if (_S_is_basic_char_type((_CharT*)0)) {
00434         _S_cond_store_eos(__r->_M_data[__old_len + __len]);
00435         __stl_assert(__r->_M_c_string == __r->_M_data);
00436     } else if (__r->_M_c_string != __r->_M_data && 0 != __r->_M_c_string) {
00437         __r->_M_free_c_string();
00438         __r->_M_c_string = 0;
00439     }
00440     __r->_M_size = __old_len + __len;
00441     __stl_assert(__r->_M_ref_count == 1);
00442     __r->_M_ref_count = 2;
00443     return __r;
00444     } else {
00445     _RopeLeaf* __result = _S_leaf_concat_char_iter(__r, __iter, __len);
00446     __stl_assert(__result->_M_ref_count == 1);
00447     return __result;
00448     }
00449 }
00450 #endif
00451 
00452 // Assumes left and right are not 0.
00453 // Does not increment (nor decrement on exception) child reference counts.
00454 // Result has ref count 1.
00455 template <class _CharT, class _Alloc>
00456 rope<_CharT,_Alloc>::_RopeRep*
00457 rope<_CharT,_Alloc>::_S_tree_concat (_RopeRep* __left, _RopeRep* __right)
00458 {
00459     _RopeConcatenation* __result =
00460       _S_new_RopeConcatenation(__left, __right, __left->get_allocator());
00461     size_t __depth = __result->_M_depth;
00462     
00463       __stl_assert(__left->get_allocator() == __right->get_allocator());
00464     if (__depth > 20 && (__result->_M_size < 1000 ||
00465              __depth > _RopeRep::_S_max_rope_depth)) {
00466         _RopeRep* __balanced;
00467       
00468     __STL_TRY {
00469        __balanced = _S_balance(__result);
00470 #          ifndef __GC
00471          if (__result != __balanced) {
00472         __stl_assert(1 == __result->_M_ref_count
00473                  && 1 == __balanced->_M_ref_count);
00474          }
00475 #          endif
00476        __result->_M_unref_nonnil();
00477         }
00478     __STL_UNWIND((_C_deallocate(__result,1)));
00479         // In case of exception, we need to deallocate
00480         // otherwise dangling result node.  But caller
00481         // still owns its children.  Thus unref is
00482         // inappropriate.
00483     return __balanced;
00484     } else {
00485     return __result;
00486     }
00487 }
00488 
00489 template <class _CharT, class _Alloc>
00490 rope<_CharT,_Alloc>::_RopeRep* rope<_CharT,_Alloc>::_S_concat_char_iter
00491         (_RopeRep* __r, const _CharT*__s, size_t __slen)
00492 {
00493     _RopeRep* __result;
00494     if (0 == __slen) {
00495     _S_ref(__r);
00496     return __r;
00497     }
00498     if (0 == __r)
00499       return __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen,
00500                           __r->get_allocator());
00501     if (_RopeRep::_S_leaf == __r->_M_tag && 
00502           __r->_M_size + __slen <= _S_copy_max) {
00503     __result = _S_leaf_concat_char_iter((_RopeLeaf*)__r, __s, __slen);
00504 #       ifndef __GC
00505       __stl_assert(1 == __result->_M_ref_count);
00506 #       endif
00507     return __result;
00508     }
00509     if (_RopeRep::_S_concat == __r->_M_tag
00510     && _RopeRep::_S_leaf == ((_RopeConcatenation*)__r)->_M_right->_M_tag) {
00511     _RopeLeaf* __right = 
00512       (_RopeLeaf* )(((_RopeConcatenation* )__r)->_M_right);
00513     if (__right->_M_size + __slen <= _S_copy_max) {
00514       _RopeRep* __left = ((_RopeConcatenation*)__r)->_M_left;
00515       _RopeRep* __nright = 
00516         _S_leaf_concat_char_iter((_RopeLeaf*)__right, __s, __slen);
00517       __left->_M_ref_nonnil();
00518       __STL_TRY {
00519         __result = _S_tree_concat(__left, __nright);
00520           }
00521       __STL_UNWIND(_S_unref(__left); _S_unref(__nright));
00522 #         ifndef __GC
00523         __stl_assert(1 == __result->_M_ref_count);
00524 #         endif
00525       return __result;
00526     }
00527     }
00528     _RopeRep* __nright =
00529       __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __r->get_allocator());
00530     __STL_TRY {
00531       __r->_M_ref_nonnil();
00532       __result = _S_tree_concat(__r, __nright);
00533     }
00534     __STL_UNWIND(_S_unref(__r); _S_unref(__nright));
00535 #   ifndef __GC
00536       __stl_assert(1 == __result->_M_ref_count);
00537 #   endif
00538     return __result;
00539 }
00540 
00541 #ifndef __GC
00542 template <class _CharT, class _Alloc>
00543 rope<_CharT,_Alloc>::_RopeRep* 
00544 rope<_CharT,_Alloc>::_S_destr_concat_char_iter(
00545   _RopeRep* __r, const _CharT* __s, size_t __slen)
00546 {
00547     _RopeRep* __result;
00548     if (0 == __r)
00549       return __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen,
00550                           __r->get_allocator());
00551     size_t __count = __r->_M_ref_count;
00552     size_t __orig_size = __r->_M_size;
00553     __stl_assert(__count >= 1);
00554     if (__count > 1) return _S_concat_char_iter(__r, __s, __slen);
00555     if (0 == __slen) {
00556     __r->_M_ref_count = 2;      // One more than before
00557     return __r;
00558     }
00559     if (__orig_size + __slen <= _S_copy_max && 
00560           _RopeRep::_S_leaf == __r->_M_tag) {
00561     __result = _S_destr_leaf_concat_char_iter((_RopeLeaf*)__r, __s, __slen);
00562     return __result;
00563     }
00564     if (_RopeRep::_S_concat == __r->_M_tag) {
00565     _RopeLeaf* __right = (_RopeLeaf*)(((_RopeConcatenation*)__r)->_M_right);
00566     if (_RopeRep::_S_leaf == __right->_M_tag
00567         && __right->_M_size + __slen <= _S_copy_max) {
00568       _RopeRep* __new_right = 
00569         _S_destr_leaf_concat_char_iter(__right, __s, __slen);
00570       if (__right == __new_right) {
00571           __stl_assert(__new_right->_M_ref_count == 2);
00572           __new_right->_M_ref_count = 1;
00573       } else {
00574           __stl_assert(__new_right->_M_ref_count >= 1);
00575           __right->_M_unref_nonnil();
00576       }
00577       __stl_assert(__r->_M_ref_count == 1);
00578       __r->_M_ref_count = 2;    // One more than before.
00579       ((_RopeConcatenation*)__r)->_M_right = __new_right;
00580       __r->_M_size = __orig_size + __slen;
00581       if (0 != __r->_M_c_string) {
00582           __r->_M_free_c_string();
00583           __r->_M_c_string = 0;
00584       }
00585       return __r;
00586     }
00587     }
00588     _RopeRep* __right =
00589       __STL_ROPE_FROM_UNOWNED_CHAR_PTR(__s, __slen, __r->get_allocator());
00590     __r->_M_ref_nonnil();
00591     __STL_TRY {
00592       __result = _S_tree_concat(__r, __right);
00593     }
00594     __STL_UNWIND(_S_unref(__r); _S_unref(__right))
00595     __stl_assert(1 == __result->_M_ref_count);
00596     return __result;
00597 }
00598 #endif /* !__GC */
00599 
00600 template <class _CharT, class _Alloc>
00601 rope<_CharT,_Alloc>::_RopeRep*
00602 rope<_CharT,_Alloc>::_S_concat(_RopeRep* __left, _RopeRep* __right)
00603 {
00604     if (0 == __left) {
00605     _S_ref(__right);
00606     return __right;
00607     }
00608     if (0 == __right) {
00609     __left->_M_ref_nonnil();
00610     return __left;
00611     }
00612     if (_RopeRep::_S_leaf == __right->_M_tag) {
00613     if (_RopeRep::_S_leaf == __left->_M_tag) {
00614       if (__right->_M_size + __left->_M_size <= _S_copy_max) {
00615         return _S_leaf_concat_char_iter((_RopeLeaf*)__left,
00616                      ((_RopeLeaf*)__right)->_M_data,
00617                      __right->_M_size);
00618       }
00619     } else if (_RopeRep::_S_concat == __left->_M_tag
00620            && _RopeRep::_S_leaf ==
00621               ((_RopeConcatenation*)__left)->_M_right->_M_tag) {
00622       _RopeLeaf* __leftright =
00623             (_RopeLeaf*)(((_RopeConcatenation*)__left)->_M_right); 
00624       if (__leftright->_M_size + __right->_M_size <= _S_copy_max) {
00625         _RopeRep* __leftleft = ((_RopeConcatenation*)__left)->_M_left;
00626         _RopeRep* __rest = _S_leaf_concat_char_iter(__leftright,
00627                        ((_RopeLeaf*)__right)->_M_data,
00628                        __right->_M_size);
00629         __leftleft->_M_ref_nonnil();
00630         __STL_TRY {
00631           return(_S_tree_concat(__leftleft, __rest));
00632             }
00633         __STL_UNWIND(_S_unref(__leftleft); _S_unref(__rest))
00634       }
00635     }
00636     }
00637     __left->_M_ref_nonnil();
00638     __right->_M_ref_nonnil();
00639     __STL_TRY {
00640       return(_S_tree_concat(__left, __right));
00641     }
00642     __STL_UNWIND(_S_unref(__left); _S_unref(__right));
00643 }
00644 
00645 template <class _CharT, class _Alloc>
00646 rope<_CharT,_Alloc>::_RopeRep*
00647 rope<_CharT,_Alloc>::_S_substring(_RopeRep* __base, 
00648                                size_t __start, size_t __endp1)
00649 {
00650     if (0 == __base) return 0;
00651     size_t __len = __base->_M_size;
00652     size_t __adj_endp1;
00653     const size_t __lazy_threshold = 128;
00654     
00655     if (__endp1 >= __len) {
00656     if (0 == __start) {
00657         __base->_M_ref_nonnil();
00658         return __base;
00659     } else {
00660         __adj_endp1 = __len;
00661     }
00662     } else {
00663     __adj_endp1 = __endp1;
00664     }
00665     switch(__base->_M_tag) {
00666     case _RopeRep::_S_concat:
00667         {
00668         _RopeConcatenation* __c = (_RopeConcatenation*)__base;
00669         _RopeRep* __left = __c->_M_left;
00670         _RopeRep* __right = __c->_M_right;
00671         size_t __left_len = __left->_M_size;
00672         _RopeRep* __result;
00673 
00674         if (__adj_endp1 <= __left_len) {
00675             return _S_substring(__left, __start, __endp1);
00676         } else if (__start >= __left_len) {
00677             return _S_substring(__right, __start - __left_len,
00678                   __adj_endp1 - __left_len);
00679         }
00680         _Self_destruct_ptr __left_result(
00681           _S_substring(__left, __start, __left_len));
00682         _Self_destruct_ptr __right_result(
00683           _S_substring(__right, 0, __endp1 - __left_len));
00684         __result = _S_concat(__left_result, __right_result);
00685 #               ifndef __GC
00686           __stl_assert(1 == __result->_M_ref_count);
00687 #               endif
00688         return __result;
00689         }
00690     case _RopeRep::_S_leaf:
00691         {
00692         _RopeLeaf* __l = (_RopeLeaf*)__base;
00693         _RopeLeaf* __result;
00694         size_t __result_len;
00695         if (__start >= __adj_endp1) return 0;
00696         __result_len = __adj_endp1 - __start;
00697         if (__result_len > __lazy_threshold) goto lazy;
00698 #               ifdef __GC
00699             const _CharT* __section = __l->_M_data + __start;
00700             __result = _S_new_RopeLeaf(__section, __result_len,
00701                       __base->get_allocator());
00702             __result->_M_c_string = 0;  // Not eos terminated.
00703 #               else
00704             // We should sometimes create substring node instead.
00705             __result = __STL_ROPE_FROM_UNOWNED_CHAR_PTR(
00706                     __l->_M_data + __start, __result_len,
00707                     __base->get_allocator());
00708 #               endif
00709         return __result;
00710         }
00711     case _RopeRep::_S_substringfn:
00712         // Avoid introducing multiple layers of substring nodes.
00713         {
00714         _RopeSubstring* __old = (_RopeSubstring*)__base;
00715         size_t __result_len;
00716         if (__start >= __adj_endp1) return 0;
00717         __result_len = __adj_endp1 - __start;
00718         if (__result_len > __lazy_threshold) {
00719             _RopeSubstring* __result =
00720             _S_new_RopeSubstring(__old->_M_base,
00721                       __start + __old->_M_start,
00722                       __adj_endp1 - __start,
00723                       __base->get_allocator());
00724             return __result;
00725 
00726         } // *** else fall through: ***
00727         }
00728     case _RopeRep::_S_function:
00729         {
00730         _RopeFunction* __f = (_RopeFunction*)__base;
00731         _CharT* __section;
00732         size_t __result_len;
00733         if (__start >= __adj_endp1) return 0;
00734         __result_len = __adj_endp1 - __start;
00735 
00736         if (__result_len > __lazy_threshold) goto lazy;
00737         __section = (_CharT*)
00738             _Data_allocate(_S_rounded_up_size(__result_len));
00739         __STL_TRY {
00740           (*(__f->_M_fn))(__start, __result_len, __section);
00741                 }
00742         __STL_UNWIND(_RopeRep::__STL_FREE_STRING(
00743                    __section, __result_len, __base->get_allocator()));
00744         _S_cond_store_eos(__section[__result_len]);
00745         return _S_new_RopeLeaf(__section, __result_len,
00746                        __base->get_allocator());
00747         }
00748     }
00749     /*NOTREACHED*/
00750     __stl_assert(false);
00751   lazy:
00752     {
00753     // Create substring node.
00754     return _S_new_RopeSubstring(__base, __start, __adj_endp1 - __start,
00755                    __base->get_allocator());
00756     }
00757 }
00758 
00759 template<class _CharT>
00760 class _Rope_flatten_char_consumer : public _Rope_char_consumer<_CharT> {
00761     private:
00762     _CharT* _M_buf_ptr;
00763     public:
00764 
00765     _Rope_flatten_char_consumer(_CharT* __buffer) {
00766         _M_buf_ptr = __buffer;
00767     };
00768     ~_Rope_flatten_char_consumer() {}
00769     bool operator() (const _CharT* __leaf, size_t __n) {
00770         uninitialized_copy_n(__leaf, __n, _M_buf_ptr);
00771         _M_buf_ptr += __n;
00772         return true;
00773     }
00774 };
00775         
00776 template<class _CharT>
00777 class _Rope_find_char_char_consumer : public _Rope_char_consumer<_CharT> {
00778     private:
00779     _CharT _M_pattern;
00780     public:
00781     size_t _M_count;  // Number of nonmatching characters
00782     _Rope_find_char_char_consumer(_CharT __p) 
00783       : _M_pattern(__p), _M_count(0) {}
00784     ~_Rope_find_char_char_consumer() {}
00785     bool operator() (const _CharT* __leaf, size_t __n) {
00786         size_t __i;
00787         for (__i = 0; __i < __n; __i++) {
00788         if (__leaf[__i] == _M_pattern) {
00789             _M_count += __i; return false;
00790         }
00791         }
00792         _M_count += __n; return true;
00793     }
00794 };
00795         
00796   template<class _CharT, class _Traits>
00797   // Here _CharT is both the stream and rope character type.
00798 class _Rope_insert_char_consumer : public _Rope_char_consumer<_CharT> {
00799     private:
00800       typedef basic_ostream<_CharT,_Traits> _Insert_ostream;
00801     _Insert_ostream& _M_o;
00802     public:
00803     _Rope_insert_char_consumer(_Insert_ostream& __writer) 
00804       : _M_o(__writer) {};
00805     ~_Rope_insert_char_consumer() { };
00806         // Caller is presumed to own the ostream
00807     bool operator() (const _CharT* __leaf, size_t __n);
00808         // Returns true to continue traversal.
00809 };
00810         
00811 template<class _CharT, class _Traits>
00812 bool _Rope_insert_char_consumer<_CharT, _Traits>::operator()
00813                                       (const _CharT* __leaf, size_t __n)
00814 {
00815   size_t __i;
00816   //  We assume that formatting is set up correctly for each element.
00817   for (__i = 0; __i < __n; __i++) _M_o.put(__leaf[__i]);
00818   return true;
00819 }
00820 
00821 template <class _CharT, class _Alloc>
00822 bool rope<_CharT, _Alloc>::_S_apply_to_pieces(
00823                 _Rope_char_consumer<_CharT>& __c,
00824                 const _RopeRep* __r,
00825                 size_t __begin, size_t __end)
00826 {
00827     if (0 == __r) return true;
00828     switch(__r->_M_tag) {
00829     case _RopeRep::_S_concat:
00830         {
00831         _RopeConcatenation* __conc = (_RopeConcatenation*)__r;
00832         _RopeRep* __left =  __conc->_M_left;
00833         size_t __left_len = __left->_M_size;
00834         if (__begin < __left_len) {
00835             size_t __left_end = min(__left_len, __end);
00836             if (!_S_apply_to_pieces(__c, __left, __begin, __left_end))
00837             return false;
00838         }
00839         if (__end > __left_len) {
00840             _RopeRep* __right =  __conc->_M_right;
00841             size_t __right_start = max(__left_len, __begin);
00842             if (!_S_apply_to_pieces(__c, __right,
00843                      __right_start - __left_len,
00844                      __end - __left_len)) {
00845             return false;
00846             }
00847         }
00848         }
00849         return true;
00850     case _RopeRep::_S_leaf:
00851         {
00852         _RopeLeaf* __l = (_RopeLeaf*)__r;
00853         return __c(__l->_M_data + __begin, __end - __begin);
00854         }
00855     case _RopeRep::_S_function:
00856     case _RopeRep::_S_substringfn:
00857         {
00858         _RopeFunction* __f = (_RopeFunction*)__r;
00859         size_t __len = __end - __begin;
00860         bool __result;
00861         _CharT* __buffer =
00862           (_CharT*)alloc::allocate(__len * sizeof(_CharT));
00863         __STL_TRY {
00864           (*(__f->_M_fn))(__begin, __len, __buffer);
00865           __result = __c(__buffer, __len);
00866                   alloc::deallocate(__buffer, __len * sizeof(_CharT));
00867                 }
00868         __STL_UNWIND((alloc::deallocate(__buffer,
00869                         __len * sizeof(_CharT))))
00870         return __result;
00871         }
00872     default:
00873         __stl_assert(false);
00874         /*NOTREACHED*/
00875         return false;
00876     }
00877 }
00878 
00879   template<class _CharT, class _Traits>
00880   inline void _Rope_fill(basic_ostream<_CharT, _Traits>& __o, size_t __n)
00881 {
00882     char __f = __o.fill();
00883     size_t __i;
00884 
00885     for (__i = 0; __i < __n; __i++) __o.put(__f);
00886 }
00887     
00888 
00889 template <class _CharT> inline bool _Rope_is_simple(_CharT*) { return false; }
00890 inline bool _Rope_is_simple(char*) { return true; }
00891 inline bool _Rope_is_simple(wchar_t*) { return true; }
00892 
00893 template<class _CharT, class _Traits, class _Alloc>
00894 basic_ostream<_CharT, _Traits>& operator<< (basic_ostream<_CharT, _Traits>& __o,
00895                                             const rope<_CharT, _Alloc>& __r)
00896 {
00897     size_t __w = __o.width();
00898     bool __left = bool(__o.flags() & ios::left);
00899     size_t __pad_len;
00900     size_t __rope_len = __r.size();
00901       _Rope_insert_char_consumer<_CharT, _Traits> __c(__o);
00902     bool __is_simple = _Rope_is_simple((_CharT*)0);
00903     
00904     if (__rope_len < __w) {
00905     __pad_len = __w - __rope_len;
00906     } else {
00907     __pad_len = 0;
00908     }
00909     if (!__is_simple) __o.width(__w/__rope_len);
00910     __STL_TRY {
00911       if (__is_simple && !__left && __pad_len > 0) {
00912     _Rope_fill(__o, __pad_len);
00913       }
00914       __r.apply_to_pieces(0, __r.size(), __c);
00915       if (__is_simple && __left && __pad_len > 0) {
00916     _Rope_fill(__o, __pad_len);
00917       }
00918       if (!__is_simple)
00919         __o.width(__w);
00920     }
00921     __STL_UNWIND(if (!__is_simple) __o.width(__w))
00922     return __o;
00923 }
00924 
00925 template <class _CharT, class _Alloc>
00926 _CharT*
00927 rope<_CharT,_Alloc>::_S_flatten(_RopeRep* __r,
00928                  size_t __start, size_t __len,
00929                  _CharT* __buffer)
00930 {
00931     _Rope_flatten_char_consumer<_CharT> __c(__buffer);
00932     _S_apply_to_pieces(__c, __r, __start, __start + __len);
00933     return(__buffer + __len);
00934 }
00935 
00936 template <class _CharT, class _Alloc>
00937 size_t
00938 rope<_CharT,_Alloc>::find(_CharT __pattern, size_t __start) const
00939 {
00940     _Rope_find_char_char_consumer<_CharT> __c(__pattern);
00941     _S_apply_to_pieces(__c, _M_tree_ptr, __start, size());
00942     size_type __result_pos = __start + __c._M_count;
00943 #   ifndef __STL_OLD_ROPE_SEMANTICS
00944     if (__result_pos == size()) __result_pos = npos;
00945 #   endif
00946     return __result_pos;
00947 }
00948 
00949 template <class _CharT, class _Alloc>
00950 _CharT*
00951 rope<_CharT,_Alloc>::_S_flatten(_RopeRep* __r, _CharT* __buffer)
00952 {
00953     if (0 == __r) return __buffer;
00954     switch(__r->_M_tag) {
00955     case _RopeRep::_S_concat:
00956         {
00957         _RopeConcatenation* __c = (_RopeConcatenation*)__r;
00958         _RopeRep* __left = __c->_M_left;
00959         _RopeRep* __right = __c->_M_right;
00960         _CharT* __rest = _S_flatten(__left, __buffer);
00961         return _S_flatten(__right, __rest);
00962         }
00963     case _RopeRep::_S_leaf:
00964         {
00965         _RopeLeaf* __l = (_RopeLeaf*)__r;
00966         return copy_n(__l->_M_data, __l->_M_size, __buffer).second;
00967         }
00968     case _RopeRep::_S_function:
00969     case _RopeRep::_S_substringfn:
00970         // We dont yet do anything with substring nodes.
00971         // This needs to be fixed before ropefiles will work well.
00972         {
00973         _RopeFunction* __f = (_RopeFunction*)__r;
00974         (*(__f->_M_fn))(0, __f->_M_size, __buffer);
00975         return __buffer + __f->_M_size;
00976         }
00977     default:
00978         __stl_assert(false);
00979         /*NOTREACHED*/
00980         return 0;
00981     }
00982 }
00983 
00984 
00985 // This needs work for _CharT != char
00986 template <class _CharT, class _Alloc>
00987 void
00988 rope<_CharT,_Alloc>::_S_dump(_RopeRep* __r, int __indent)
00989 {
00990     for (int __i = 0; __i < __indent; __i++) putchar(' ');
00991     if (0 == __r) {
00992     printf("NULL\n"); return;
00993     }
00994     if (_RopeRep::_S_concat == __r->_M_tag) {
00995     _RopeConcatenation* __c = (_RopeConcatenation*)__r;
00996     _RopeRep* __left = __c->_M_left;
00997     _RopeRep* __right = __c->_M_right;
00998 
00999 #       ifdef __GC
01000       printf("Concatenation %p (depth = %d, len = %ld, %s balanced)\n",
01001         __r, __r->_M_depth, __r->_M_size, __r->_M_is_balanced? "" : "not");
01002 #       else
01003       printf("Concatenation %p (rc = %ld, depth = %d, "
01004                "len = %ld, %s balanced)\n",
01005          __r, __r->_M_ref_count, __r->_M_depth, __r->_M_size,
01006          __r->_M_is_balanced? "" : "not");
01007 #       endif
01008     _S_dump(__left, __indent + 2);
01009     _S_dump(__right, __indent + 2);
01010     return;
01011     } else {
01012     char* __kind;
01013 
01014     switch (__r->_M_tag) {
01015         case _RopeRep::_S_leaf:
01016         __kind = "Leaf";
01017         break;
01018         case _RopeRep::_S_function:
01019         __kind = "Function";
01020         break;
01021         case _RopeRep::_S_substringfn:
01022         __kind = "Function representing substring";
01023         break;
01024         default:
01025         __kind = "(corrupted kind field!)";
01026     }
01027 #       ifdef __GC
01028       printf("%s %p (depth = %d, len = %ld) ",
01029          __kind, __r, __r->_M_depth, __r->_M_size);
01030 #       else
01031       printf("%s %p (rc = %ld, depth = %d, len = %ld) ",
01032          __kind, __r, __r->_M_ref_count, __r->_M_depth, __r->_M_size);
01033 #       endif
01034     if (_S_is_one_byte_char_type((_CharT*)0)) {
01035         const int __max_len = 40;
01036         _Self_destruct_ptr __prefix(_S_substring(__r, 0, __max_len));
01037         _CharT __buffer[__max_len + 1];
01038         bool __too_big = __r->_M_size > __prefix->_M_size;
01039 
01040         _S_flatten(__prefix, __buffer);
01041         __buffer[__prefix->_M_size] = _S_eos((_CharT*)0); 
01042         printf("%s%s\n", 
01043                (char*)__buffer, __too_big? "...\n" : "\n");
01044     } else {
01045         printf("\n");
01046     }
01047     }
01048 }
01049 
01050 template <class _CharT, class _Alloc>
01051 const unsigned long
01052 rope<_CharT,_Alloc>::_S_min_len[
01053   _Rope_RopeRep<_CharT,_Alloc>::_S_max_rope_depth + 1] = {
01054 /* 0 */1, /* 1 */2, /* 2 */3, /* 3 */5, /* 4 */8, /* 5 */13, /* 6 */21,
01055 /* 7 */34, /* 8 */55, /* 9 */89, /* 10 */144, /* 11 */233, /* 12 */377,
01056 /* 13 */610, /* 14 */987, /* 15 */1597, /* 16 */2584, /* 17 */4181,
01057 /* 18 */6765, /* 19 */10946, /* 20 */17711, /* 21 */28657, /* 22 */46368,
01058 /* 23 */75025, /* 24 */121393, /* 25 */196418, /* 26 */317811,
01059 /* 27 */514229, /* 28 */832040, /* 29 */1346269, /* 30 */2178309,
01060 /* 31 */3524578, /* 32 */5702887, /* 33 */9227465, /* 34 */14930352,
01061 /* 35 */24157817, /* 36 */39088169, /* 37 */63245986, /* 38 */102334155,
01062 /* 39 */165580141, /* 40 */267914296, /* 41 */433494437,
01063 /* 42 */701408733, /* 43 */1134903170, /* 44 */1836311903,
01064 /* 45 */2971215073u };
01065 // These are Fibonacci numbers < 2**32.
01066 
01067 template <class _CharT, class _Alloc>
01068 rope<_CharT,_Alloc>::_RopeRep*
01069 rope<_CharT,_Alloc>::_S_balance(_RopeRep* __r)
01070 {
01071     _RopeRep* __forest[_RopeRep::_S_max_rope_depth + 1];
01072     _RopeRep* __result = 0;
01073     int __i;
01074     // Invariant:
01075     // The concatenation of forest in descending order is equal to __r.
01076     // __forest[__i]._M_size >= _S_min_len[__i]
01077     // __forest[__i]._M_depth = __i
01078     // References from forest are included in refcount.
01079 
01080     for (__i = 0; __i <= _RopeRep::_S_max_rope_depth; ++__i) 
01081       __forest[__i] = 0;
01082     __STL_TRY {
01083       _S_add_to_forest(__r, __forest);
01084       for (__i = 0; __i <= _RopeRep::_S_max_rope_depth; ++__i) 
01085         if (0 != __forest[__i]) {
01086 #   ifndef __GC
01087       _Self_destruct_ptr __old(__result);
01088 #   endif
01089       __result = _S_concat(__forest[__i], __result);
01090     __forest[__i]->_M_unref_nonnil();
01091 #   if !defined(__GC) && defined(__STL_USE_EXCEPTIONS)
01092       __forest[__i] = 0;
01093 #   endif
01094       }
01095     }
01096     __STL_UNWIND(for(__i = 0; __i <= _RopeRep::_S_max_rope_depth; __i++)
01097          _S_unref(__forest[__i]))
01098     if (__result->_M_depth > _RopeRep::_S_max_rope_depth) {
01099 #     ifdef __STL_USE_EXCEPTIONS
01100     __STL_THROW(length_error("rope too long"));
01101 #     else
01102     abort();
01103 #     endif
01104     }
01105     return(__result);
01106 }
01107 
01108 
01109 template <class _CharT, class _Alloc>
01110 void
01111 rope<_CharT,_Alloc>::_S_add_to_forest(_RopeRep* __r, _RopeRep** __forest)
01112 {
01113     if (__r->_M_is_balanced) {
01114     _S_add_leaf_to_forest(__r, __forest);
01115     return;
01116     }
01117     __stl_assert(__r->_M_tag == _RopeRep::_S_concat);
01118     {
01119     _RopeConcatenation* __c = (_RopeConcatenation*)__r;
01120 
01121     _S_add_to_forest(__c->_M_left, __forest);
01122     _S_add_to_forest(__c->_M_right, __forest);
01123     }
01124 }
01125 
01126 
01127 template <class _CharT, class _Alloc>
01128 void
01129 rope<_CharT,_Alloc>::_S_add_leaf_to_forest(_RopeRep* __r, _RopeRep** __forest)
01130 {
01131     _RopeRep* __insertee;           // included in refcount
01132     _RopeRep* __too_tiny = 0;       // included in refcount
01133     int __i;                // forest[0..__i-1] is empty
01134     size_t __s = __r->_M_size;
01135 
01136     for (__i = 0; __s >= _S_min_len[__i+1]/* not this bucket */; ++__i) {
01137     if (0 != __forest[__i]) {
01138 #       ifndef __GC
01139           _Self_destruct_ptr __old(__too_tiny);
01140 #       endif
01141         __too_tiny = _S_concat_and_set_balanced(__forest[__i], __too_tiny);
01142         __forest[__i]->_M_unref_nonnil();
01143         __forest[__i] = 0;
01144     }
01145     }
01146     {
01147 #   ifndef __GC
01148       _Self_destruct_ptr __old(__too_tiny);
01149 #   endif
01150     __insertee = _S_concat_and_set_balanced(__too_tiny, __r);
01151     }
01152     // Too_tiny dead, and no longer included in refcount.
01153     // Insertee is live and included.
01154     __stl_assert(_S_is_almost_balanced(__insertee));
01155     __stl_assert(__insertee->_M_depth <= __r->_M_depth + 1);
01156     for (;; ++__i) {
01157     if (0 != __forest[__i]) {
01158 #       ifndef __GC
01159           _Self_destruct_ptr __old(__insertee);
01160 #       endif
01161         __insertee = _S_concat_and_set_balanced(__forest[__i], __insertee);
01162         __forest[__i]->_M_unref_nonnil();
01163         __forest[__i] = 0;
01164         __stl_assert(_S_is_almost_balanced(__insertee));
01165     }
01166     __stl_assert(_S_min_len[__i] <= __insertee->_M_size);
01167     __stl_assert(__forest[__i] == 0);
01168     if (__i == _RopeRep::_S_max_rope_depth || 
01169           __insertee->_M_size < _S_min_len[__i+1]) {
01170         __forest[__i] = __insertee;
01171         // refcount is OK since __insertee is now dead.
01172         return;
01173     }
01174     }
01175 }
01176 
01177 template <class _CharT, class _Alloc>
01178 _CharT
01179 rope<_CharT,_Alloc>::_S_fetch(_RopeRep* __r, size_type __i)
01180 {
01181     __GC_CONST _CharT* __cstr = __r->_M_c_string;
01182 
01183     __stl_assert(__i < __r->_M_size);
01184     if (0 != __cstr) return __cstr[__i]; 
01185     for(;;) {
01186       switch(__r->_M_tag) {
01187     case _RopeRep::_S_concat:
01188         {
01189         _RopeConcatenation* __c = (_RopeConcatenation*)__r;
01190         _RopeRep* __left = __c->_M_left;
01191         size_t __left_len = __left->_M_size;
01192 
01193         if (__i >= __left_len) {
01194             __i -= __left_len;
01195             __r = __c->_M_right;
01196         } else {
01197             __r = __left;
01198         }
01199         }
01200         break;
01201     case _RopeRep::_S_leaf:
01202         {
01203         _RopeLeaf* __l = (_RopeLeaf*)__r;
01204         return __l->_M_data[__i];
01205         }
01206     case _RopeRep::_S_function:
01207     case _RopeRep::_S_substringfn:
01208         {
01209         _RopeFunction* __f = (_RopeFunction*)__r;
01210         _CharT __result;
01211 
01212         (*(__f->_M_fn))(__i, 1, &__result);
01213         return __result;
01214         }
01215       }
01216     }
01217 }
01218 
01219 # ifndef __GC
01220 // Return a uniquely referenced character slot for the given
01221 // position, or 0 if that's not possible.
01222 template <class _CharT, class _Alloc>
01223 _CharT*
01224 rope<_CharT,_Alloc>::_S_fetch_ptr(_RopeRep* __r, size_type __i)
01225 {
01226     _RopeRep* __clrstack[_RopeRep::_S_max_rope_depth];
01227     size_t __csptr = 0;
01228 
01229     for(;;) {
01230       if (__r->_M_ref_count > 1) return 0;
01231       switch(__r->_M_tag) {
01232     case _RopeRep::_S_concat:
01233         {
01234         _RopeConcatenation* __c = (_RopeConcatenation*)__r;
01235         _RopeRep* __left = __c->_M_left;
01236         size_t __left_len = __left->_M_size;
01237 
01238         if (__c->_M_c_string != 0) __clrstack[__csptr++] = __c;
01239         if (__i >= __left_len) {
01240             __i -= __left_len;
01241             __r = __c->_M_right;
01242         } else {
01243             __r = __left;
01244         }
01245         }
01246         break;
01247     case _RopeRep::_S_leaf:
01248         {
01249         _RopeLeaf* __l = (_RopeLeaf*)__r;
01250         if (__l->_M_c_string != __l->_M_data && __l->_M_c_string != 0)
01251             __clrstack[__csptr++] = __l;
01252         while (__csptr > 0) {
01253             -- __csptr;
01254             _RopeRep* __d = __clrstack[__csptr];
01255             __d->_M_free_c_string();
01256             __d->_M_c_string = 0;
01257         }
01258         return __l->_M_data + __i;
01259         }
01260     case _RopeRep::_S_function:
01261     case _RopeRep::_S_substringfn:
01262         return 0;
01263       }
01264     }
01265 }
01266 # endif /* __GC */
01267 
01268 // The following could be implemented trivially using
01269 // lexicographical_compare_3way.
01270 // We do a little more work to avoid dealing with rope iterators for
01271 // flat strings.
01272 template <class _CharT, class _Alloc>
01273 int
01274 rope<_CharT,_Alloc>::_S_compare (const _RopeRep* __left, 
01275                                  const _RopeRep* __right)
01276 {
01277     size_t __left_len;
01278     size_t __right_len;
01279 
01280     if (0 == __right) return 0 != __left;
01281     if (0 == __left) return -1;
01282     __left_len = __left->_M_size;
01283     __right_len = __right->_M_size;
01284     if (_RopeRep::_S_leaf == __left->_M_tag) {
01285     _RopeLeaf* __l = (_RopeLeaf*) __left;
01286     if (_RopeRep::_S_leaf == __right->_M_tag) {
01287         _RopeLeaf* __r = (_RopeLeaf*) __right;
01288         return lexicographical_compare_3way(
01289             __l->_M_data, __l->_M_data + __left_len,
01290             __r->_M_data, __r->_M_data + __right_len);
01291     } else {
01292         const_iterator __rstart(__right, 0);
01293         const_iterator __rend(__right, __right_len);
01294         return lexicographical_compare_3way(
01295             __l->_M_data, __l->_M_data + __left_len,
01296             __rstart, __rend);
01297     }
01298     } else {
01299     const_iterator __lstart(__left, 0);
01300     const_iterator __lend(__left, __left_len);
01301     if (_RopeRep::_S_leaf == __right->_M_tag) {
01302         _RopeLeaf* __r = (_RopeLeaf*) __right;
01303         return lexicographical_compare_3way(
01304                    __lstart, __lend,
01305                    __r->_M_data, __r->_M_data + __right_len);
01306     } else {
01307         const_iterator __rstart(__right, 0);
01308         const_iterator __rend(__right, __right_len);
01309         return lexicographical_compare_3way(
01310                    __lstart, __lend,
01311                    __rstart, __rend);
01312     }
01313     }
01314 }
01315 
01316 // Assignment to reference proxies.
01317 template <class _CharT, class _Alloc>
01318 _Rope_char_ref_proxy<_CharT, _Alloc>&
01319 _Rope_char_ref_proxy<_CharT, _Alloc>::operator= (_CharT __c) {
01320     _RopeRep* __old = _M_root->_M_tree_ptr;
01321 #   ifndef __GC
01322     // First check for the case in which everything is uniquely
01323     // referenced.  In that case we can do this destructively.
01324     _CharT* __ptr = _My_rope::_S_fetch_ptr(__old, _M_pos);
01325     if (0 != __ptr) {
01326         *__ptr = __c;
01327         return *this;
01328     }
01329 #   endif
01330     _Self_destruct_ptr __left(
01331       _My_rope::_S_substring(__old, 0, _M_pos));
01332     _Self_destruct_ptr __right(
01333       _My_rope::_S_substring(__old, _M_pos+1, __old->_M_size));
01334     _Self_destruct_ptr __result_left(
01335       _My_rope::_S_destr_concat_char_iter(__left, &__c, 1));
01336 
01337 #   ifndef __GC
01338       __stl_assert(__left == __result_left || 1 == __result_left->_M_ref_count);
01339 #   endif
01340     _RopeRep* __result =
01341         _My_rope::_S_concat(__result_left, __right);
01342 #   ifndef __GC
01343       __stl_assert(1 <= __result->_M_ref_count);
01344       _RopeRep::_S_unref(__old);
01345 #   endif
01346     _M_root->_M_tree_ptr = __result;
01347     return *this;
01348 }
01349 
01350 template <class _CharT, class _Alloc>
01351 inline _Rope_char_ref_proxy<_CharT, _Alloc>::operator _CharT () const
01352 {
01353     if (_M_current_valid) {
01354     return _M_current;
01355     } else {
01356         return _My_rope::_S_fetch(_M_root->_M_tree_ptr, _M_pos);
01357     }
01358 }
01359 template <class _CharT, class _Alloc>
01360 _Rope_char_ptr_proxy<_CharT, _Alloc>
01361 _Rope_char_ref_proxy<_CharT, _Alloc>::operator& () const {
01362     return _Rope_char_ptr_proxy<_CharT, _Alloc>(*this);
01363 }
01364 
01365 template <class _CharT, class _Alloc>
01366 rope<_CharT, _Alloc>::rope(size_t __n, _CharT __c,
01367                const allocator_type& __a)
01368 : _Base(__a)
01369 {
01370     rope<_CharT,_Alloc> __result;
01371     const size_t __exponentiate_threshold = 32;
01372     size_t __exponent;
01373     size_t __rest;
01374     _CharT* __rest_buffer;
01375     _RopeRep* __remainder;
01376     rope<_CharT,_Alloc> __remainder_rope;
01377 
01378     if (0 == __n)
01379       return;
01380     
01381     __exponent = __n / __exponentiate_threshold;
01382     __rest = __n % __exponentiate_threshold;
01383     if (0 == __rest) {
01384     __remainder = 0;
01385     } else {
01386     __rest_buffer = _Data_allocate(_S_rounded_up_size(__rest));
01387     uninitialized_fill_n(__rest_buffer, __rest, __c);
01388     _S_cond_store_eos(__rest_buffer[__rest]);
01389     __STL_TRY {
01390         __remainder = _S_new_RopeLeaf(__rest_buffer, __rest, __a);
01391         }
01392     __STL_UNWIND(_RopeRep::__STL_FREE_STRING(__rest_buffer, __rest, __a))
01393     }
01394     __remainder_rope._M_tree_ptr = __remainder;
01395     if (__exponent != 0) {
01396     _CharT* __base_buffer =
01397       _Data_allocate(_S_rounded_up_size(__exponentiate_threshold));
01398     _RopeLeaf* __base_leaf;
01399     rope __base_rope;
01400     uninitialized_fill_n(__base_buffer, __exponentiate_threshold, __c);
01401     _S_cond_store_eos(__base_buffer[__exponentiate_threshold]);
01402     __STL_TRY {
01403           __base_leaf = _S_new_RopeLeaf(__base_buffer,
01404                                         __exponentiate_threshold, __a);
01405         }
01406     __STL_UNWIND(_RopeRep::__STL_FREE_STRING(__base_buffer, 
01407                                              __exponentiate_threshold, __a))
01408     __base_rope._M_tree_ptr = __base_leaf;
01409     if (1 == __exponent) {
01410       __result = __base_rope;
01411 #         ifndef __GC
01412         __stl_assert(2 == __result._M_tree_ptr->_M_ref_count);
01413         // One each for base_rope and __result
01414 #         endif
01415     } else {
01416       __result = power(__base_rope, __exponent,
01417                _Rope_Concat_fn<_CharT,_Alloc>());
01418     }
01419     if (0 != __remainder) {
01420       __result += __remainder_rope;
01421     }
01422     } else {
01423     __result = __remainder_rope;
01424     }
01425     _M_tree_ptr = __result._M_tree_ptr;
01426     _M_tree_ptr->_M_ref_nonnil();
01427 }
01428 
01429 template<class _CharT, class _Alloc>
01430   _CharT rope<_CharT,_Alloc>::_S_empty_c_str[1];
01431 
01432 template<class _CharT, class _Alloc>
01433 const _CharT* rope<_CharT,_Alloc>::c_str() const {
01434     if (0 == _M_tree_ptr) {
01435         _S_empty_c_str[0] = _S_eos((_CharT*)0);  // Possibly redundant,
01436                          // but probably fast.
01437         return _S_empty_c_str;
01438     }
01439     __GC_CONST _CharT* __old_c_string = _M_tree_ptr->_M_c_string;
01440     if (0 != __old_c_string) return(__old_c_string);
01441     size_t __s = size();
01442     _CharT* __result = _Data_allocate(__s + 1);
01443     _S_flatten(_M_tree_ptr, __result);
01444     __result[__s] = _S_eos((_CharT*)0);
01445 #   ifdef __GC
01446     _M_tree_ptr->_M_c_string = __result;
01447 #   else
01448       if ((__old_c_string = (__GC_CONST _CharT*)
01449              _Atomic_swap((unsigned long *)(&(_M_tree_ptr->_M_c_string)),
01450               (unsigned long)__result)) != 0) {
01451     // It must have been added in the interim.  Hence it had to have been
01452     // separately allocated.  Deallocate the old copy, since we just
01453     // replaced it.
01454     destroy(__old_c_string, __old_c_string + __s + 1);
01455     _Data_deallocate(__old_c_string, __s + 1);
01456       }
01457 #   endif
01458     return(__result);
01459 }
01460 
01461 template<class _CharT, class _Alloc>
01462 const _CharT* rope<_CharT,_Alloc>::replace_with_c_str() {
01463     if (0 == _M_tree_ptr) {
01464         _S_empty_c_str[0] = _S_eos((_CharT*)0);
01465         return _S_empty_c_str;
01466     }
01467     __GC_CONST _CharT* __old_c_string = _M_tree_ptr->_M_c_string;
01468     if (_RopeRep::_S_leaf == _M_tree_ptr->_M_tag && 0 != __old_c_string) {
01469     return(__old_c_string);
01470     }
01471     size_t __s = size();
01472     _CharT* __result = _Data_allocate(_S_rounded_up_size(__s));
01473     _S_flatten(_M_tree_ptr, __result);
01474     __result[__s] = _S_eos((_CharT*)0);
01475     _M_tree_ptr->_M_unref_nonnil();
01476     _M_tree_ptr = _S_new_RopeLeaf(__result, __s, get_allocator());
01477     return(__result);
01478 }
01479 
01480 // Algorithm specializations.  More should be added.
01481 
01482 template<class _Rope_iterator>  // was templated on CharT and Alloc
01483 void                // VC++ workaround
01484 _Rope_rotate(_Rope_iterator __first,
01485              _Rope_iterator __middle,
01486              _Rope_iterator __last)
01487 {
01488   typedef typename _Rope_iterator::value_type _CharT;
01489   typedef typename _Rope_iterator::_allocator_type _Alloc;
01490   
01491   __stl_assert(__first.container() == __middle.container()
01492                            && __middle.container() == __last.container());
01493   rope<_CharT,_Alloc>& __r(__first.container());
01494   rope<_CharT,_Alloc> __prefix = __r.substr(0, __first.index());
01495   rope<_CharT,_Alloc> __suffix = 
01496     __r.substr(__last.index(), __r.size() - __last.index());
01497   rope<_CharT,_Alloc> __part1 = 
01498     __r.substr(__middle.index(), __last.index() - __middle.index());
01499   rope<_CharT,_Alloc> __part2 = 
01500     __r.substr(__first.index(), __middle.index() - __first.index());
01501   __r = __prefix;
01502   __r += __part1;
01503   __r += __part2;
01504   __r += __suffix;
01505 }
01506 
01507 #if !defined(__GNUC__)
01508 // Appears to confuse g++
01509 inline void rotate(_Rope_iterator<char,__STL_DEFAULT_ALLOCATOR(char)> __first,
01510                    _Rope_iterator<char,__STL_DEFAULT_ALLOCATOR(char)> __middle,
01511                    _Rope_iterator<char,__STL_DEFAULT_ALLOCATOR(char)> __last) {
01512     _Rope_rotate(__first, __middle, __last);
01513 }
01514 #endif
01515 
01516 # if 0
01517 // Probably not useful for several reasons:
01518 // - for SGIs 7.1 compiler and probably some others,
01519 //   this forces lots of rope<wchar_t, ...> instantiations, creating a
01520 //   code bloat and compile time problem.  (Fixed in 7.2.)
01521 // - wchar_t is 4 bytes wide on most UNIX platforms, making it unattractive
01522 //   for unicode strings.  Unsigned short may be a better character
01523 //   type.
01524 inline void rotate(
01525         _Rope_iterator<wchar_t,__STL_DEFAULT_ALLOCATOR(char)> __first,
01526                 _Rope_iterator<wchar_t,__STL_DEFAULT_ALLOCATOR(char)> __middle,
01527                 _Rope_iterator<wchar_t,__STL_DEFAULT_ALLOCATOR(char)> __last) {
01528     _Rope_rotate(__first, __middle, __last);
01529 }
01530 # endif
01531 
01532 } // namespace std
01533 
01534 // Local Variables:
01535 // mode:C++
01536 // End:
01537 

Generated on Mon Apr 8 03:11:31 2002 for libstdc++-v3 Source by doxygen1.2.15