1 # This file is part of NIT (http://www.nitlanguage.org).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Tree-based representation of a String.
17 # Ropes are a data structure introduced in a 1995 paper from
18 # Hans J. Boehm, Russ Atkinson and Michael Plass.
22 # > Ropes: an Alternative to Strings,
23 # > *Software - Practice and Experience*,
24 # > Vol. 25(12), 1315-1330 (December 1995).
26 # The implementation developed here provides an automatic change
27 # of data structure depending on the length of the leaves.
29 # The length from which a `Rope` is built from a `flat` string
30 # if defined at top-level (see `maxlen`) and can be redefined by clients
31 # depending on their needs (e.g. if you need to bench the speed of
32 # the creation of concat nodes, lower the size of maxlen).
34 # A Rope as defined in the original paper is a Tree made of concatenation
35 # nodes and containing `Flat` (that is Array-based) strings as Leaves.
44 # "My" " Name" " is" " Simon."
47 # Note that the above example is not representative of the actual implementation
48 # of `Ropes`, since short leaves are merged to keep the rope at an acceptable
49 # height (hence, this rope here might actually be a `FlatString` !).
54 # Maxlen is the maximum length of a Leaf node
56 # When concatenating two leaves, if `new_length` > `maxlen`,
57 # A `Concat` node is created instead
59 # Its purpose is to limit the depth of the `Rope` (this
60 # improves performance when accessing/iterating).
61 fun maxlen
: Int do return 64
63 # String using a tree-based representation with leaves as `FlatStrings`
64 private abstract class Rope
68 # Node that represents a concatenation between two `String`
73 redef var chars
is lazy
do return new RopeChars(self)
75 redef var bytes
is lazy
do return new RopeBytes(self)
77 redef var length
is noinit
79 redef var bytelen
is noinit
81 redef fun substrings
do return new RopeSubstrings.from
(self, 0)
83 redef fun empty
do return ""
85 # Cache for the latest accessed FlatString in `self`
86 var flat_cache
: FlatString is noinit
88 # Position of the beginning of `flat_cache` in `self`
89 var flat_last_pos_start
: Int = -1
91 var flat_last_pos_end
: Int = -1
93 redef var to_cstring
is lazy
do
95 var ns
= new NativeString(len
+ 1)
98 for i
in substrings
do
100 i
.as(FlatString)._items
.copy_to
(ns
, ilen
, i
.as(FlatString)._first_byte
, off
)
106 # Left child of the node
108 # Right child of the node
114 length
= l
.length
+ r
.length
115 _bytelen
= l
.bytelen
+ r
.bytelen
118 redef fun is_empty
do return _bytelen
== 0
125 redef fun iterator
do return new RopeCharIterator.from
(self, 0)
129 for j
in [1 .. i
[ do x
+= self
134 assert i
>= 0 and i
<= _length
135 var flps
= _flat_last_pos_start
136 if flps
!= -1 and i
>= flps
and i
<= _flat_last_pos_end
then
137 return _flat_cache
.fetch_char_at
(i
- flps
)
139 var lf
= get_leaf_at
(i
)
140 return lf
.fetch_char_at
(i
- _flat_last_pos_start
)
143 fun get_leaf_at
(pos
: Int): FlatString do
144 var flps
= _flat_last_pos_start
145 if flps
!= -1 and pos
>= flps
and pos
<= _flat_last_pos_end
then
151 if s
isa FlatString then break
154 var llen
= lft
.length
162 _flat_last_pos_start
= st
- pos
163 _flat_last_pos_end
= st
- pos
+ s
.length
- 1
168 redef fun substring
(from
, count
) do
171 if count
< 0 then return ""
176 if (count
+ from
) > ln
then count
= ln
- from
177 if count
<= 0 then return ""
178 var end_index
= from
+ count
- 1
180 var flps
= _flat_last_pos_start
181 if flps
!= -1 and from
>= flps
and end_index
<= _flat_last_pos_end
then
182 return _flat_cache
.substring_impl
(from
- flps
, count
, end_index
- flps
)
186 var llen
= lft
.length
188 if from
+ count
< llen
then return lft
.substring
(from
, count
)
189 var lsublen
= llen
- from
190 return lft
.substring_from
(from
) + _right
.substring
(0, count
- lsublen
)
192 return _right
.substring
(from
- llen
, count
)
196 redef fun reversed
do return new Concat(_right
.reversed
, _left
.reversed
)
198 redef fun insert_at
(s
, pos
) do
200 if pos
> lft
.length
then
201 return lft
+ _right
.insert_at
(s
, pos
- lft
.length
)
203 return lft
.insert_at
(s
, pos
) + _right
206 redef fun to_upper
do return new Concat(_left
.to_upper
, _right
.to_upper
)
208 redef fun to_lower
do return new Concat(_left
.to_lower
, _right
.to_lower
)
214 return new Concat(self, s
)
218 if rlen
+ slen
> maxlen
then return new Concat(self, s
)
219 return new Concat(_left
, r
+ s
)
223 redef fun copy_to_native
(dest
, n
, src_offset
, dest_offset
) do
224 var subs
= new RopeSubstrings.from
(self, src_offset
)
225 var st
= src_offset
- subs
.pos
226 var off
= dest_offset
229 if n
> it
.length
then
230 var cplen
= it
.length
- st
231 it
._items
.copy_to
(dest
, cplen
, st
, off
)
235 it
._items
.copy_to
(dest
, n
, st
, off
)
243 # Returns a balanced version of `self`
244 fun balance
: String do
245 var children
= new Array[String]
247 var iter
: nullable RopeCharIteratorPiece = new RopeCharIteratorPiece(self, false, false, null)
249 if iter
== null then break
251 if not rnod
isa Concat then
256 if not iter
.ldone
then
258 iter
= new RopeCharIteratorPiece(rnod
._left
, false, false, iter
)
259 else if not iter
.rdone
then
261 iter
= new RopeCharIteratorPiece(rnod
._right
, false, false, iter
)
267 return recurse_balance
(children
, children
.length
)
270 fun recurse_balance
(nodes
: Array[String], len
: Int): String do
274 if len
- stpos
> 1 then
275 nodes
[finpos
] = new Concat(nodes
[stpos
], nodes
[stpos
+ 1])
278 nodes
[finpos
] = nodes
[stpos
]
283 if finpos
== 1 then return nodes
[0]
284 return recurse_balance
(nodes
, finpos
)
288 # Mutable `Rope`, optimized for concatenation operations
290 # A `RopeBuffer` is an efficient way of building a `String` when
291 # concatenating small strings.
293 # It does concatenations in an optimized way by having a
294 # mutable part and an immutable part built by efficiently
295 # concatenating strings in chain.
297 # Every concatenation operation is done by copying a string to
298 # the mutable part and flushing it when full.
300 # However, when a long string is appended to the `Buffer`,
301 # the concatenation is done at it would be in a `Rope`.
306 redef var chars
: Sequence[Char] is lazy
do return new RopeBufferChars(self)
308 redef var bytes
is lazy
do return new RopeBufferBytes(self)
310 # The final string being built on the fly
311 private var str
: String = ""
313 # Current concatenation buffer
314 private var ns
: NativeString is noinit
316 # Next available (e.g. unset) character in the `Buffer`
319 # Length (in chars) of the buffered part
320 private var nslen
= 0
322 # Keeps track of the buffer's currently dumped part
324 # This might happen if for instance, a String was being
325 # built by concatenating small parts of string and suddenly
326 # a long string (length > maxlen) is appended.
327 private var dumped
: Int is noinit
329 # Length of the complete rope in chars (0)
340 # Length of the complete rope in bytes
341 redef var bytelen
= 0
343 # Length of the mutable part (in bytes)
345 # Is also used as base to compute the size of the next
346 # mutable native string (`ns`)
347 private var buf_size
: Int is noinit
349 redef fun substrings
do return new RopeBufSubstringIterator.from
(self)
351 # Builds an empty `RopeBuffer`
353 ns
= new NativeString(maxlen
)
358 # Builds a new `RopeBuffer` with `str` in it.
359 init from
(str
: String) do
361 ns
= new NativeString(maxlen
)
363 _bytelen
= str
.length
367 # Resets the informations of the `Buffer`
369 # This is called when doing in-place modifications
370 # on a previously to_s'd `RopeBuffer`
372 var nns
= new NativeString(buf_size
)
373 var blen
= rpos
- dumped
374 ns
.copy_to
(nns
, blen
, dumped
, 0)
382 if i
< str
.length
then
385 var index
= ns
.char_to_byte_index_cached
(i
- str
.length
, 0, dumped
)
386 return ns
.char_at
(index
)
390 redef fun []=(i
, c
) do
391 assert i
>= 0 and i
<= length
392 if i
== length
then add c
393 if i
< str
.length
then
394 _bytelen
+= c
.u8char_len
- str
[i
].u8char_len
396 var l
= s
.substring
(0, i
)
397 var r
= s
.substring_from
(i
+ 1)
400 var reali
= i
- str
.length
401 var index
= ns
.char_to_byte_index_cached
(reali
, 0, dumped
)
402 var st_nxt
= ns
.char_to_byte_index_cached
(reali
+ 1, reali
, index
)
403 var loc_c
= ns
.char_at
(index
)
404 if loc_c
.u8char_len
!= c
.u8char_len
then
405 var delta
= c
.u8char_len
- loc_c
.u8char_len
406 var remsp
= buf_size
- rpos
407 if remsp
< delta
then
409 var nns
= new NativeString(buf_size
)
410 ns
.copy_to
(nns
, index
- dumped
, dumped
, 0)
411 ns
.copy_to
(nns
, rpos
- index
- loc_c
.u8char_len
, index
+ loc_c
.u8char_len
, index
- dumped
+ delta
)
413 index
= index
- dumped
415 ns
.copy_to
(ns
, rpos
- st_nxt
, st_nxt
, st_nxt
+ delta
)
420 ns
.set_char_at
(index
, c
)
424 redef fun empty
do return new RopeBuffer
432 ns
= new NativeString(buf_size
)
437 redef fun substring
(from
, count
) do
438 var strlen
= str
.length
442 if count
< 0 then count
= 0
446 if count
> length
then count
= length
- from
448 if count
== 0 then return empty
450 if from
< strlen
then
451 var subpos
= strlen
- from
452 if count
<= subpos
then
453 return new RopeBuffer.from
(str
.substring
(from
, count
))
455 var l
= str
.substring_from
(from
)
456 var rem
= count
- subpos
457 var nns
= new NativeString(rem
)
458 ns
.copy_to
(nns
, rem
, dumped
, 0)
459 return new RopeBuffer.from
(l
+ nns
.to_s_unsafe
(rem
))
462 var nns
= new NativeString(count
)
463 ns
.copy_to
(nns
, count
, dumped
, 0)
464 return new RopeBuffer.from
(nns
.to_s_unsafe
(count
))
468 redef fun append
(s
) do
470 if slen
>= maxlen
then
475 if s
isa FlatText then
477 var from
= s
.first_byte
478 var remsp
= buf_size
- rpos
479 if slen
<= remsp
then
480 oits
.copy_to
(ns
, slen
, from
, rpos
)
484 var brk
= oits
.find_beginning_of_char_at
(from
+ remsp
)
485 oits
.copy_to
(ns
, brk
, from
, rpos
)
488 oits
.copy_to
(ns
, slen
- remsp
, brk
, 0)
491 for i
in s
.substrings
do append i
497 var remsp
= buf_size
- rp
498 var cln
= c
.u8char_len
503 ns
.set_char_at
(rp
, c
)
509 # Converts the Buffer to a FlatString, appends it to
510 # the final String and re-allocates a new larger Buffer.
511 private fun dump_buffer
do
513 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
)
517 ns
= new NativeString(bs
)
523 # Similar to dump_buffer, but does not reallocate a new NativeString
524 private fun persist_buffer
do
525 if rpos
== dumped
then return
526 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
)
533 new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
).output
536 # Enlarge is useless here since the `Buffer`
537 # part is automatically dumped when necessary.
539 # Also, since the buffer can not be overused by a
540 # single string, there is no need for manual
543 # "You have no power here !"
544 redef fun enlarge
(i
) do end
553 # Flush the buffer in order to only have to reverse `str`.
554 if rpos
> 0 and dumped
!= rpos
then
555 str
+= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
)
562 if written
then reset
568 if written
then reset
574 redef class FlatString
576 redef fun insert_at
(s
, pos
) do
577 var l
= substring
(0, pos
)
578 var r
= substring_from
(pos
)
586 if slen
== 0 then return self
587 if mlen
== 0 then return s
588 var nlen
= slen
+ mlen
589 if s
isa FlatString then
590 if nlen
> maxlen
then return new Concat(self, s
)
592 var sifrom
= s
._first_byte
593 var mifrom
= _first_byte
595 var ns
= new NativeString(nlen
+ 1)
596 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
597 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
598 return new FlatString.full
(ns
, nlen
, 0, length
+ s
.length
)
599 else if s
isa Concat then
601 var sllen
= sl
.bytelen
602 if sllen
+ mlen
> maxlen
then return new Concat(self, s
)
603 return new Concat(self + sl
, s
._right
)
610 # A simple linked list for use with iterators
611 private class RopeCharIteratorPiece
612 # The encapsulated node of the `Rope`
614 # Was its _left child (if any) visited ?
616 # Was its _right child (if any) visited ?
618 # The previous node in the list.
619 var prev
: nullable RopeCharIteratorPiece
622 # A reverse iterator capable of working with `Rope` objects
623 private class RopeByteReverseIterator
624 super IndexedIterator[Byte]
626 # Current NativeString
627 var ns
: NativeString is noautoinit
628 # Current position in NativeString
629 var pns
: Int is noautoinit
630 # Position in the Rope (0-indexed)
631 var pos
: Int is noautoinit
632 # Iterator on the substrings, does the Postfix part of
633 # the Rope traversal.
634 var subs
: IndexedIterator[FlatString] is noautoinit
636 init from
(root
: Concat, pos
: Int) do
638 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
641 pns
= pos
- subs
.index
644 redef fun index
do return pos
646 redef fun is_ok
do return pos
>= 0
648 redef fun item
do return ns
[pns
]
653 if pns
>= 0 then return
654 if not subs
.is_ok
then return
656 if not subs
.is_ok
then return
663 # Forward iterator on the bytes of a `Rope`
664 private class RopeByteIterator
665 super IndexedIterator[Byte]
667 # Position in current `String`
668 var pns
: Int is noautoinit
669 # Current `String` being iterated on
670 var ns
: NativeString is noautoinit
671 # Substrings of the Rope
672 var subs
: IndexedIterator[FlatString] is noautoinit
673 # Maximum position to iterate on (e.g. Rope.length)
674 var max
: Int is noautoinit
675 # Position (char) in the Rope (0-indexed)
676 var pos
: Int is noautoinit
678 init from
(root
: Concat, pos
: Int) do
679 subs
= new RopeSubstrings.from
(root
, pos
)
680 pns
= pos
- subs
.index
682 ns
= subs
.item
._items
683 max
= root
.length
- 1
686 redef fun item
do return ns
[pns
]
688 redef fun is_ok
do return pos
<= max
690 redef fun index
do return pos
695 if pns
< subs
.item
._bytelen
then return
696 if not subs
.is_ok
then return
698 if not subs
.is_ok
then return
699 ns
= subs
.item
._items
705 # A reverse iterator capable of working with `Rope` objects
706 private class RopeCharReverseIterator
707 super IndexedIterator[Char]
709 # Current NativeString
710 var ns
: String is noautoinit
711 # Current position in NativeString
712 var pns
: Int is noautoinit
713 # Position in the Rope (0-indexed)
714 var pos
: Int is noautoinit
715 # Iterator on the substrings, does the Postfix part of
716 # the Rope traversal.
717 var subs
: IndexedIterator[String] is noautoinit
719 init from
(root
: Concat, pos
: Int) do
721 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
723 pns
= pos
- subs
.index
726 redef fun index
do return pos
728 redef fun is_ok
do return pos
>= 0
730 redef fun item
do return ns
[pns
]
735 if pns
>= 0 then return
736 if not subs
.is_ok
then return
738 if not subs
.is_ok
then return
744 # Forward iterator on the chars of a `Rope`
745 private class RopeCharIterator
746 super IndexedIterator[Char]
748 # Position in current `String`
749 var pns
: Int is noautoinit
750 # Current `String` being iterated on
751 var str
: String is noautoinit
752 # Substrings of the Rope
753 var subs
: IndexedIterator[String] is noautoinit
754 # Maximum position to iterate on (e.g. Rope.length)
755 var max
: Int is noautoinit
756 # Position (char) in the Rope (0-indexed)
757 var pos
: Int is noautoinit
759 init from
(root
: Concat, pos
: Int) do
760 subs
= new RopeSubstrings.from
(root
, pos
)
761 pns
= pos
- subs
.index
764 max
= root
.length
- 1
767 redef fun item
do return str
[pns
]
769 redef fun is_ok
do return pos
<= max
771 redef fun index
do return pos
776 if pns
< subs
.item
.length
then return
777 if not subs
.is_ok
then return
779 if not subs
.is_ok
then return
785 # Substrings of a Rope (i.e. Reverse postfix iterator on leaves)
786 private class ReverseRopeSubstrings
787 super IndexedIterator[FlatString]
790 var iter
: RopeCharIteratorPiece is noinit
792 var pos
: Int is noinit
795 var str
: FlatString is noinit
797 init from
(root
: Concat, pos
: Int) do
798 var r
= new RopeCharIteratorPiece(root
, false, true, null)
799 var rnod
: String = root
802 if rnod
isa Concat then
803 if off
>= rnod
._left
.length
then
804 off
-= rnod
._left
.length
806 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
810 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
813 str
= rnod
.as(FlatString)
822 redef fun item
do return str
824 redef fun index
do return pos
826 redef fun is_ok
do return pos
>= 0
829 if pos
< 0 then return
831 var currit
= curr
.node
832 while curr
!= null do
834 if not currit
isa Concat then
835 str
= currit
.as(FlatString)
840 if not curr
.rdone
then
842 curr
= new RopeCharIteratorPiece(currit
._right
, false, false, curr
)
845 if not curr
.ldone
then
847 curr
= new RopeCharIteratorPiece(currit
._left
, false, false, curr
)
856 private class RopeBufSubstringIterator
857 super Iterator[FlatText]
859 # Iterator on the substrings of the building string
860 var iter
: Iterator[FlatText] is noautoinit
861 # Makes a String out of the buffered part of the Ropebuffer
862 var nsstr
: FlatString is noautoinit
863 # Did we attain the buffered part ?
864 var nsstr_done
= false
866 init from
(str
: RopeBuffer) do
867 iter
= str
.str
.substrings
868 nsstr
= new FlatString.with_infos
(str
.ns
, str
.rpos
- str
.dumped
, str
.dumped
)
869 if str
.length
== 0 then nsstr_done
= true
872 redef fun is_ok
do return iter
.is_ok
or not nsstr_done
876 if iter
.is_ok
then return iter
.item
889 # Substrings of a Rope (i.e. Postfix iterator on leaves)
890 private class RopeSubstrings
891 super IndexedIterator[FlatString]
894 var iter
: RopeCharIteratorPiece is noinit
896 var pos
: Int is noinit
897 # Maximum position in `Rope` (i.e. length - 1)
898 var max
: Int is noinit
901 var str
: FlatString is noinit
903 init from
(root
: Concat, pos
: Int) do
904 var r
= new RopeCharIteratorPiece(root
, true, false, null)
905 max
= root
.length
- 1
906 var rnod
: String = root
909 if rnod
isa Concat then
910 if off
>= rnod
._left
.length
then
912 off
-= rnod
._left
.length
914 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
917 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
920 str
= rnod
.as(FlatString)
929 redef fun item
do return str
931 redef fun is_ok
do return pos
<= max
933 redef fun index
do return pos
937 if pos
> max
then return
941 if not rnod
isa Concat then
944 str
= rnod
.as(FlatString)
945 iter
= it
.as(not null)
951 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
952 else if not it
.rdone
then
955 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
965 # Implementation of a `StringCharView` for `Concat` objects
966 private class RopeChars
969 redef type SELFTYPE: Concat
975 redef fun iterator_from
(i
) do return new RopeCharIterator.from
(target
, i
)
977 redef fun reverse_iterator_from
(i
) do return new RopeCharReverseIterator.from
(target
, i
)
981 # Implementation of a `StringCharView` for `Concat` objects
982 private class RopeBytes
985 redef type SELFTYPE: Concat
988 var nod
: String = target
990 if nod
isa FlatString then return nod
._items
[i
]
991 if not nod
isa Concat then abort
993 if lft
.bytelen
>= i
then
1001 redef fun iterator_from
(i
) do return new RopeByteIterator.from
(target
, i
)
1003 redef fun reverse_iterator_from
(i
) do return new RopeByteReverseIterator.from
(target
, i
)
1007 # An Iterator over a RopeBuffer.
1008 class RopeBufferCharIterator
1009 super IndexedIterator[Char]
1012 var sit
: IndexedIterator[Char] is noautoinit
1014 redef fun index
do return sit
.index
1016 # Init the iterator from a RopeBuffer starting from `pos`.
1017 init from
(t
: RopeBuffer, pos
: Int) do
1019 sit
= t
.str
.chars
.iterator_from
(pos
)
1022 redef fun is_ok
do return sit
.is_ok
1029 redef fun next
do sit
.next
1032 # Reverse iterator over a RopeBuffer.
1033 class RopeBufferCharReverseIterator
1034 super IndexedIterator[Char]
1037 var sit
: IndexedIterator[Char] is noautoinit
1039 redef fun index
do return sit
.index
1041 # Init the iterator from a RopeBuffer starting from `pos`.
1042 init from
(tgt
: RopeBuffer, pos
: Int) do
1044 sit
= tgt
.str
.chars
.reverse_iterator_from
(pos
)
1047 redef fun is_ok
do return sit
.is_ok
1054 redef fun next
do sit
.next
1057 # View on the chars of a `RopeBuffer`
1058 class RopeBufferChars
1059 super BufferCharView
1061 redef type SELFTYPE: RopeBuffer
1063 redef fun [](i
) do return target
[i
]
1065 redef fun []=(i
,c
) do target
[i
] = c
1067 redef fun add
(c
) do target
.add c
1069 redef fun push
(c
) do target
.add c
1071 redef fun iterator_from
(i
) do return new RopeBufferCharIterator.from
(target
, i
)
1073 redef fun reverse_iterator_from
(i
) do return new RopeBufferCharReverseIterator.from
(target
, i
)
1076 # An Iterator over a RopeBuffer.
1077 class RopeBufferByteIterator
1078 super IndexedIterator[Byte]
1081 var sit
: IndexedIterator[Byte] is noautoinit
1083 # Native string iterated over.
1084 var ns
: NativeString is noautoinit
1086 # Current position in `ns`.
1087 var pns
: Int is noautoinit
1089 # Maximum position iterable.
1090 var maxpos
: Int is noautoinit
1092 redef var index
is noautoinit
1094 # Init the iterator from a RopeBuffer starting from `pos`.
1095 init from
(t
: RopeBuffer, pos
: Int) do
1098 sit
= t
.str
.bytes
.iterator_from
(pos
)
1099 pns
= pos
- t
.str
.length
1103 redef fun is_ok
do return index
< maxpos
1106 if sit
.is_ok
then return sit
.item
1120 # Reverse iterator over a RopeBuffer.
1121 class RopeBufferByteReverseIterator
1122 super IndexedIterator[Byte]
1125 var sit
: IndexedIterator[Byte] is noautoinit
1127 # Native string iterated over.
1128 var ns
: NativeString is noautoinit
1130 # Current position in `ns`.
1131 var pns
: Int is noautoinit
1133 redef var index
is noautoinit
1135 # Init the iterator from a RopeBuffer starting from `pos`.
1136 init from
(tgt
: RopeBuffer, pos
: Int) do
1137 sit
= tgt
.str
.bytes
.reverse_iterator_from
(pos
- (tgt
.rpos
- tgt
.dumped
))
1138 pns
= pos
- tgt
.str
.bytelen
+ tgt
.rpos
1143 redef fun is_ok
do return index
>= 0
1146 if pns
>= 0 then return ns
[pns
]
1160 # View on the chars of a `RopeBuffer`
1161 class RopeBufferBytes
1162 super BufferByteView
1164 redef type SELFTYPE: RopeBuffer
1167 if i
< target
.str
.bytelen
then
1168 return target
.str
.bytes
[i
]
1170 return target
.ns
[i
- target
.str
.bytelen
]
1174 redef fun iterator_from
(i
) do return new RopeBufferByteIterator.from
(target
, i
)
1176 redef fun reverse_iterator_from
(i
) do return new RopeBufferByteReverseIterator.from
(target
, i
)