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(self)
83 redef fun empty
do return ""
85 # Cache for the latest accessed FlatString in `self`
86 var flat_cache
: String = ""
88 # Position of the beginning of `flat_cache` in `self`
89 var flat_last_pos_start
: Int = -1
91 redef var to_cstring
is lazy
do
93 var ns
= new NativeString(len
+ 1)
96 for i
in substrings
do
98 i
.as(FlatString).items
.copy_to
(ns
, ilen
, i
.as(FlatString).first_byte
, off
)
104 # Left child of the node
106 # Right child of the node
110 length
= left
.length
+ right
.length
111 bytelen
= left
.bytelen
+ right
.bytelen
119 redef fun iterator
do return new RopeCharIterator(self)
123 for j
in [1 .. i
[ do x
+= self
128 if flat_last_pos_start
!= -1 then
129 var fsp
= i
- flat_last_pos_start
130 if fsp
>= 0 and fsp
< flat_cache
.length
then return flat_cache
[fsp
]
135 if s
isa FlatString then break
138 var llen
= lft
.length
146 flat_last_pos_start
= st
- i
151 redef fun substring
(from
, len
) do
152 var llen
= left
.length
154 if from
+ len
< llen
then return left
.substring
(from
,len
)
155 var lsublen
= llen
- from
156 return left
.substring_from
(from
) + right
.substring
(0, len
- lsublen
)
158 return right
.substring
(from
- llen
, len
)
162 redef fun reversed
do return new Concat(right
.reversed
, left
.reversed
)
164 redef fun insert_at
(s
, pos
) do
165 if pos
> left
.length
then
166 return left
+ right
.insert_at
(s
, pos
- left
.length
)
168 return left
.insert_at
(s
, pos
) + right
171 redef fun to_upper
do return new Concat(left
.to_upper
, right
.to_upper
)
173 redef fun to_lower
do return new Concat(left
.to_lower
, right
.to_lower
)
179 return new Concat(self, s
)
183 if rlen
+ slen
> maxlen
then return new Concat(self, s
)
184 return new Concat(left
, r
+ s
)
188 redef fun copy_to_native
(dest
, n
, src_offset
, dest_offset
) do
189 var subs
= new RopeSubstrings.from
(self, src_offset
)
190 var st
= src_offset
- subs
.pos
191 var off
= dest_offset
194 if n
> it
.length
then
195 var cplen
= it
.length
- st
196 it
.items
.copy_to
(dest
, cplen
, st
, off
)
200 it
.items
.copy_to
(dest
, n
, st
, off
)
208 # Returns a balanced version of `self`
209 fun balance
: String do
210 var children
= new Array[String]
212 var iter
: nullable RopeCharIteratorPiece = new RopeCharIteratorPiece(self, false, false, null)
214 if iter
== null then break
216 if not rnod
isa Concat then
221 if not iter
.ldone
then
223 iter
= new RopeCharIteratorPiece(rnod
.left
, false, false, iter
)
224 else if not iter
.rdone
then
226 iter
= new RopeCharIteratorPiece(rnod
.right
, false, false, iter
)
232 return recurse_balance
(children
, children
.length
)
235 fun recurse_balance
(nodes
: Array[String], len
: Int): String do
239 if len
- stpos
> 1 then
240 nodes
[finpos
] = new Concat(nodes
[stpos
], nodes
[stpos
+ 1])
243 nodes
[finpos
] = nodes
[stpos
]
248 if finpos
== 1 then return nodes
[0]
249 return recurse_balance
(nodes
, finpos
)
253 # Mutable `Rope`, optimized for concatenation operations
255 # A `RopeBuffer` is an efficient way of building a `String` when
256 # concatenating small strings.
258 # It does concatenations in an optimized way by having a
259 # mutable part and an immutable part built by efficiently
260 # concatenating strings in chain.
262 # Every concatenation operation is done by copying a string to
263 # the mutable part and flushing it when full.
265 # However, when a long string is appended to the `Buffer`,
266 # the concatenation is done at it would be in a `Rope`.
271 redef var chars
: Sequence[Char] is lazy
do return new RopeBufferChars(self)
273 redef var bytes
is lazy
do return new RopeBufferBytes(self)
275 # The final string being built on the fly
276 private var str
: String = ""
278 # Current concatenation buffer
279 private var ns
: NativeString is noinit
281 # Next available (e.g. unset) character in the `Buffer`
284 # Length (in chars) of the buffered part
285 private var nslen
= 0
287 # Keeps track of the buffer's currently dumped part
289 # This might happen if for instance, a String was being
290 # built by concatenating small parts of string and suddenly
291 # a long string (length > maxlen) is appended.
292 private var dumped
: Int is noinit
294 # Length of the complete rope in chars (0)
305 # Length of the complete rope in bytes
306 redef var bytelen
= 0
308 # Length of the mutable part (in bytes)
310 # Is also used as base to compute the size of the next
311 # mutable native string (`ns`)
312 private var buf_size
: Int is noinit
314 redef fun substrings
do return new RopeBufSubstringIterator(self)
316 # Builds an empty `RopeBuffer`
318 ns
= new NativeString(maxlen
)
323 # Builds a new `RopeBuffer` with `str` in it.
324 init from
(str
: String) do
326 ns
= new NativeString(maxlen
)
332 # Resets the informations of the `Buffer`
334 # This is called when doing in-place modifications
335 # on a previously to_s'd `RopeBuffer`
337 var nns
= new NativeString(buf_size
)
338 var blen
= rpos
- dumped
339 ns
.copy_to
(nns
, blen
, dumped
, 0)
347 if i
< str
.length
then
350 var index
= ns
.char_to_byte_index_cached
(i
- str
.length
, 0, dumped
)
351 return ns
.char_at
(index
)
355 redef fun []=(i
, c
) do
356 assert i
>= 0 and i
<= length
357 if i
== length
then add c
358 if i
< str
.length
then
359 bytelen
+= c
.u8char_len
- str
[i
].u8char_len
361 var l
= s
.substring
(0, i
)
362 var r
= s
.substring_from
(i
+ 1)
365 var reali
= i
- str
.length
366 var index
= ns
.char_to_byte_index_cached
(reali
, 0, dumped
)
367 var st_nxt
= ns
.char_to_byte_index_cached
(reali
+ 1, reali
, index
)
368 var loc_c
= ns
.char_at
(index
)
369 if loc_c
.u8char_len
!= c
.u8char_len
then
370 var delta
= c
.u8char_len
- loc_c
.u8char_len
371 var remsp
= buf_size
- rpos
372 if remsp
< delta
then
374 var nns
= new NativeString(buf_size
)
375 ns
.copy_to
(nns
, index
- dumped
, dumped
, 0)
376 ns
.copy_to
(nns
, rpos
- index
- loc_c
.u8char_len
, index
+ loc_c
.u8char_len
, index
- dumped
+ delta
)
378 index
= index
- dumped
380 ns
.copy_to
(ns
, rpos
- st_nxt
, st_nxt
, st_nxt
+ delta
)
385 ns
.set_char_at
(index
, c
)
389 redef fun empty
do return new RopeBuffer
397 ns
= new NativeString(buf_size
)
402 redef fun substring
(from
, count
) do
403 var strlen
= str
.length
407 if count
< 0 then count
= 0
411 if count
> length
then count
= length
- from
413 if count
== 0 then return empty
415 if from
< strlen
then
416 var subpos
= strlen
- from
417 if count
<= subpos
then
418 return new RopeBuffer.from
(str
.substring
(from
, count
))
420 var l
= str
.substring_from
(from
)
421 var rem
= count
- subpos
422 var nns
= new NativeString(rem
)
423 ns
.copy_to
(nns
, rem
, dumped
, 0)
424 return new RopeBuffer.from
(l
+ nns
.to_s_with_length
(rem
))
427 var nns
= new NativeString(count
)
428 ns
.copy_to
(nns
, count
, dumped
, 0)
429 return new RopeBuffer.from
(nns
.to_s_with_length
(count
))
433 redef fun append
(s
) do
435 if slen
>= maxlen
then
440 if s
isa FlatText then
442 var from
= s
.first_byte
443 var remsp
= buf_size
- rpos
444 if slen
<= remsp
then
445 oits
.copy_to
(ns
, slen
, from
, rpos
)
449 var brk
= oits
.find_beginning_of_char_at
(from
+ remsp
)
450 oits
.copy_to
(ns
, brk
, from
, rpos
)
453 oits
.copy_to
(ns
, slen
- remsp
, brk
, 0)
456 for i
in s
.substrings
do append i
462 if rp
>= buf_size
then
466 # TODO: Fix when supporting UTF-8
467 ns
[rp
] = c
.ascii
.to_b
473 # Converts the Buffer to a FlatString, appends it to
474 # the final String and re-allocates a new larger Buffer.
475 private fun dump_buffer
do
477 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
481 ns
= new NativeString(bs
)
487 # Similar to dump_buffer, but does not reallocate a new NativeString
488 private fun persist_buffer
do
489 if rpos
== dumped
then return
490 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
497 new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1).output
500 # Enlarge is useless here since the `Buffer`
501 # part is automatically dumped when necessary.
503 # Also, since the buffer can not be overused by a
504 # single string, there is no need for manual
507 # "You have no power here !"
508 redef fun enlarge
(i
) do end
517 # Flush the buffer in order to only have to reverse `str`.
518 if rpos
> 0 and dumped
!= rpos
then
519 str
+= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
526 if written
then reset
532 if written
then reset
538 redef class FlatString
540 redef fun insert_at
(s
, pos
) do
541 var l
= substring
(0, pos
)
542 var r
= substring_from
(pos
)
550 if slen
== 0 then return self
551 if mlen
== 0 then return s
552 var nlen
= slen
+ mlen
553 if s
isa FlatString then
554 if nlen
> maxlen
then return new Concat(self, s
)
556 var sifrom
= s
.first_byte
557 var mifrom
= first_byte
559 var ns
= new NativeString(nlen
+ 1)
560 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
561 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
562 return new FlatString.full
(ns
, nlen
, 0, nlen
- 1, length
+ s
.length
)
563 else if s
isa Concat then
565 var sllen
= sl
.bytelen
566 if sllen
+ mlen
> maxlen
then return new Concat(self, s
)
567 return new Concat(self + sl
, s
.right
)
574 # A simple linked list for use with iterators
575 private class RopeCharIteratorPiece
576 # The encapsulated node of the `Rope`
578 # Was its left child (if any) visited ?
580 # Was its right child (if any) visited ?
582 # The previous node in the list.
583 var prev
: nullable RopeCharIteratorPiece
586 # A reverse iterator capable of working with `Rope` objects
587 private class RopeByteReverseIterator
588 super IndexedIterator[Byte]
590 # Current NativeString
592 # Current position in NativeString
594 # Position in the Rope (0-indexed)
596 # Iterator on the substrings, does the Postfix part of
597 # the Rope traversal.
598 var subs
: IndexedIterator[FlatString]
600 init(root
: Concat) is old_style_init
do
601 pos
= root
.bytelen
- 1
602 subs
= new ReverseRopeSubstrings(root
)
608 init from
(root
: Concat, pos
: Int) do
610 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
613 pns
= pos
- subs
.index
616 redef fun index
do return pos
618 redef fun is_ok
do return pos
>= 0
620 redef fun item
do return ns
[pns
]
625 if pns
>= 0 then return
626 if not subs
.is_ok
then return
628 if not subs
.is_ok
then return
635 # Forward iterator on the bytes of a `Rope`
636 private class RopeByteIterator
637 super IndexedIterator[Byte]
639 # Position in current `String`
641 # Current `String` being iterated on
643 # Substrings of the Rope
644 var subs
: IndexedIterator[FlatString]
645 # Maximum position to iterate on (e.g. Rope.length)
647 # Position (char) in the Rope (0-indexed)
650 init(root
: Concat) is old_style_init
do
651 subs
= new RopeSubstrings(root
)
654 max
= root
.length
- 1
658 init from
(root
: Concat, pos
: Int) do
659 subs
= new RopeSubstrings.from
(root
, pos
)
660 pns
= pos
- subs
.index
663 max
= root
.length
- 1
666 redef fun item
do return ns
[pns
]
668 redef fun is_ok
do return pos
<= max
670 redef fun index
do return pos
675 if pns
< subs
.item
.bytelen
then return
676 if not subs
.is_ok
then return
678 if not subs
.is_ok
then return
685 # A reverse iterator capable of working with `Rope` objects
686 private class RopeCharReverseIterator
687 super IndexedIterator[Char]
689 # Current NativeString
691 # Current position in NativeString
693 # Position in the Rope (0-indexed)
695 # Iterator on the substrings, does the Postfix part of
696 # the Rope traversal.
697 var subs
: IndexedIterator[String]
699 init(root
: Concat) is old_style_init
do
700 pos
= root
.length
- 1
701 subs
= new ReverseRopeSubstrings(root
)
706 init from
(root
: Concat, pos
: Int) do
708 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
710 pns
= pos
- subs
.index
713 redef fun index
do return pos
715 redef fun is_ok
do return pos
>= 0
717 redef fun item
do return ns
[pns
]
722 if pns
>= 0 then return
723 if not subs
.is_ok
then return
725 if not subs
.is_ok
then return
731 # Forward iterator on the chars of a `Rope`
732 private class RopeCharIterator
733 super IndexedIterator[Char]
735 # Position in current `String`
737 # Current `String` being iterated on
739 # Substrings of the Rope
740 var subs
: IndexedIterator[String]
741 # Maximum position to iterate on (e.g. Rope.length)
743 # Position (char) in the Rope (0-indexed)
746 init(root
: Concat) is old_style_init
do
747 subs
= new RopeSubstrings(root
)
750 max
= root
.length
- 1
754 init from
(root
: Concat, pos
: Int) do
755 subs
= new RopeSubstrings.from
(root
, pos
)
756 pns
= pos
- subs
.index
759 max
= root
.length
- 1
762 redef fun item
do return str
[pns
]
764 redef fun is_ok
do return pos
<= max
766 redef fun index
do return pos
771 if pns
< subs
.item
.length
then return
772 if not subs
.is_ok
then return
774 if not subs
.is_ok
then return
780 # Substrings of a Rope (i.e. Reverse postfix iterator on leaves)
781 private class ReverseRopeSubstrings
782 super IndexedIterator[FlatString]
785 var iter
: RopeCharIteratorPiece is noinit
787 var pos
: Int is noinit
790 var str
: FlatString is noinit
792 init(root
: Concat) is old_style_init
do
793 var r
= new RopeCharIteratorPiece(root
, false, true, null)
794 pos
= root
.length
- 1
795 var lnod
: String = root
797 if lnod
isa Concat then
799 r
= new RopeCharIteratorPiece(lnod
, false, true, r
)
801 str
= lnod
.as(FlatString)
808 init from
(root
: Concat, pos
: Int) do
809 var r
= new RopeCharIteratorPiece(root
, false, true, null)
810 var rnod
: String = root
813 if rnod
isa Concat then
814 if off
>= rnod
.left
.length
then
815 off
-= rnod
.left
.length
817 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
821 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
824 str
= rnod
.as(FlatString)
833 redef fun item
do return str
835 redef fun index
do return pos
837 redef fun is_ok
do return pos
>= 0
840 if pos
< 0 then return
842 var currit
= curr
.node
843 while curr
!= null do
845 if not currit
isa Concat then
846 str
= currit
.as(FlatString)
851 if not curr
.rdone
then
853 curr
= new RopeCharIteratorPiece(currit
.right
, false, false, curr
)
856 if not curr
.ldone
then
858 curr
= new RopeCharIteratorPiece(currit
.left
, false, false, curr
)
867 private class RopeBufSubstringIterator
868 super Iterator[FlatText]
870 # Iterator on the substrings of the building string
871 var iter
: Iterator[FlatText]
872 # Makes a String out of the buffered part of the Ropebuffer
873 var nsstr
: FlatString
874 # Did we attain the buffered part ?
875 var nsstr_done
= false
877 init(str
: RopeBuffer) is old_style_init
do
878 iter
= str
.str
.substrings
879 nsstr
= new FlatString.with_infos
(str
.ns
, str
.rpos
- str
.dumped
, str
.dumped
, str
.rpos
- 1)
880 if str
.length
== 0 then nsstr_done
= true
883 redef fun is_ok
do return iter
.is_ok
or not nsstr_done
887 if iter
.is_ok
then return iter
.item
900 # Substrings of a Rope (i.e. Postfix iterator on leaves)
901 private class RopeSubstrings
902 super IndexedIterator[FlatString]
905 var iter
: RopeCharIteratorPiece is noinit
907 var pos
: Int is noinit
908 # Maximum position in `Rope` (i.e. length - 1)
909 var max
: Int is noinit
912 var str
: FlatString is noinit
914 init(root
: Concat) is old_style_init
do
915 var r
= new RopeCharIteratorPiece(root
, true, false, null)
917 max
= root
.length
- 1
918 var rnod
: String = root
920 if rnod
isa Concat then
922 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
924 str
= rnod
.as(FlatString)
932 init from
(root
: Concat, pos
: Int) do
933 var r
= new RopeCharIteratorPiece(root
, true, false, null)
934 max
= root
.length
- 1
935 var rnod
: String = root
938 if rnod
isa Concat then
939 if off
>= rnod
.left
.length
then
941 off
-= rnod
.left
.length
943 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
946 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
949 str
= rnod
.as(FlatString)
958 redef fun item
do return str
960 redef fun is_ok
do return pos
<= max
962 redef fun index
do return pos
966 if pos
> max
then return
970 if not rnod
isa Concat then
973 str
= rnod
.as(FlatString)
974 iter
= it
.as(not null)
980 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
981 else if not it
.rdone
then
984 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
994 # Implementation of a `StringCharView` for `Concat` objects
995 private class RopeChars
998 redef type SELFTYPE: Concat
1004 redef fun iterator_from
(i
) do return new RopeCharIterator.from
(target
, i
)
1006 redef fun reverse_iterator_from
(i
) do return new RopeCharReverseIterator.from
(target
, i
)
1010 # Implementation of a `StringCharView` for `Concat` objects
1011 private class RopeBytes
1012 super StringByteView
1014 redef type SELFTYPE: Concat
1017 var nod
: String = target
1019 if nod
isa FlatString then return nod
.items
[i
]
1020 if not nod
isa Concat then abort
1021 if nod
.left
.bytelen
>= i
then
1029 redef fun iterator_from
(i
) do return new RopeByteIterator.from
(target
, i
)
1031 redef fun reverse_iterator_from
(i
) do return new RopeByteReverseIterator.from
(target
, i
)
1035 # An Iterator over a RopeBuffer.
1036 class RopeBufferCharIterator
1037 super IndexedIterator[Char]
1040 var sit
: IndexedIterator[Char]
1042 redef fun index
do return sit
.index
1044 # Init the iterator from a RopeBuffer.
1045 init(t
: RopeBuffer) is old_style_init
do
1047 sit
= t
.str
.chars
.iterator
1050 # Init the iterator from a RopeBuffer starting from `pos`.
1051 init from
(t
: RopeBuffer, pos
: Int) do
1053 sit
= t
.str
.chars
.iterator_from
(pos
)
1056 redef fun is_ok
do return sit
.is_ok
1063 redef fun next
do sit
.next
1066 # Reverse iterator over a RopeBuffer.
1067 class RopeBufferCharReverseIterator
1068 super IndexedIterator[Char]
1071 var sit
: IndexedIterator[Char]
1073 redef fun index
do return sit
.index
1075 # Init the iterator from a RopeBuffer.
1076 init(tgt
: RopeBuffer) is old_style_init
do
1078 sit
= tgt
.str
.chars
.reverse_iterator
1081 # Init the iterator from a RopeBuffer starting from `pos`.
1082 init from
(tgt
: RopeBuffer, pos
: Int) do
1084 sit
= tgt
.str
.chars
.reverse_iterator_from
(pos
)
1087 redef fun is_ok
do return sit
.is_ok
1094 redef fun next
do sit
.next
1097 # View on the chars of a `RopeBuffer`
1098 class RopeBufferChars
1099 super BufferCharView
1101 redef type SELFTYPE: RopeBuffer
1103 redef fun [](i
) do return target
[i
]
1105 redef fun []=(i
,c
) do target
[i
] = c
1107 redef fun add
(c
) do target
.add c
1109 redef fun push
(c
) do target
.add c
1111 redef fun iterator_from
(i
) do return new RopeBufferCharIterator.from
(target
, i
)
1113 redef fun reverse_iterator_from
(i
) do return new RopeBufferCharReverseIterator.from
(target
, i
)
1116 # An Iterator over a RopeBuffer.
1117 class RopeBufferByteIterator
1118 super IndexedIterator[Byte]
1121 var sit
: IndexedIterator[Byte]
1123 # Native string iterated over.
1124 var ns
: NativeString
1126 # Current position in `ns`.
1129 # Maximum position iterable.
1134 # Init the iterator from a RopeBuffer.
1135 init(t
: RopeBuffer) is old_style_init
do
1138 sit
= t
.str
.bytes
.iterator
1143 # Init the iterator from a RopeBuffer starting from `pos`.
1144 init from
(t
: RopeBuffer, pos
: Int) do
1147 sit
= t
.str
.bytes
.iterator_from
(pos
)
1148 pns
= pos
- t
.str
.length
1152 redef fun is_ok
do return index
< maxpos
1155 if sit
.is_ok
then return sit
.item
1169 # Reverse iterator over a RopeBuffer.
1170 class RopeBufferByteReverseIterator
1171 super IndexedIterator[Byte]
1174 var sit
: IndexedIterator[Byte]
1176 # Native string iterated over.
1177 var ns
: NativeString
1179 # Current position in `ns`.
1184 # Init the iterator from a RopeBuffer.
1185 init(tgt
: RopeBuffer) is old_style_init
do
1186 sit
= tgt
.str
.bytes
.reverse_iterator
1188 index
= tgt
.bytelen
- 1
1192 # Init the iterator from a RopeBuffer starting from `pos`.
1193 init from
(tgt
: RopeBuffer, pos
: Int) do
1194 sit
= tgt
.str
.bytes
.reverse_iterator_from
(pos
- (tgt
.rpos
- tgt
.dumped
))
1195 pns
= pos
- tgt
.str
.bytelen
+ tgt
.rpos
1200 redef fun is_ok
do return index
>= 0
1203 if pns
>= 0 then return ns
[pns
]
1217 # View on the chars of a `RopeBuffer`
1218 class RopeBufferBytes
1219 super BufferByteView
1221 redef type SELFTYPE: RopeBuffer
1224 if i
< target
.str
.bytelen
then
1225 return target
.str
.bytes
[i
]
1227 return target
.ns
[i
- target
.str
.bytelen
]
1231 redef fun iterator_from
(i
) do return new RopeBufferByteIterator.from
(target
, i
)
1233 redef fun reverse_iterator_from
(i
) do return new RopeBufferByteReverseIterator.from
(target
, i
)