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
112 length
= l
.length
+ r
.length
113 _bytelen
= l
.bytelen
+ r
.bytelen
121 redef fun iterator
do return new RopeCharIterator(self)
125 for j
in [1 .. i
[ do x
+= self
130 if flat_last_pos_start
!= -1 then
131 var fsp
= i
- flat_last_pos_start
132 if fsp
>= 0 and fsp
< flat_cache
.length
then return flat_cache
[fsp
]
137 if s
isa FlatString then break
140 var llen
= lft
.length
148 flat_last_pos_start
= st
- i
153 redef fun substring
(from
, len
) do
155 var llen
= lft
.length
157 if from
+ len
< llen
then return lft
.substring
(from
,len
)
158 var lsublen
= llen
- from
159 return lft
.substring_from
(from
) + _right
.substring
(0, len
- lsublen
)
161 return _right
.substring
(from
- llen
, len
)
165 redef fun reversed
do return new Concat(_right
.reversed
, _left
.reversed
)
167 redef fun insert_at
(s
, pos
) do
169 if pos
> lft
.length
then
170 return lft
+ _right
.insert_at
(s
, pos
- lft
.length
)
172 return lft
.insert_at
(s
, pos
) + _right
175 redef fun to_upper
do return new Concat(_left
.to_upper
, _right
.to_upper
)
177 redef fun to_lower
do return new Concat(_left
.to_lower
, _right
.to_lower
)
183 return new Concat(self, s
)
187 if rlen
+ slen
> maxlen
then return new Concat(self, s
)
188 return new Concat(_left
, r
+ s
)
192 redef fun copy_to_native
(dest
, n
, src_offset
, dest_offset
) do
193 var subs
= new RopeSubstrings.from
(self, src_offset
)
194 var st
= src_offset
- subs
.pos
195 var off
= dest_offset
198 if n
> it
.length
then
199 var cplen
= it
.length
- st
200 it
._items
.copy_to
(dest
, cplen
, st
, off
)
204 it
._items
.copy_to
(dest
, n
, st
, off
)
212 # Returns a balanced version of `self`
213 fun balance
: String do
214 var children
= new Array[String]
216 var iter
: nullable RopeCharIteratorPiece = new RopeCharIteratorPiece(self, false, false, null)
218 if iter
== null then break
220 if not rnod
isa Concat then
225 if not iter
.ldone
then
227 iter
= new RopeCharIteratorPiece(rnod
._left
, false, false, iter
)
228 else if not iter
.rdone
then
230 iter
= new RopeCharIteratorPiece(rnod
._right
, false, false, iter
)
236 return recurse_balance
(children
, children
.length
)
239 fun recurse_balance
(nodes
: Array[String], len
: Int): String do
243 if len
- stpos
> 1 then
244 nodes
[finpos
] = new Concat(nodes
[stpos
], nodes
[stpos
+ 1])
247 nodes
[finpos
] = nodes
[stpos
]
252 if finpos
== 1 then return nodes
[0]
253 return recurse_balance
(nodes
, finpos
)
257 # Mutable `Rope`, optimized for concatenation operations
259 # A `RopeBuffer` is an efficient way of building a `String` when
260 # concatenating small strings.
262 # It does concatenations in an optimized way by having a
263 # mutable part and an immutable part built by efficiently
264 # concatenating strings in chain.
266 # Every concatenation operation is done by copying a string to
267 # the mutable part and flushing it when full.
269 # However, when a long string is appended to the `Buffer`,
270 # the concatenation is done at it would be in a `Rope`.
275 redef var chars
: Sequence[Char] is lazy
do return new RopeBufferChars(self)
277 redef var bytes
is lazy
do return new RopeBufferBytes(self)
279 # The final string being built on the fly
280 private var str
: String = ""
282 # Current concatenation buffer
283 private var ns
: NativeString is noinit
285 # Next available (e.g. unset) character in the `Buffer`
288 # Length (in chars) of the buffered part
289 private var nslen
= 0
291 # Keeps track of the buffer's currently dumped part
293 # This might happen if for instance, a String was being
294 # built by concatenating small parts of string and suddenly
295 # a long string (length > maxlen) is appended.
296 private var dumped
: Int is noinit
298 # Length of the complete rope in chars (0)
309 # Length of the complete rope in bytes
310 redef var bytelen
= 0
312 # Length of the mutable part (in bytes)
314 # Is also used as base to compute the size of the next
315 # mutable native string (`ns`)
316 private var buf_size
: Int is noinit
318 redef fun substrings
do return new RopeBufSubstringIterator(self)
320 # Builds an empty `RopeBuffer`
322 ns
= new NativeString(maxlen
)
327 # Builds a new `RopeBuffer` with `str` in it.
328 init from
(str
: String) do
330 ns
= new NativeString(maxlen
)
332 _bytelen
= str
.length
336 # Resets the informations of the `Buffer`
338 # This is called when doing in-place modifications
339 # on a previously to_s'd `RopeBuffer`
341 var nns
= new NativeString(buf_size
)
342 var blen
= rpos
- dumped
343 ns
.copy_to
(nns
, blen
, dumped
, 0)
351 if i
< str
.length
then
354 var index
= ns
.char_to_byte_index_cached
(i
- str
.length
, 0, dumped
)
355 return ns
.char_at
(index
)
359 redef fun []=(i
, c
) do
360 assert i
>= 0 and i
<= length
361 if i
== length
then add c
362 if i
< str
.length
then
363 _bytelen
+= c
.u8char_len
- str
[i
].u8char_len
365 var l
= s
.substring
(0, i
)
366 var r
= s
.substring_from
(i
+ 1)
369 var reali
= i
- str
.length
370 var index
= ns
.char_to_byte_index_cached
(reali
, 0, dumped
)
371 var st_nxt
= ns
.char_to_byte_index_cached
(reali
+ 1, reali
, index
)
372 var loc_c
= ns
.char_at
(index
)
373 if loc_c
.u8char_len
!= c
.u8char_len
then
374 var delta
= c
.u8char_len
- loc_c
.u8char_len
375 var remsp
= buf_size
- rpos
376 if remsp
< delta
then
378 var nns
= new NativeString(buf_size
)
379 ns
.copy_to
(nns
, index
- dumped
, dumped
, 0)
380 ns
.copy_to
(nns
, rpos
- index
- loc_c
.u8char_len
, index
+ loc_c
.u8char_len
, index
- dumped
+ delta
)
382 index
= index
- dumped
384 ns
.copy_to
(ns
, rpos
- st_nxt
, st_nxt
, st_nxt
+ delta
)
389 ns
.set_char_at
(index
, c
)
393 redef fun empty
do return new RopeBuffer
401 ns
= new NativeString(buf_size
)
406 redef fun substring
(from
, count
) do
407 var strlen
= str
.length
411 if count
< 0 then count
= 0
415 if count
> length
then count
= length
- from
417 if count
== 0 then return empty
419 if from
< strlen
then
420 var subpos
= strlen
- from
421 if count
<= subpos
then
422 return new RopeBuffer.from
(str
.substring
(from
, count
))
424 var l
= str
.substring_from
(from
)
425 var rem
= count
- subpos
426 var nns
= new NativeString(rem
)
427 ns
.copy_to
(nns
, rem
, dumped
, 0)
428 return new RopeBuffer.from
(l
+ nns
.to_s_with_length
(rem
))
431 var nns
= new NativeString(count
)
432 ns
.copy_to
(nns
, count
, dumped
, 0)
433 return new RopeBuffer.from
(nns
.to_s_with_length
(count
))
437 redef fun append
(s
) do
439 if slen
>= maxlen
then
444 if s
isa FlatText then
446 var from
= s
.first_byte
447 var remsp
= buf_size
- rpos
448 if slen
<= remsp
then
449 oits
.copy_to
(ns
, slen
, from
, rpos
)
453 var brk
= oits
.find_beginning_of_char_at
(from
+ remsp
)
454 oits
.copy_to
(ns
, brk
, from
, rpos
)
457 oits
.copy_to
(ns
, slen
- remsp
, brk
, 0)
460 for i
in s
.substrings
do append i
466 var remsp
= buf_size
- rp
467 var cln
= c
.u8char_len
472 ns
.set_char_at
(rp
, c
)
478 # Converts the Buffer to a FlatString, appends it to
479 # the final String and re-allocates a new larger Buffer.
480 private fun dump_buffer
do
482 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
486 ns
= new NativeString(bs
)
492 # Similar to dump_buffer, but does not reallocate a new NativeString
493 private fun persist_buffer
do
494 if rpos
== dumped
then return
495 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
502 new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1).output
505 # Enlarge is useless here since the `Buffer`
506 # part is automatically dumped when necessary.
508 # Also, since the buffer can not be overused by a
509 # single string, there is no need for manual
512 # "You have no power here !"
513 redef fun enlarge
(i
) do end
522 # Flush the buffer in order to only have to reverse `str`.
523 if rpos
> 0 and dumped
!= rpos
then
524 str
+= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
531 if written
then reset
537 if written
then reset
543 redef class FlatString
545 redef fun insert_at
(s
, pos
) do
546 var l
= substring
(0, pos
)
547 var r
= substring_from
(pos
)
555 if slen
== 0 then return self
556 if mlen
== 0 then return s
557 var nlen
= slen
+ mlen
558 if s
isa FlatString then
559 if nlen
> maxlen
then return new Concat(self, s
)
561 var sifrom
= s
._first_byte
562 var mifrom
= _first_byte
564 var ns
= new NativeString(nlen
+ 1)
565 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
566 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
567 return new FlatString.full
(ns
, nlen
, 0, nlen
- 1, length
+ s
.length
)
568 else if s
isa Concat then
570 var sllen
= sl
.bytelen
571 if sllen
+ mlen
> maxlen
then return new Concat(self, s
)
572 return new Concat(self + sl
, s
._right
)
579 # A simple linked list for use with iterators
580 private class RopeCharIteratorPiece
581 # The encapsulated node of the `Rope`
583 # Was its _left child (if any) visited ?
585 # Was its _right child (if any) visited ?
587 # The previous node in the list.
588 var prev
: nullable RopeCharIteratorPiece
591 # A reverse iterator capable of working with `Rope` objects
592 private class RopeByteReverseIterator
593 super IndexedIterator[Byte]
595 # Current NativeString
597 # Current position in NativeString
599 # Position in the Rope (0-indexed)
601 # Iterator on the substrings, does the Postfix part of
602 # the Rope traversal.
603 var subs
: IndexedIterator[FlatString]
605 init(root
: Concat) is old_style_init
do
606 pos
= root
._bytelen
- 1
607 subs
= new ReverseRopeSubstrings(root
)
613 init from
(root
: Concat, pos
: Int) do
615 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
618 pns
= pos
- subs
.index
621 redef fun index
do return pos
623 redef fun is_ok
do return pos
>= 0
625 redef fun item
do return ns
[pns
]
630 if pns
>= 0 then return
631 if not subs
.is_ok
then return
633 if not subs
.is_ok
then return
640 # Forward iterator on the bytes of a `Rope`
641 private class RopeByteIterator
642 super IndexedIterator[Byte]
644 # Position in current `String`
646 # Current `String` being iterated on
648 # Substrings of the Rope
649 var subs
: IndexedIterator[FlatString]
650 # Maximum position to iterate on (e.g. Rope.length)
652 # Position (char) in the Rope (0-indexed)
655 init(root
: Concat) is old_style_init
do
656 subs
= new RopeSubstrings(root
)
658 ns
= subs
.item
._items
659 max
= root
.length
- 1
663 init from
(root
: Concat, pos
: Int) do
664 subs
= new RopeSubstrings.from
(root
, pos
)
665 pns
= pos
- subs
.index
667 ns
= subs
.item
._items
668 max
= root
.length
- 1
671 redef fun item
do return ns
[pns
]
673 redef fun is_ok
do return pos
<= max
675 redef fun index
do return pos
680 if pns
< subs
.item
._bytelen
then return
681 if not subs
.is_ok
then return
683 if not subs
.is_ok
then return
684 ns
= subs
.item
._items
690 # A reverse iterator capable of working with `Rope` objects
691 private class RopeCharReverseIterator
692 super IndexedIterator[Char]
694 # Current NativeString
696 # Current position in NativeString
698 # Position in the Rope (0-indexed)
700 # Iterator on the substrings, does the Postfix part of
701 # the Rope traversal.
702 var subs
: IndexedIterator[String]
704 init(root
: Concat) is old_style_init
do
705 pos
= root
.length
- 1
706 subs
= new ReverseRopeSubstrings(root
)
711 init from
(root
: Concat, pos
: Int) do
713 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
715 pns
= pos
- subs
.index
718 redef fun index
do return pos
720 redef fun is_ok
do return pos
>= 0
722 redef fun item
do return ns
[pns
]
727 if pns
>= 0 then return
728 if not subs
.is_ok
then return
730 if not subs
.is_ok
then return
736 # Forward iterator on the chars of a `Rope`
737 private class RopeCharIterator
738 super IndexedIterator[Char]
740 # Position in current `String`
742 # Current `String` being iterated on
744 # Substrings of the Rope
745 var subs
: IndexedIterator[String]
746 # Maximum position to iterate on (e.g. Rope.length)
748 # Position (char) in the Rope (0-indexed)
751 init(root
: Concat) is old_style_init
do
752 subs
= new RopeSubstrings(root
)
755 max
= root
.length
- 1
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(root
: Concat) is old_style_init
do
798 var r
= new RopeCharIteratorPiece(root
, false, true, null)
799 pos
= root
.length
- 1
800 var lnod
: String = root
802 if lnod
isa Concat then
804 r
= new RopeCharIteratorPiece(lnod
, false, true, r
)
806 str
= lnod
.as(FlatString)
813 init from
(root
: Concat, pos
: Int) do
814 var r
= new RopeCharIteratorPiece(root
, false, true, null)
815 var rnod
: String = root
818 if rnod
isa Concat then
819 if off
>= rnod
._left
.length
then
820 off
-= rnod
._left
.length
822 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
826 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
829 str
= rnod
.as(FlatString)
838 redef fun item
do return str
840 redef fun index
do return pos
842 redef fun is_ok
do return pos
>= 0
845 if pos
< 0 then return
847 var currit
= curr
.node
848 while curr
!= null do
850 if not currit
isa Concat then
851 str
= currit
.as(FlatString)
856 if not curr
.rdone
then
858 curr
= new RopeCharIteratorPiece(currit
._right
, false, false, curr
)
861 if not curr
.ldone
then
863 curr
= new RopeCharIteratorPiece(currit
._left
, false, false, curr
)
872 private class RopeBufSubstringIterator
873 super Iterator[FlatText]
875 # Iterator on the substrings of the building string
876 var iter
: Iterator[FlatText]
877 # Makes a String out of the buffered part of the Ropebuffer
878 var nsstr
: FlatString
879 # Did we attain the buffered part ?
880 var nsstr_done
= false
882 init(str
: RopeBuffer) is old_style_init
do
883 iter
= str
.str
.substrings
884 nsstr
= new FlatString.with_infos
(str
.ns
, str
.rpos
- str
.dumped
, str
.dumped
, str
.rpos
- 1)
885 if str
.length
== 0 then nsstr_done
= true
888 redef fun is_ok
do return iter
.is_ok
or not nsstr_done
892 if iter
.is_ok
then return iter
.item
905 # Substrings of a Rope (i.e. Postfix iterator on leaves)
906 private class RopeSubstrings
907 super IndexedIterator[FlatString]
910 var iter
: RopeCharIteratorPiece is noinit
912 var pos
: Int is noinit
913 # Maximum position in `Rope` (i.e. length - 1)
914 var max
: Int is noinit
917 var str
: FlatString is noinit
919 init(root
: Concat) is old_style_init
do
920 var r
= new RopeCharIteratorPiece(root
, true, false, null)
922 max
= root
.length
- 1
923 var rnod
: String = root
925 if rnod
isa Concat then
927 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
929 str
= rnod
.as(FlatString)
937 init from
(root
: Concat, pos
: Int) do
938 var r
= new RopeCharIteratorPiece(root
, true, false, null)
939 max
= root
.length
- 1
940 var rnod
: String = root
943 if rnod
isa Concat then
944 if off
>= rnod
._left
.length
then
946 off
-= rnod
._left
.length
948 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
951 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
954 str
= rnod
.as(FlatString)
963 redef fun item
do return str
965 redef fun is_ok
do return pos
<= max
967 redef fun index
do return pos
971 if pos
> max
then return
975 if not rnod
isa Concat then
978 str
= rnod
.as(FlatString)
979 iter
= it
.as(not null)
985 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
986 else if not it
.rdone
then
989 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
999 # Implementation of a `StringCharView` for `Concat` objects
1000 private class RopeChars
1001 super StringCharView
1003 redef type SELFTYPE: Concat
1009 redef fun iterator_from
(i
) do return new RopeCharIterator.from
(target
, i
)
1011 redef fun reverse_iterator_from
(i
) do return new RopeCharReverseIterator.from
(target
, i
)
1015 # Implementation of a `StringCharView` for `Concat` objects
1016 private class RopeBytes
1017 super StringByteView
1019 redef type SELFTYPE: Concat
1022 var nod
: String = target
1024 if nod
isa FlatString then return nod
._items
[i
]
1025 if not nod
isa Concat then abort
1027 if lft
.bytelen
>= i
then
1035 redef fun iterator_from
(i
) do return new RopeByteIterator.from
(target
, i
)
1037 redef fun reverse_iterator_from
(i
) do return new RopeByteReverseIterator.from
(target
, i
)
1041 # An Iterator over a RopeBuffer.
1042 class RopeBufferCharIterator
1043 super IndexedIterator[Char]
1046 var sit
: IndexedIterator[Char]
1048 redef fun index
do return sit
.index
1050 # Init the iterator from a RopeBuffer.
1051 init(t
: RopeBuffer) is old_style_init
do
1053 sit
= t
.str
.chars
.iterator
1056 # Init the iterator from a RopeBuffer starting from `pos`.
1057 init from
(t
: RopeBuffer, pos
: Int) do
1059 sit
= t
.str
.chars
.iterator_from
(pos
)
1062 redef fun is_ok
do return sit
.is_ok
1069 redef fun next
do sit
.next
1072 # Reverse iterator over a RopeBuffer.
1073 class RopeBufferCharReverseIterator
1074 super IndexedIterator[Char]
1077 var sit
: IndexedIterator[Char]
1079 redef fun index
do return sit
.index
1081 # Init the iterator from a RopeBuffer.
1082 init(tgt
: RopeBuffer) is old_style_init
do
1084 sit
= tgt
.str
.chars
.reverse_iterator
1087 # Init the iterator from a RopeBuffer starting from `pos`.
1088 init from
(tgt
: RopeBuffer, pos
: Int) do
1090 sit
= tgt
.str
.chars
.reverse_iterator_from
(pos
)
1093 redef fun is_ok
do return sit
.is_ok
1100 redef fun next
do sit
.next
1103 # View on the chars of a `RopeBuffer`
1104 class RopeBufferChars
1105 super BufferCharView
1107 redef type SELFTYPE: RopeBuffer
1109 redef fun [](i
) do return target
[i
]
1111 redef fun []=(i
,c
) do target
[i
] = c
1113 redef fun add
(c
) do target
.add c
1115 redef fun push
(c
) do target
.add c
1117 redef fun iterator_from
(i
) do return new RopeBufferCharIterator.from
(target
, i
)
1119 redef fun reverse_iterator_from
(i
) do return new RopeBufferCharReverseIterator.from
(target
, i
)
1122 # An Iterator over a RopeBuffer.
1123 class RopeBufferByteIterator
1124 super IndexedIterator[Byte]
1127 var sit
: IndexedIterator[Byte]
1129 # Native string iterated over.
1130 var ns
: NativeString
1132 # Current position in `ns`.
1135 # Maximum position iterable.
1140 # Init the iterator from a RopeBuffer.
1141 init(t
: RopeBuffer) is old_style_init
do
1144 sit
= t
.str
.bytes
.iterator
1149 # Init the iterator from a RopeBuffer starting from `pos`.
1150 init from
(t
: RopeBuffer, pos
: Int) do
1153 sit
= t
.str
.bytes
.iterator_from
(pos
)
1154 pns
= pos
- t
.str
.length
1158 redef fun is_ok
do return index
< maxpos
1161 if sit
.is_ok
then return sit
.item
1175 # Reverse iterator over a RopeBuffer.
1176 class RopeBufferByteReverseIterator
1177 super IndexedIterator[Byte]
1180 var sit
: IndexedIterator[Byte]
1182 # Native string iterated over.
1183 var ns
: NativeString
1185 # Current position in `ns`.
1190 # Init the iterator from a RopeBuffer.
1191 init(tgt
: RopeBuffer) is old_style_init
do
1192 sit
= tgt
.str
.bytes
.reverse_iterator
1194 index
= tgt
._bytelen
- 1
1198 # Init the iterator from a RopeBuffer starting from `pos`.
1199 init from
(tgt
: RopeBuffer, pos
: Int) do
1200 sit
= tgt
.str
.bytes
.reverse_iterator_from
(pos
- (tgt
.rpos
- tgt
.dumped
))
1201 pns
= pos
- tgt
.str
.bytelen
+ tgt
.rpos
1206 redef fun is_ok
do return index
>= 0
1209 if pns
>= 0 then return ns
[pns
]
1223 # View on the chars of a `RopeBuffer`
1224 class RopeBufferBytes
1225 super BufferByteView
1227 redef type SELFTYPE: RopeBuffer
1230 if i
< target
.str
.bytelen
then
1231 return target
.str
.bytes
[i
]
1233 return target
.ns
[i
- target
.str
.bytelen
]
1237 redef fun iterator_from
(i
) do return new RopeBufferByteIterator.from
(target
, i
)
1239 redef fun reverse_iterator_from
(i
) do return new RopeBufferByteReverseIterator.from
(target
, i
)