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
: Sequence[Byte] 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 # Keeps track of the buffer's currently dumped part
286 # This might happen if for instance, a String was being
287 # built by concatenating small parts of string and suddenly
288 # a long string (length > maxlen) is appended.
289 private var dumped
: Int is noinit
291 # Length of the complete rope in chars (0)
302 # Length of the complete rope in bytes
303 redef var bytelen
= 0
305 # Length of the mutable part (in bytes)
307 # Is also used as base to compute the size of the next
308 # mutable native string (`ns`)
309 private var buf_size
: Int is noinit
311 redef fun substrings
do return new RopeBufSubstringIterator(self)
313 # Builds an empty `RopeBuffer`
315 ns
= new NativeString(maxlen
)
320 # Builds a new `RopeBuffer` with `str` in it.
321 init from
(str
: String) do
323 ns
= new NativeString(maxlen
)
329 # Resets the informations of the `Buffer`
331 # This is called when doing in-place modifications
332 # on a previously to_s'd `RopeBuffer`
334 var nns
= new NativeString(buf_size
)
335 var blen
= rpos
- dumped
336 ns
.copy_to
(nns
, blen
, dumped
, 0)
344 if i
< str
.length
then
347 var index
= ns
.char_to_byte_index_cached
(i
- str
.length
, 0, dumped
)
348 return ns
.char_at
(index
)
352 redef fun []=(i
, c
) do
353 assert i
>= 0 and i
<= length
354 if i
== length
then add c
355 if i
< str
.length
then
356 bytelen
+= c
.u8char_len
- str
[i
].u8char_len
358 var l
= s
.substring
(0, i
)
359 var r
= s
.substring_from
(i
+ 1)
362 var reali
= i
- str
.length
363 var index
= ns
.char_to_byte_index_cached
(reali
, 0, dumped
)
364 var st_nxt
= ns
.char_to_byte_index_cached
(reali
+ 1, reali
, index
)
365 var loc_c
= ns
.char_at
(index
)
366 if loc_c
.u8char_len
!= c
.u8char_len
then
367 var delta
= c
.u8char_len
- loc_c
.u8char_len
368 var remsp
= buf_size
- rpos
369 if remsp
< delta
then
371 var nns
= new NativeString(buf_size
)
372 ns
.copy_to
(nns
, index
- dumped
, dumped
, 0)
373 ns
.copy_to
(nns
, rpos
- index
- loc_c
.u8char_len
, index
+ loc_c
.u8char_len
, index
- dumped
+ delta
)
375 index
= index
- dumped
377 ns
.copy_to
(ns
, rpos
- st_nxt
, st_nxt
, st_nxt
+ delta
)
382 ns
.set_char_at
(index
, c
)
386 redef fun empty
do return new RopeBuffer
394 ns
= new NativeString(buf_size
)
399 redef fun substring
(from
, count
) do
400 var strlen
= str
.length
404 if count
< 0 then count
= 0
408 if count
> length
then count
= length
- from
410 if count
== 0 then return empty
412 if from
< strlen
then
413 var subpos
= strlen
- from
414 if count
<= subpos
then
415 return new RopeBuffer.from
(str
.substring
(from
, count
))
417 var l
= str
.substring_from
(from
)
418 var rem
= count
- subpos
419 var nns
= new NativeString(rem
)
420 ns
.copy_to
(nns
, rem
, dumped
, 0)
421 return new RopeBuffer.from
(l
+ nns
.to_s_with_length
(rem
))
424 var nns
= new NativeString(count
)
425 ns
.copy_to
(nns
, count
, dumped
, 0)
426 return new RopeBuffer.from
(nns
.to_s_with_length
(count
))
430 redef fun append
(s
) do
432 if slen
>= maxlen
then
437 if s
isa FlatText then
439 var from
= if s
isa FlatString then s
.first_byte
else 0
440 var remsp
= buf_size
- rpos
441 if slen
<= remsp
then
442 oits
.copy_to
(ns
, slen
, from
, rpos
)
446 var brk
= oits
.find_beginning_of_char_at
(from
+ remsp
)
447 oits
.copy_to
(ns
, brk
, from
, rpos
)
450 oits
.copy_to
(ns
, slen
- remsp
, brk
, 0)
453 for i
in s
.substrings
do append i
459 if rp
>= buf_size
then
463 # TODO: Fix when supporting UTF-8
464 ns
[rp
] = c
.ascii
.to_b
470 private fun add_byte
(b
: Byte) do
472 if rp
>= buf_size
then
482 # Converts the Buffer to a FlatString, appends it to
483 # the final String and re-allocates a new larger Buffer.
484 private fun dump_buffer
do
486 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
490 ns
= new NativeString(bs
)
496 # Similar to dump_buffer, but does not reallocate a new NativeString
497 private fun persist_buffer
do
498 if rpos
== dumped
then return
499 var nstr
= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
506 new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1).output
509 # Enlarge is useless here since the `Buffer`
510 # part is automatically dumped when necessary.
512 # Also, since the buffer can not be overused by a
513 # single string, there is no need for manual
516 # "You have no power here !"
517 redef fun enlarge
(i
) do end
526 # Flush the buffer in order to only have to reverse `str`.
527 if rpos
> 0 and dumped
!= rpos
then
528 str
+= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
535 if written
then reset
541 if written
then reset
547 redef class FlatString
549 redef fun insert_at
(s
, pos
) do
550 var l
= substring
(0, pos
)
551 var r
= substring_from
(pos
)
559 if slen
== 0 then return self
560 if mlen
== 0 then return s
561 var nlen
= slen
+ mlen
562 if s
isa FlatString then
563 if nlen
> maxlen
then return new Concat(self, s
)
565 var sifrom
= s
.first_byte
566 var mifrom
= first_byte
568 var ns
= new NativeString(nlen
+ 1)
569 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
570 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
571 return ns
.to_s_with_length
(nlen
)
572 else if s
isa Concat then
574 var sllen
= sl
.bytelen
575 if sllen
+ mlen
> maxlen
then return new Concat(self, s
)
576 return new Concat(self + sl
, s
.right
)
583 # A simple linked list for use with iterators
584 private class RopeCharIteratorPiece
585 # The encapsulated node of the `Rope`
587 # Was its left child (if any) visited ?
589 # Was its right child (if any) visited ?
591 # The previous node in the list.
592 var prev
: nullable RopeCharIteratorPiece
595 # A reverse iterator capable of working with `Rope` objects
596 private class RopeByteReverseIterator
597 super IndexedIterator[Byte]
599 # Current NativeString
601 # Current position in NativeString
603 # Position in the Rope (0-indexed)
605 # Iterator on the substrings, does the Postfix part of
606 # the Rope traversal.
607 var subs
: IndexedIterator[FlatString]
609 init(root
: Concat) is old_style_init
do
610 pos
= root
.bytelen
- 1
611 subs
= new ReverseRopeSubstrings(root
)
617 init from
(root
: Concat, pos
: Int) do
619 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
622 pns
= pos
- subs
.index
625 redef fun index
do return pos
627 redef fun is_ok
do return pos
>= 0
629 redef fun item
do return ns
[pns
]
634 if pns
>= 0 then return
635 if not subs
.is_ok
then return
637 if not subs
.is_ok
then return
644 # Forward iterator on the bytes of a `Rope`
645 private class RopeByteIterator
646 super IndexedIterator[Byte]
648 # Position in current `String`
650 # Current `String` being iterated on
652 # Substrings of the Rope
653 var subs
: IndexedIterator[FlatString]
654 # Maximum position to iterate on (e.g. Rope.length)
656 # Position (char) in the Rope (0-indexed)
659 init(root
: Concat) is old_style_init
do
660 subs
= new RopeSubstrings(root
)
663 max
= root
.length
- 1
667 init from
(root
: Concat, pos
: Int) do
668 subs
= new RopeSubstrings.from
(root
, pos
)
669 pns
= pos
- subs
.index
672 max
= root
.length
- 1
675 redef fun item
do return ns
[pns
]
677 redef fun is_ok
do return pos
<= max
679 redef fun index
do return pos
684 if pns
< subs
.item
.bytelen
then return
685 if not subs
.is_ok
then return
687 if not subs
.is_ok
then return
694 # A reverse iterator capable of working with `Rope` objects
695 private class RopeCharReverseIterator
696 super IndexedIterator[Char]
698 # Current NativeString
700 # Current position in NativeString
702 # Position in the Rope (0-indexed)
704 # Iterator on the substrings, does the Postfix part of
705 # the Rope traversal.
706 var subs
: IndexedIterator[String]
708 init(root
: Concat) is old_style_init
do
709 pos
= root
.length
- 1
710 subs
= new ReverseRopeSubstrings(root
)
715 init from
(root
: Concat, pos
: Int) do
717 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
719 pns
= pos
- subs
.index
722 redef fun index
do return pos
724 redef fun is_ok
do return pos
>= 0
726 redef fun item
do return ns
[pns
]
731 if pns
>= 0 then return
732 if not subs
.is_ok
then return
734 if not subs
.is_ok
then return
740 # Forward iterator on the chars of a `Rope`
741 private class RopeCharIterator
742 super IndexedIterator[Char]
744 # Position in current `String`
746 # Current `String` being iterated on
748 # Substrings of the Rope
749 var subs
: IndexedIterator[String]
750 # Maximum position to iterate on (e.g. Rope.length)
752 # Position (char) in the Rope (0-indexed)
755 init(root
: Concat) is old_style_init
do
756 subs
= new RopeSubstrings(root
)
759 max
= root
.length
- 1
763 init from
(root
: Concat, pos
: Int) do
764 subs
= new RopeSubstrings.from
(root
, pos
)
765 pns
= pos
- subs
.index
768 max
= root
.length
- 1
771 redef fun item
do return str
[pns
]
773 redef fun is_ok
do return pos
<= max
775 redef fun index
do return pos
780 if pns
< subs
.item
.length
then return
781 if not subs
.is_ok
then return
783 if not subs
.is_ok
then return
789 # Substrings of a Rope (i.e. Reverse postfix iterator on leaves)
790 private class ReverseRopeSubstrings
791 super IndexedIterator[FlatString]
794 var iter
: RopeCharIteratorPiece is noinit
796 var pos
: Int is noinit
799 var str
: FlatString is noinit
801 init(root
: Concat) is old_style_init
do
802 var r
= new RopeCharIteratorPiece(root
, false, true, null)
803 pos
= root
.length
- 1
804 var lnod
: String = root
806 if lnod
isa Concat then
808 r
= new RopeCharIteratorPiece(lnod
, false, true, r
)
810 str
= lnod
.as(FlatString)
817 init from
(root
: Concat, pos
: Int) do
818 var r
= new RopeCharIteratorPiece(root
, false, true, null)
819 var rnod
: String = root
822 if rnod
isa Concat then
823 if off
>= rnod
.left
.length
then
824 off
-= rnod
.left
.length
826 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
830 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
833 str
= rnod
.as(FlatString)
842 redef fun item
do return str
844 redef fun index
do return pos
846 redef fun is_ok
do return pos
>= 0
849 if pos
< 0 then return
851 var currit
= curr
.node
852 while curr
!= null do
854 if not currit
isa Concat then
855 str
= currit
.as(FlatString)
860 if not curr
.rdone
then
862 curr
= new RopeCharIteratorPiece(currit
.right
, false, false, curr
)
865 if not curr
.ldone
then
867 curr
= new RopeCharIteratorPiece(currit
.left
, false, false, curr
)
876 private class RopeBufSubstringIterator
877 super Iterator[FlatText]
879 # Iterator on the substrings of the building string
880 var iter
: Iterator[FlatText]
881 # Makes a String out of the buffered part of the Ropebuffer
882 var nsstr
: FlatString
883 # Did we attain the buffered part ?
884 var nsstr_done
= false
886 init(str
: RopeBuffer) is old_style_init
do
887 iter
= str
.str
.substrings
888 nsstr
= new FlatString.with_infos
(str
.ns
, str
.rpos
- str
.dumped
, str
.dumped
, str
.rpos
- 1)
889 if str
.length
== 0 then nsstr_done
= true
892 redef fun is_ok
do return iter
.is_ok
or not nsstr_done
896 if iter
.is_ok
then return iter
.item
909 # Substrings of a Rope (i.e. Postfix iterator on leaves)
910 private class RopeSubstrings
911 super IndexedIterator[FlatString]
914 var iter
: RopeCharIteratorPiece is noinit
916 var pos
: Int is noinit
917 # Maximum position in `Rope` (i.e. length - 1)
918 var max
: Int is noinit
921 var str
: FlatString is noinit
923 init(root
: Concat) is old_style_init
do
924 var r
= new RopeCharIteratorPiece(root
, true, false, null)
926 max
= root
.length
- 1
927 var rnod
: String = root
929 if rnod
isa Concat then
931 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
933 str
= rnod
.as(FlatString)
941 init from
(root
: Concat, pos
: Int) do
942 var r
= new RopeCharIteratorPiece(root
, true, false, null)
943 max
= root
.length
- 1
944 var rnod
: String = root
947 if rnod
isa Concat then
948 if off
>= rnod
.left
.length
then
950 off
-= rnod
.left
.length
952 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
955 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
958 str
= rnod
.as(FlatString)
967 redef fun item
do return str
969 redef fun is_ok
do return pos
<= max
971 redef fun index
do return pos
975 if pos
> max
then return
979 if not rnod
isa Concat then
982 str
= rnod
.as(FlatString)
983 iter
= it
.as(not null)
989 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
990 else if not it
.rdone
then
993 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
1003 # Implementation of a `StringCharView` for `Concat` objects
1004 private class RopeChars
1005 super StringCharView
1007 redef type SELFTYPE: Concat
1013 redef fun iterator_from
(i
) do return new RopeCharIterator.from
(target
, i
)
1015 redef fun reverse_iterator_from
(i
) do return new RopeCharReverseIterator.from
(target
, i
)
1019 # Implementation of a `StringCharView` for `Concat` objects
1020 private class RopeBytes
1021 super StringByteView
1023 redef type SELFTYPE: Concat
1026 var nod
: String = target
1028 if nod
isa FlatString then return nod
.items
[i
]
1029 if not nod
isa Concat then abort
1030 if nod
.left
.bytelen
>= i
then
1038 redef fun iterator_from
(i
) do return new RopeByteIterator.from
(target
, i
)
1040 redef fun reverse_iterator_from
(i
) do return new RopeByteReverseIterator.from
(target
, i
)
1044 # An Iterator over a RopeBuffer.
1045 class RopeBufferCharIterator
1046 super IndexedIterator[Char]
1049 var sit
: IndexedIterator[Char]
1051 redef fun index
do return sit
.index
1053 # Init the iterator from a RopeBuffer.
1054 init(t
: RopeBuffer) is old_style_init
do
1056 sit
= t
.str
.chars
.iterator
1059 # Init the iterator from a RopeBuffer starting from `pos`.
1060 init from
(t
: RopeBuffer, pos
: Int) do
1062 sit
= t
.str
.chars
.iterator_from
(pos
)
1065 redef fun is_ok
do return sit
.is_ok
1072 redef fun next
do sit
.next
1075 # Reverse iterator over a RopeBuffer.
1076 class RopeBufferCharReverseIterator
1077 super IndexedIterator[Char]
1080 var sit
: IndexedIterator[Char]
1082 redef fun index
do return sit
.index
1084 # Init the iterator from a RopeBuffer.
1085 init(tgt
: RopeBuffer) is old_style_init
do
1087 sit
= tgt
.str
.chars
.reverse_iterator
1090 # Init the iterator from a RopeBuffer starting from `pos`.
1091 init from
(tgt
: RopeBuffer, pos
: Int) do
1093 sit
= tgt
.str
.chars
.reverse_iterator_from
(pos
)
1096 redef fun is_ok
do return sit
.is_ok
1103 redef fun next
do sit
.next
1106 # View on the chars of a `RopeBuffer`
1107 class RopeBufferChars
1108 super BufferCharView
1110 redef type SELFTYPE: RopeBuffer
1112 redef fun [](i
) do return target
[i
]
1114 redef fun []=(i
,c
) do target
[i
] = c
1116 redef fun add
(c
) do target
.add c
1118 redef fun push
(c
) do target
.add c
1120 redef fun iterator_from
(i
) do return new RopeBufferCharIterator.from
(target
, i
)
1122 redef fun reverse_iterator_from
(i
) do return new RopeBufferCharReverseIterator.from
(target
, i
)
1125 # An Iterator over a RopeBuffer.
1126 class RopeBufferByteIterator
1127 super IndexedIterator[Byte]
1130 var sit
: IndexedIterator[Byte]
1132 # Native string iterated over.
1133 var ns
: NativeString
1135 # Current position in `ns`.
1138 # Maximum position iterable.
1143 # Init the iterator from a RopeBuffer.
1144 init(t
: RopeBuffer) is old_style_init
do
1147 sit
= t
.str
.bytes
.iterator
1152 # Init the iterator from a RopeBuffer starting from `pos`.
1153 init from
(t
: RopeBuffer, pos
: Int) do
1156 sit
= t
.str
.bytes
.iterator_from
(pos
)
1157 pns
= pos
- t
.str
.length
1161 redef fun is_ok
do return index
< maxpos
1164 if sit
.is_ok
then return sit
.item
1178 # Reverse iterator over a RopeBuffer.
1179 class RopeBufferByteReverseIterator
1180 super IndexedIterator[Byte]
1183 var sit
: IndexedIterator[Byte]
1185 # Native string iterated over.
1186 var ns
: NativeString
1188 # Current position in `ns`.
1193 # Init the iterator from a RopeBuffer.
1194 init(tgt
: RopeBuffer) is old_style_init
do
1195 sit
= tgt
.str
.bytes
.reverse_iterator
1197 index
= tgt
.bytelen
- 1
1201 # Init the iterator from a RopeBuffer starting from `pos`.
1202 init from
(tgt
: RopeBuffer, pos
: Int) do
1203 sit
= tgt
.str
.bytes
.reverse_iterator_from
(pos
- (tgt
.rpos
- tgt
.dumped
))
1204 pns
= pos
- tgt
.str
.bytelen
+ tgt
.rpos
1209 redef fun is_ok
do return index
>= 0
1212 if pns
>= 0 then return ns
[pns
]
1226 # View on the chars of a `RopeBuffer`
1227 class RopeBufferBytes
1228 super BufferByteView
1230 redef type SELFTYPE: RopeBuffer
1233 if i
< target
.str
.bytelen
then
1234 return target
.str
.bytes
[i
]
1236 return target
.ns
[i
- target
.str
.bytelen
]
1240 redef fun []=(i
,c
) do
1241 if i
== target
.length
then target
.add_byte c
1242 if i
< target
.str
.length
then
1243 # FIXME: Will need to be optimized and rewritten with Unicode
1245 var l
= s
.substring
(0, i
)
1246 var r
= s
.substring_from
(i
+ 1)
1247 target
.str
= l
+ c
.to_i
.ascii
.to_s
+ r
1249 target
.ns
[i
- target
.str
.length
] = c
1253 redef fun add
(c
) do target
.add_byte c
1255 redef fun push
(c
) do target
.add_byte c
1257 redef fun iterator_from
(i
) do return new RopeBufferByteIterator.from
(target
, i
)
1259 redef fun reverse_iterator_from
(i
) do return new RopeBufferByteReverseIterator.from
(target
, i
)