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
525 # Flush the buffer in order to only have to reverse `str`.
526 if rpos
> 0 and dumped
!= rpos
then
527 str
+= new FlatString.with_infos
(ns
, rpos
- dumped
, dumped
, rpos
- 1)
534 if written
then reset
540 if written
then reset
546 redef class FlatString
548 redef fun insert_at
(s
, pos
) do
549 var l
= substring
(0, pos
)
550 var r
= substring_from
(pos
)
558 if slen
== 0 then return self
559 if mlen
== 0 then return s
560 var nlen
= slen
+ mlen
561 if s
isa FlatString then
562 if nlen
> maxlen
then return new Concat(self, s
)
564 var sifrom
= s
.first_byte
565 var mifrom
= first_byte
567 var ns
= new NativeString(nlen
+ 1)
568 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
569 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
570 return ns
.to_s_with_length
(nlen
)
571 else if s
isa Concat then
573 var sllen
= sl
.bytelen
574 if sllen
+ mlen
> maxlen
then return new Concat(self, s
)
575 return new Concat(self + sl
, s
.right
)
582 # A simple linked list for use with iterators
583 private class RopeCharIteratorPiece
584 # The encapsulated node of the `Rope`
586 # Was its left child (if any) visited ?
588 # Was its right child (if any) visited ?
590 # The previous node in the list.
591 var prev
: nullable RopeCharIteratorPiece
594 # A reverse iterator capable of working with `Rope` objects
595 private class RopeByteReverseIterator
596 super IndexedIterator[Byte]
598 # Current NativeString
600 # Current position in NativeString
602 # Position in the Rope (0-indexed)
604 # Iterator on the substrings, does the Postfix part of
605 # the Rope traversal.
606 var subs
: IndexedIterator[FlatString]
608 init(root
: Concat) is old_style_init
do
609 pos
= root
.bytelen
- 1
610 subs
= new ReverseRopeSubstrings(root
)
616 init from
(root
: Concat, pos
: Int) do
618 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
621 pns
= pos
- subs
.index
624 redef fun index
do return pos
626 redef fun is_ok
do return pos
>= 0
628 redef fun item
do return ns
[pns
]
633 if pns
>= 0 then return
634 if not subs
.is_ok
then return
636 if not subs
.is_ok
then return
643 # Forward iterator on the bytes of a `Rope`
644 private class RopeByteIterator
645 super IndexedIterator[Byte]
647 # Position in current `String`
649 # Current `String` being iterated on
651 # Substrings of the Rope
652 var subs
: IndexedIterator[FlatString]
653 # Maximum position to iterate on (e.g. Rope.length)
655 # Position (char) in the Rope (0-indexed)
658 init(root
: Concat) is old_style_init
do
659 subs
= new RopeSubstrings(root
)
662 max
= root
.length
- 1
666 init from
(root
: Concat, pos
: Int) do
667 subs
= new RopeSubstrings.from
(root
, pos
)
668 pns
= pos
- subs
.index
671 max
= root
.length
- 1
674 redef fun item
do return ns
[pns
]
676 redef fun is_ok
do return pos
<= max
678 redef fun index
do return pos
683 if pns
< subs
.item
.bytelen
then return
684 if not subs
.is_ok
then return
686 if not subs
.is_ok
then return
693 # A reverse iterator capable of working with `Rope` objects
694 private class RopeCharReverseIterator
695 super IndexedIterator[Char]
697 # Current NativeString
699 # Current position in NativeString
701 # Position in the Rope (0-indexed)
703 # Iterator on the substrings, does the Postfix part of
704 # the Rope traversal.
705 var subs
: IndexedIterator[String]
707 init(root
: Concat) is old_style_init
do
708 pos
= root
.length
- 1
709 subs
= new ReverseRopeSubstrings(root
)
714 init from
(root
: Concat, pos
: Int) do
716 subs
= new ReverseRopeSubstrings.from
(root
, pos
)
718 pns
= pos
- subs
.index
721 redef fun index
do return pos
723 redef fun is_ok
do return pos
>= 0
725 redef fun item
do return ns
[pns
]
730 if pns
>= 0 then return
731 if not subs
.is_ok
then return
733 if not subs
.is_ok
then return
739 # Forward iterator on the chars of a `Rope`
740 private class RopeCharIterator
741 super IndexedIterator[Char]
743 # Position in current `String`
745 # Current `String` being iterated on
747 # Substrings of the Rope
748 var subs
: IndexedIterator[String]
749 # Maximum position to iterate on (e.g. Rope.length)
751 # Position (char) in the Rope (0-indexed)
754 init(root
: Concat) is old_style_init
do
755 subs
= new RopeSubstrings(root
)
758 max
= root
.length
- 1
762 init from
(root
: Concat, pos
: Int) do
763 subs
= new RopeSubstrings.from
(root
, pos
)
764 pns
= pos
- subs
.index
767 max
= root
.length
- 1
770 redef fun item
do return str
[pns
]
772 redef fun is_ok
do return pos
<= max
774 redef fun index
do return pos
779 if pns
< subs
.item
.length
then return
780 if not subs
.is_ok
then return
782 if not subs
.is_ok
then return
788 # Substrings of a Rope (i.e. Reverse postfix iterator on leaves)
789 private class ReverseRopeSubstrings
790 super IndexedIterator[FlatString]
793 var iter
: RopeCharIteratorPiece is noinit
795 var pos
: Int is noinit
798 var str
: FlatString is noinit
800 init(root
: Concat) is old_style_init
do
801 var r
= new RopeCharIteratorPiece(root
, false, true, null)
802 pos
= root
.length
- 1
803 var lnod
: String = root
805 if lnod
isa Concat then
807 r
= new RopeCharIteratorPiece(lnod
, false, true, r
)
809 str
= lnod
.as(FlatString)
816 init from
(root
: Concat, pos
: Int) do
817 var r
= new RopeCharIteratorPiece(root
, false, true, null)
818 var rnod
: String = root
821 if rnod
isa Concat then
822 if off
>= rnod
.left
.length
then
823 off
-= rnod
.left
.length
825 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
829 r
= new RopeCharIteratorPiece(rnod
, false, true, r
)
832 str
= rnod
.as(FlatString)
841 redef fun item
do return str
843 redef fun index
do return pos
845 redef fun is_ok
do return pos
>= 0
848 if pos
< 0 then return
850 var currit
= curr
.node
851 while curr
!= null do
853 if not currit
isa Concat then
854 str
= currit
.as(FlatString)
859 if not curr
.rdone
then
861 curr
= new RopeCharIteratorPiece(currit
.right
, false, false, curr
)
864 if not curr
.ldone
then
866 curr
= new RopeCharIteratorPiece(currit
.left
, false, false, curr
)
875 private class RopeBufSubstringIterator
876 super Iterator[FlatText]
878 # Iterator on the substrings of the building string
879 var iter
: Iterator[FlatText]
880 # Makes a String out of the buffered part of the Ropebuffer
881 var nsstr
: FlatString
882 # Did we attain the buffered part ?
883 var nsstr_done
= false
885 init(str
: RopeBuffer) is old_style_init
do
886 iter
= str
.str
.substrings
887 nsstr
= new FlatString.with_infos
(str
.ns
, str
.rpos
- str
.dumped
, str
.dumped
, str
.rpos
- 1)
888 if str
.length
== 0 then nsstr_done
= true
891 redef fun is_ok
do return iter
.is_ok
or not nsstr_done
895 if iter
.is_ok
then return iter
.item
908 # Substrings of a Rope (i.e. Postfix iterator on leaves)
909 private class RopeSubstrings
910 super IndexedIterator[FlatString]
913 var iter
: RopeCharIteratorPiece is noinit
915 var pos
: Int is noinit
916 # Maximum position in `Rope` (i.e. length - 1)
917 var max
: Int is noinit
920 var str
: FlatString is noinit
922 init(root
: Concat) is old_style_init
do
923 var r
= new RopeCharIteratorPiece(root
, true, false, null)
925 max
= root
.length
- 1
926 var rnod
: String = root
928 if rnod
isa Concat then
930 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
932 str
= rnod
.as(FlatString)
940 init from
(root
: Concat, pos
: Int) do
941 var r
= new RopeCharIteratorPiece(root
, true, false, null)
942 max
= root
.length
- 1
943 var rnod
: String = root
946 if rnod
isa Concat then
947 if off
>= rnod
.left
.length
then
949 off
-= rnod
.left
.length
951 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
954 r
= new RopeCharIteratorPiece(rnod
, true, false, r
)
957 str
= rnod
.as(FlatString)
966 redef fun item
do return str
968 redef fun is_ok
do return pos
<= max
970 redef fun index
do return pos
974 if pos
> max
then return
978 if not rnod
isa Concat then
981 str
= rnod
.as(FlatString)
982 iter
= it
.as(not null)
988 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
989 else if not it
.rdone
then
992 it
= new RopeCharIteratorPiece(rnod
, false, false, it
)
1002 # Implementation of a `StringCharView` for `Concat` objects
1003 private class RopeChars
1004 super StringCharView
1006 redef type SELFTYPE: Concat
1012 redef fun iterator_from
(i
) do return new RopeCharIterator.from
(target
, i
)
1014 redef fun reverse_iterator_from
(i
) do return new RopeCharReverseIterator.from
(target
, i
)
1018 # Implementation of a `StringCharView` for `Concat` objects
1019 private class RopeBytes
1020 super StringByteView
1022 redef type SELFTYPE: Concat
1025 var nod
: String = target
1027 if nod
isa FlatString then return nod
.items
[i
]
1028 if not nod
isa Concat then abort
1029 if nod
.left
.bytelen
>= i
then
1037 redef fun iterator_from
(i
) do return new RopeByteIterator.from
(target
, i
)
1039 redef fun reverse_iterator_from
(i
) do return new RopeByteReverseIterator.from
(target
, i
)
1043 # An Iterator over a RopeBuffer.
1044 class RopeBufferCharIterator
1045 super IndexedIterator[Char]
1048 var sit
: IndexedIterator[Char]
1050 redef fun index
do return sit
.index
1052 # Init the iterator from a RopeBuffer.
1053 init(t
: RopeBuffer) is old_style_init
do
1055 sit
= t
.str
.chars
.iterator
1058 # Init the iterator from a RopeBuffer starting from `pos`.
1059 init from
(t
: RopeBuffer, pos
: Int) do
1061 sit
= t
.str
.chars
.iterator_from
(pos
)
1064 redef fun is_ok
do return sit
.is_ok
1071 redef fun next
do sit
.next
1074 # Reverse iterator over a RopeBuffer.
1075 class RopeBufferCharReverseIterator
1076 super IndexedIterator[Char]
1079 var sit
: IndexedIterator[Char]
1081 redef fun index
do return sit
.index
1083 # Init the iterator from a RopeBuffer.
1084 init(tgt
: RopeBuffer) is old_style_init
do
1086 sit
= tgt
.str
.chars
.reverse_iterator
1089 # Init the iterator from a RopeBuffer starting from `pos`.
1090 init from
(tgt
: RopeBuffer, pos
: Int) do
1092 sit
= tgt
.str
.chars
.reverse_iterator_from
(pos
)
1095 redef fun is_ok
do return sit
.is_ok
1102 redef fun next
do sit
.next
1105 # View on the chars of a `RopeBuffer`
1106 class RopeBufferChars
1107 super BufferCharView
1109 redef type SELFTYPE: RopeBuffer
1111 redef fun [](i
) do return target
[i
]
1113 redef fun []=(i
,c
) do target
[i
] = c
1115 redef fun add
(c
) do target
.add c
1117 redef fun push
(c
) do target
.add c
1119 redef fun iterator_from
(i
) do return new RopeBufferCharIterator.from
(target
, i
)
1121 redef fun reverse_iterator_from
(i
) do return new RopeBufferCharReverseIterator.from
(target
, i
)
1124 # An Iterator over a RopeBuffer.
1125 class RopeBufferByteIterator
1126 super IndexedIterator[Byte]
1129 var sit
: IndexedIterator[Byte]
1131 # Native string iterated over.
1132 var ns
: NativeString
1134 # Current position in `ns`.
1137 # Maximum position iterable.
1142 # Init the iterator from a RopeBuffer.
1143 init(t
: RopeBuffer) is old_style_init
do
1146 sit
= t
.str
.bytes
.iterator
1151 # Init the iterator from a RopeBuffer starting from `pos`.
1152 init from
(t
: RopeBuffer, pos
: Int) do
1155 sit
= t
.str
.bytes
.iterator_from
(pos
)
1156 pns
= pos
- t
.str
.length
1160 redef fun is_ok
do return index
< maxpos
1163 if sit
.is_ok
then return sit
.item
1177 # Reverse iterator over a RopeBuffer.
1178 class RopeBufferByteReverseIterator
1179 super IndexedIterator[Byte]
1182 var sit
: IndexedIterator[Byte]
1184 # Native string iterated over.
1185 var ns
: NativeString
1187 # Current position in `ns`.
1192 # Init the iterator from a RopeBuffer.
1193 init(tgt
: RopeBuffer) is old_style_init
do
1194 sit
= tgt
.str
.bytes
.reverse_iterator
1196 index
= tgt
.bytelen
- 1
1200 # Init the iterator from a RopeBuffer starting from `pos`.
1201 init from
(tgt
: RopeBuffer, pos
: Int) do
1202 sit
= tgt
.str
.bytes
.reverse_iterator_from
(pos
- (tgt
.rpos
- tgt
.dumped
))
1203 pns
= pos
- tgt
.str
.bytelen
+ tgt
.rpos
1208 redef fun is_ok
do return index
>= 0
1211 if pns
>= 0 then return ns
[pns
]
1225 # View on the chars of a `RopeBuffer`
1226 class RopeBufferBytes
1227 super BufferByteView
1229 redef type SELFTYPE: RopeBuffer
1232 if i
< target
.str
.bytelen
then
1233 return target
.str
.bytes
[i
]
1235 return target
.ns
[i
- target
.str
.bytelen
]
1239 redef fun []=(i
,c
) do
1240 if i
== target
.length
then target
.add_byte c
1241 if i
< target
.str
.length
then
1242 # FIXME: Will need to be optimized and rewritten with Unicode
1244 var l
= s
.substring
(0, i
)
1245 var r
= s
.substring_from
(i
+ 1)
1246 target
.str
= l
+ c
.to_i
.ascii
.to_s
+ r
1248 target
.ns
[i
- target
.str
.length
] = c
1252 redef fun add
(c
) do target
.add_byte c
1254 redef fun push
(c
) do target
.add_byte c
1256 redef fun iterator_from
(i
) do return new RopeBufferByteIterator.from
(target
, i
)
1258 redef fun reverse_iterator_from
(i
) do return new RopeBufferByteReverseIterator.from
(target
, i
)