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
123 redef fun iterator
do return new RopeCharIterator.from
(self, 0)
127 for j
in [1 .. i
[ do x
+= self
132 assert i
>= 0 and i
<= _length
133 var flps
= _flat_last_pos_start
134 if flps
!= -1 and i
>= flps
and i
<= _flat_last_pos_end
then
135 return _flat_cache
.fetch_char_at
(i
- flps
)
137 var lf
= get_leaf_at
(i
)
138 return lf
.fetch_char_at
(i
- _flat_last_pos_start
)
141 fun get_leaf_at
(pos
: Int): FlatString do
142 var flps
= _flat_last_pos_start
143 if flps
!= -1 and pos
>= flps
and pos
<= _flat_last_pos_end
then
149 if s
isa FlatString then break
152 var llen
= lft
.length
160 _flat_last_pos_start
= st
- pos
161 _flat_last_pos_end
= st
- pos
+ s
.length
- 1
166 redef fun substring
(from
, count
) do
169 if count
< 0 then return ""
174 if (count
+ from
) > ln
then count
= ln
- from
175 if count
<= 0 then return ""
176 var end_index
= from
+ count
- 1
178 var flps
= _flat_last_pos_start
179 if flps
!= -1 and from
>= flps
and end_index
<= _flat_last_pos_end
then
180 return _flat_cache
.substring_impl
(from
- flps
, count
, end_index
- flps
)
184 var llen
= lft
.length
186 if from
+ count
< llen
then return lft
.substring
(from
, count
)
187 var lsublen
= llen
- from
188 return lft
.substring_from
(from
) + _right
.substring
(0, count
- lsublen
)
190 return _right
.substring
(from
- llen
, count
)
194 redef fun reversed
do return new Concat(_right
.reversed
, _left
.reversed
)
196 redef fun insert_at
(s
, pos
) do
198 if pos
> lft
.length
then
199 return lft
+ _right
.insert_at
(s
, pos
- lft
.length
)
201 return lft
.insert_at
(s
, pos
) + _right
204 redef fun to_upper
do return new Concat(_left
.to_upper
, _right
.to_upper
)
206 redef fun to_lower
do return new Concat(_left
.to_lower
, _right
.to_lower
)
212 return new Concat(self, s
)
216 if rlen
+ slen
> maxlen
then return new Concat(self, s
)
217 return new Concat(_left
, r
+ s
)
221 redef fun copy_to_native
(dest
, n
, src_offset
, dest_offset
) do
222 var subs
= new RopeSubstrings.from
(self, src_offset
)
223 var st
= src_offset
- subs
.pos
224 var off
= dest_offset
227 if n
> it
.length
then
228 var cplen
= it
.length
- st
229 it
._items
.copy_to
(dest
, cplen
, st
, off
)
233 it
._items
.copy_to
(dest
, n
, st
, off
)
241 # Returns a balanced version of `self`
242 fun balance
: String do
243 var children
= new Array[String]
245 var iter
: nullable RopeCharIteratorPiece = new RopeCharIteratorPiece(self, false, false, null)
247 if iter
== null then break
249 if not rnod
isa Concat then
254 if not iter
.ldone
then
256 iter
= new RopeCharIteratorPiece(rnod
._left
, false, false, iter
)
257 else if not iter
.rdone
then
259 iter
= new RopeCharIteratorPiece(rnod
._right
, false, false, iter
)
265 return recurse_balance
(children
, children
.length
)
268 fun recurse_balance
(nodes
: Array[String], len
: Int): String do
272 if len
- stpos
> 1 then
273 nodes
[finpos
] = new Concat(nodes
[stpos
], nodes
[stpos
+ 1])
276 nodes
[finpos
] = nodes
[stpos
]
281 if finpos
== 1 then return nodes
[0]
282 return recurse_balance
(nodes
, finpos
)
286 # Mutable `Rope`, optimized for concatenation operations
288 # A `RopeBuffer` is an efficient way of building a `String` when
289 # concatenating small strings.
291 # It does concatenations in an optimized way by having a
292 # mutable part and an immutable part built by efficiently
293 # concatenating strings in chain.
295 # Every concatenation operation is done by copying a string to
296 # the mutable part and flushing it when full.
298 # However, when a long string is appended to the `Buffer`,
299 # the concatenation is done at it would be in a `Rope`.
304 redef var chars
: Sequence[Char] is lazy
do return new RopeBufferChars(self)
306 redef var bytes
is lazy
do return new RopeBufferBytes(self)
308 # The final string being built on the fly
309 private var str
: String = ""
311 # Current concatenation buffer
312 private var ns
: NativeString is noinit
314 # Next available (e.g. unset) character in the `Buffer`
317 # Length (in chars) of the buffered part
318 private var nslen
= 0
320 # Keeps track of the buffer's currently dumped part
322 # This might happen if for instance, a String was being
323 # built by concatenating small parts of string and suddenly
324 # a long string (length > maxlen) is appended.
325 private var dumped
: Int is noinit
327 # Length of the complete rope in chars (0)
338 # Length of the complete rope in bytes
339 redef var bytelen
= 0
341 # Length of the mutable part (in bytes)
343 # Is also used as base to compute the size of the next
344 # mutable native string (`ns`)
345 private var buf_size
: Int is noinit
347 redef fun substrings
do return new RopeBufSubstringIterator.from
(self)
349 # Builds an empty `RopeBuffer`
351 ns
= new NativeString(maxlen
)
356 # Builds a new `RopeBuffer` with `str` in it.
357 init from
(str
: String) do
359 ns
= new NativeString(maxlen
)
361 _bytelen
= str
.length
365 # Resets the informations of the `Buffer`
367 # This is called when doing in-place modifications
368 # on a previously to_s'd `RopeBuffer`
370 var nns
= new NativeString(buf_size
)
371 var blen
= rpos
- dumped
372 ns
.copy_to
(nns
, blen
, dumped
, 0)
380 if i
< str
.length
then
383 var index
= ns
.char_to_byte_index_cached
(i
- str
.length
, 0, dumped
)
384 return ns
.char_at
(index
)
388 redef fun []=(i
, c
) do
389 assert i
>= 0 and i
<= length
390 if i
== length
then add c
391 if i
< str
.length
then
392 _bytelen
+= c
.u8char_len
- str
[i
].u8char_len
394 var l
= s
.substring
(0, i
)
395 var r
= s
.substring_from
(i
+ 1)
398 var reali
= i
- str
.length
399 var index
= ns
.char_to_byte_index_cached
(reali
, 0, dumped
)
400 var st_nxt
= ns
.char_to_byte_index_cached
(reali
+ 1, reali
, index
)
401 var loc_c
= ns
.char_at
(index
)
402 if loc_c
.u8char_len
!= c
.u8char_len
then
403 var delta
= c
.u8char_len
- loc_c
.u8char_len
404 var remsp
= buf_size
- rpos
405 if remsp
< delta
then
407 var nns
= new NativeString(buf_size
)
408 ns
.copy_to
(nns
, index
- dumped
, dumped
, 0)
409 ns
.copy_to
(nns
, rpos
- index
- loc_c
.u8char_len
, index
+ loc_c
.u8char_len
, index
- dumped
+ delta
)
411 index
= index
- dumped
413 ns
.copy_to
(ns
, rpos
- st_nxt
, st_nxt
, st_nxt
+ delta
)
418 ns
.set_char_at
(index
, c
)
422 redef fun empty
do return new RopeBuffer
430 ns
= new NativeString(buf_size
)
435 redef fun substring
(from
, count
) do
436 var strlen
= str
.length
440 if count
< 0 then count
= 0
444 if count
> length
then count
= length
- from
446 if count
== 0 then return empty
448 if from
< strlen
then
449 var subpos
= strlen
- from
450 if count
<= subpos
then
451 return new RopeBuffer.from
(str
.substring
(from
, count
))
453 var l
= str
.substring_from
(from
)
454 var rem
= count
- subpos
455 var nns
= new NativeString(rem
)
456 ns
.copy_to
(nns
, rem
, dumped
, 0)
457 return new RopeBuffer.from
(l
+ nns
.to_s_unsafe
(rem
))
460 var nns
= new NativeString(count
)
461 ns
.copy_to
(nns
, count
, dumped
, 0)
462 return new RopeBuffer.from
(nns
.to_s_unsafe
(count
))
466 redef fun append
(s
) do
468 if slen
>= maxlen
then
473 if s
isa FlatText then
475 var from
= s
.first_byte
476 var remsp
= buf_size
- rpos
477 if slen
<= remsp
then
478 oits
.copy_to
(ns
, slen
, from
, rpos
)
482 var brk
= oits
.find_beginning_of_char_at
(from
+ remsp
)
483 oits
.copy_to
(ns
, brk
, from
, rpos
)
486 oits
.copy_to
(ns
, slen
- remsp
, brk
, 0)
489 for i
in s
.substrings
do append i
495 var remsp
= buf_size
- rp
496 var cln
= c
.u8char_len
501 ns
.set_char_at
(rp
, c
)
507 # Converts the Buffer to a FlatString, appends it to
508 # the final String and re-allocates a new larger Buffer.
509 private fun dump_buffer
do
511 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
)
515 ns
= new NativeString(bs
)
521 # Similar to dump_buffer, but does not reallocate a new NativeString
522 private fun persist_buffer
do
523 if rpos
== dumped
then return
524 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
)
531 new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
).output
534 # Enlarge is useless here since the `Buffer`
535 # part is automatically dumped when necessary.
537 # Also, since the buffer can not be overused by a
538 # single string, there is no need for manual
541 # "You have no power here !"
542 redef fun enlarge
(i
) do end
551 # Flush the buffer in order to only have to reverse `str`.
552 if rpos
> 0 and dumped
!= rpos
then
553 str
+= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
)
560 if written
then reset
566 if written
then reset
572 redef class FlatString
574 redef fun insert_at
(s
, pos
) do
575 var l
= substring
(0, pos
)
576 var r
= substring_from
(pos
)
584 if slen
== 0 then return self
585 if mlen
== 0 then return s
586 var nlen
= slen
+ mlen
587 if s
isa FlatString then
588 if nlen
> maxlen
then return new Concat(self, s
)
590 var sifrom
= s
._first_byte
591 var mifrom
= _first_byte
593 var ns
= new NativeString(nlen
+ 1)
594 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
595 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
596 return new FlatString.full
(ns
, nlen
, 0, length
+ s
.length
)
597 else if s
isa Concat then
599 var sllen
= sl
.bytelen
600 if sllen
+ mlen
> maxlen
then return new Concat(self, s
)
601 return new Concat(self + sl
, s
._right
)
608 # A simple linked list for use with iterators
609 private class RopeCharIteratorPiece
610 # The encapsulated node of the `Rope`
612 # Was its _left child (if any) visited ?
614 # Was its _right child (if any) visited ?
616 # The previous node in the list.
617 var prev
: nullable RopeCharIteratorPiece
620 # A reverse iterator capable of working with `Rope` objects
621 private class RopeByteReverseIterator
622 super IndexedIterator[Byte]
624 # Current NativeString
625 var ns
: NativeString is noautoinit
626 # Current position in NativeString
627 var pns
: Int is noautoinit
628 # Position in the Rope (0-indexed)
629 var pos
: Int is noautoinit
630 # Iterator on the substrings, does the Postfix part of
631 # the Rope traversal.
632 var subs
: IndexedIterator[FlatString] is noautoinit
634 init from
(root
: Concat, pos
: Int) do
636 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
639 pns
= pos
- subs
.index
642 redef fun index
do return pos
644 redef fun is_ok
do return pos
>= 0
646 redef fun item
do return ns
[pns
]
651 if pns
>= 0 then return
652 if not subs
.is_ok
then return
654 if not subs
.is_ok
then return
661 # Forward iterator on the bytes of a `Rope`
662 private class RopeByteIterator
663 super IndexedIterator[Byte]
665 # Position in current `String`
666 var pns
: Int is noautoinit
667 # Current `String` being iterated on
668 var ns
: NativeString is noautoinit
669 # Substrings of the Rope
670 var subs
: IndexedIterator[FlatString] is noautoinit
671 # Maximum position to iterate on (e.g. Rope.length)
672 var max
: Int is noautoinit
673 # Position (char) in the Rope (0-indexed)
674 var pos
: Int is noautoinit
676 init from
(root
: Concat, pos
: Int) do
677 subs
= new RopeSubstrings.from
(root
, pos
)
678 pns
= pos
- subs
.index
680 ns
= subs
.item
._items
681 max
= root
.length
- 1
684 redef fun item
do return ns
[pns
]
686 redef fun is_ok
do return pos
<= max
688 redef fun index
do return pos
693 if pns
< subs
.item
._bytelen
then return
694 if not subs
.is_ok
then return
696 if not subs
.is_ok
then return
697 ns
= subs
.item
._items
703 # A reverse iterator capable of working with `Rope` objects
704 private class RopeCharReverseIterator
705 super IndexedIterator[Char]
707 # Current NativeString
708 var ns
: String is noautoinit
709 # Current position in NativeString
710 var pns
: Int is noautoinit
711 # Position in the Rope (0-indexed)
712 var pos
: Int is noautoinit
713 # Iterator on the substrings, does the Postfix part of
714 # the Rope traversal.
715 var subs
: IndexedIterator[String] is noautoinit
717 init from
(root
: Concat, pos
: Int) do
719 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
721 pns
= pos
- subs
.index
724 redef fun index
do return pos
726 redef fun is_ok
do return pos
>= 0
728 redef fun item
do return ns
[pns
]
733 if pns
>= 0 then return
734 if not subs
.is_ok
then return
736 if not subs
.is_ok
then return
742 # Forward iterator on the chars of a `Rope`
743 private class RopeCharIterator
744 super IndexedIterator[Char]
746 # Position in current `String`
747 var pns
: Int is noautoinit
748 # Current `String` being iterated on
749 var str
: String is noautoinit
750 # Substrings of the Rope
751 var subs
: IndexedIterator[String] is noautoinit
752 # Maximum position to iterate on (e.g. Rope.length)
753 var max
: Int is noautoinit
754 # Position (char) in the Rope (0-indexed)
755 var pos
: Int is noautoinit
757 init from
(root
: Concat, pos
: Int) do
758 subs
= new RopeSubstrings.from
(root
, pos
)
759 pns
= pos
- subs
.index
762 max
= root
.length
- 1
765 redef fun item
do return str
[pns
]
767 redef fun is_ok
do return pos
<= max
769 redef fun index
do return pos
774 if pns
< subs
.item
.length
then return
775 if not subs
.is_ok
then return
777 if not subs
.is_ok
then return
783 # Substrings of a Rope (i.e. Reverse postfix iterator on leaves)
784 private class ReverseRopeSubstrings
785 super IndexedIterator[FlatString]
788 var iter
: RopeCharIteratorPiece is noinit
790 var pos
: Int is noinit
793 var str
: FlatString is noinit
795 init from
(root
: Concat, pos
: Int) do
796 var r
= new RopeCharIteratorPiece(root
, false, true, null)
797 var rnod
: String = root
800 if rnod
isa Concat then
801 if off
>= rnod
._left
.length
then
802 off
-= rnod
._left
.length
804 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
808 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
811 str
= rnod
.as(FlatString)
820 redef fun item
do return str
822 redef fun index
do return pos
824 redef fun is_ok
do return pos
>= 0
827 if pos
< 0 then return
829 var currit
= curr
.node
830 while curr
!= null do
832 if not currit
isa Concat then
833 str
= currit
.as(FlatString)
838 if not curr
.rdone
then
840 curr
= new RopeCharIteratorPiece(currit
._right
, false, false, curr
)
843 if not curr
.ldone
then
845 curr
= new RopeCharIteratorPiece(currit
._left
, false, false, curr
)
854 private class RopeBufSubstringIterator
855 super Iterator[FlatText]
857 # Iterator on the substrings of the building string
858 var iter
: Iterator[FlatText] is noautoinit
859 # Makes a String out of the buffered part of the Ropebuffer
860 var nsstr
: FlatString is noautoinit
861 # Did we attain the buffered part ?
862 var nsstr_done
= false
864 init from
(str
: RopeBuffer) do
865 iter
= str
.str
.substrings
866 nsstr
= new FlatString.with_infos
(str
.ns
, str
.rpos
- str
.dumped
, str
.dumped
)
867 if str
.length
== 0 then nsstr_done
= true
870 redef fun is_ok
do return iter
.is_ok
or not nsstr_done
874 if iter
.is_ok
then return iter
.item
887 # Substrings of a Rope (i.e. Postfix iterator on leaves)
888 private class RopeSubstrings
889 super IndexedIterator[FlatString]
892 var iter
: RopeCharIteratorPiece is noinit
894 var pos
: Int is noinit
895 # Maximum position in `Rope` (i.e. length - 1)
896 var max
: Int is noinit
899 var str
: FlatString is noinit
901 init from
(root
: Concat, pos
: Int) do
902 var r
= new RopeCharIteratorPiece(root
, true, false, null)
903 max
= root
.length
- 1
904 var rnod
: String = root
907 if rnod
isa Concat then
908 if off
>= rnod
._left
.length
then
910 off
-= rnod
._left
.length
912 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
915 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
918 str
= rnod
.as(FlatString)
927 redef fun item
do return str
929 redef fun is_ok
do return pos
<= max
931 redef fun index
do return pos
935 if pos
> max
then return
939 if not rnod
isa Concat then
942 str
= rnod
.as(FlatString)
943 iter
= it
.as(not null)
949 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
950 else if not it
.rdone
then
953 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
963 # Implementation of a `StringCharView` for `Concat` objects
964 private class RopeChars
967 redef type SELFTYPE: Concat
973 redef fun iterator_from
(i
) do return new RopeCharIterator.from
(target
, i
)
975 redef fun reverse_iterator_from
(i
) do return new RopeCharReverseIterator.from
(target
, i
)
979 # Implementation of a `StringCharView` for `Concat` objects
980 private class RopeBytes
983 redef type SELFTYPE: Concat
986 var nod
: String = target
988 if nod
isa FlatString then return nod
._items
[i
]
989 if not nod
isa Concat then abort
991 if lft
.bytelen
>= i
then
999 redef fun iterator_from
(i
) do return new RopeByteIterator.from
(target
, i
)
1001 redef fun reverse_iterator_from
(i
) do return new RopeByteReverseIterator.from
(target
, i
)
1005 # An Iterator over a RopeBuffer.
1006 class RopeBufferCharIterator
1007 super IndexedIterator[Char]
1010 var sit
: IndexedIterator[Char] is noautoinit
1012 redef fun index
do return sit
.index
1014 # Init the iterator from a RopeBuffer starting from `pos`.
1015 init from
(t
: RopeBuffer, pos
: Int) do
1017 sit
= t
.str
.chars
.iterator_from
(pos
)
1020 redef fun is_ok
do return sit
.is_ok
1027 redef fun next
do sit
.next
1030 # Reverse iterator over a RopeBuffer.
1031 class RopeBufferCharReverseIterator
1032 super IndexedIterator[Char]
1035 var sit
: IndexedIterator[Char] is noautoinit
1037 redef fun index
do return sit
.index
1039 # Init the iterator from a RopeBuffer starting from `pos`.
1040 init from
(tgt
: RopeBuffer, pos
: Int) do
1042 sit
= tgt
.str
.chars
.reverse_iterator_from
(pos
)
1045 redef fun is_ok
do return sit
.is_ok
1052 redef fun next
do sit
.next
1055 # View on the chars of a `RopeBuffer`
1056 class RopeBufferChars
1057 super BufferCharView
1059 redef type SELFTYPE: RopeBuffer
1061 redef fun [](i
) do return target
[i
]
1063 redef fun []=(i
,c
) do target
[i
] = c
1065 redef fun add
(c
) do target
.add c
1067 redef fun push
(c
) do target
.add c
1069 redef fun iterator_from
(i
) do return new RopeBufferCharIterator.from
(target
, i
)
1071 redef fun reverse_iterator_from
(i
) do return new RopeBufferCharReverseIterator.from
(target
, i
)
1074 # An Iterator over a RopeBuffer.
1075 class RopeBufferByteIterator
1076 super IndexedIterator[Byte]
1079 var sit
: IndexedIterator[Byte] is noautoinit
1081 # Native string iterated over.
1082 var ns
: NativeString is noautoinit
1084 # Current position in `ns`.
1085 var pns
: Int is noautoinit
1087 # Maximum position iterable.
1088 var maxpos
: Int is noautoinit
1090 redef var index
is noautoinit
1092 # Init the iterator from a RopeBuffer starting from `pos`.
1093 init from
(t
: RopeBuffer, pos
: Int) do
1096 sit
= t
.str
.bytes
.iterator_from
(pos
)
1097 pns
= pos
- t
.str
.length
1101 redef fun is_ok
do return index
< maxpos
1104 if sit
.is_ok
then return sit
.item
1118 # Reverse iterator over a RopeBuffer.
1119 class RopeBufferByteReverseIterator
1120 super IndexedIterator[Byte]
1123 var sit
: IndexedIterator[Byte] is noautoinit
1125 # Native string iterated over.
1126 var ns
: NativeString is noautoinit
1128 # Current position in `ns`.
1129 var pns
: Int is noautoinit
1131 redef var index
is noautoinit
1133 # Init the iterator from a RopeBuffer starting from `pos`.
1134 init from
(tgt
: RopeBuffer, pos
: Int) do
1135 sit
= tgt
.str
.bytes
.reverse_iterator_from
(pos
- (tgt
.rpos
- tgt
.dumped
))
1136 pns
= pos
- tgt
.str
.bytelen
+ tgt
.rpos
1141 redef fun is_ok
do return index
>= 0
1144 if pns
>= 0 then return ns
[pns
]
1158 # View on the chars of a `RopeBuffer`
1159 class RopeBufferBytes
1160 super BufferByteView
1162 redef type SELFTYPE: RopeBuffer
1165 if i
< target
.str
.bytelen
then
1166 return target
.str
.bytes
[i
]
1168 return target
.ns
[i
- target
.str
.bytelen
]
1172 redef fun iterator_from
(i
) do return new RopeBufferByteIterator.from
(target
, i
)
1174 redef fun reverse_iterator_from
(i
) do return new RopeBufferByteReverseIterator.from
(target
, i
)