1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # This file is free software, which comes along with NIT. This software is
4 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
5 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
6 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
7 # is kept unaltered, and a notification of the changes is added.
8 # You are allowed to redistribute it and sell it, alone or is a part of
11 # All the array-based text representations
14 intrude import abstract_text
22 private class FlatSubstringsIter
23 super Iterator[FlatText]
25 var tgt
: nullable FlatText
29 return tgt
.as(not null)
32 redef fun is_ok
do return tgt
!= null
34 redef fun next
do tgt
= null
39 # First byte of the NativeString
40 protected fun first_byte
: Int do return 0
42 # Last byte of the NativeString
43 protected fun last_byte
: Int do return first_byte
+ _bytelen
- 1
45 # Cache of the latest position (char) explored in the string
48 # Cached position (bytes) in the NativeString underlying the String
51 # Index of the character `index` in `_items`
52 fun char_to_byte_index
(index
: Int): Int do
53 var dpos
= index
- _position
56 if dpos
== 0 then return b
58 b
+= _items
.length_of_char_at
(b
)
64 b
= _items
.find_beginning_of_char_at
(b
- 1)
72 # Find best insertion point
73 var delta_begin
= index
74 var delta_end
= (ln
- 1) - index
75 var delta_cache
= (pos
- index
).abs
79 if delta_cache
< min
then min
= delta_cache
80 if delta_end
< min
then min
= delta_end
85 if min
== delta_cache
then
88 else if min
== delta_begin
then
92 ns_i
= its
.find_beginning_of_char_at
(last_byte
)
96 ns_i
= its
.char_to_byte_index_cached
(index
, my_i
, ns_i
)
104 # By escaping `self` to HTML, how many more bytes will be needed ?
105 fun chars_to_html_escape
: Int do
114 else if c
== 0x3Eu
8 then
116 else if c
== 0x26u
8 then
118 else if c
== 0x22u
8 then
120 else if c
== 0x27u
8 then
122 else if c
== 0x2Fu
8 then
130 redef fun html_escape
132 var extra
= chars_to_html_escape
133 if extra
== 0 then return to_s
137 var nlen
= extra
+ _bytelen
138 var nits
= new NativeString(nlen
)
143 # Some HTML characters are used as meta-data, they need
144 # to be replaced by an HTML-Escaped equivalent
148 # * 0x26 (&) => &
149 # * 0x22 (") => "
150 # * 0x27 (') => '
151 # * 0x2F (/) => /
153 nits
[outpos
] = 0x26u
8
154 nits
[outpos
+ 1] = 0x6Cu
8
155 nits
[outpos
+ 2] = 0x74u
8
156 nits
[outpos
+ 3] = 0x3Bu
8
158 else if c
== 0x3Eu
8 then
159 nits
[outpos
] = 0x26u
8
160 nits
[outpos
+ 1] = 0x67u
8
161 nits
[outpos
+ 2] = 0x74u
8
162 nits
[outpos
+ 3] = 0x3Bu
8
164 else if c
== 0x26u
8 then
165 nits
[outpos
] = 0x26u
8
166 nits
[outpos
+ 1] = 0x61u
8
167 nits
[outpos
+ 2] = 0x6Du
8
168 nits
[outpos
+ 3] = 0x70u
8
169 nits
[outpos
+ 4] = 0x3Bu
8
171 else if c
== 0x22u
8 then
172 nits
[outpos
] = 0x26u
8
173 nits
[outpos
+ 1] = 0x23u
8
174 nits
[outpos
+ 2] = 0x33u
8
175 nits
[outpos
+ 3] = 0x34u
8
176 nits
[outpos
+ 4] = 0x3Bu
8
178 else if c
== 0x27u
8 then
179 nits
[outpos
] = 0x26u
8
180 nits
[outpos
+ 1] = 0x23u
8
181 nits
[outpos
+ 2] = 0x33u
8
182 nits
[outpos
+ 3] = 0x39u
8
183 nits
[outpos
+ 4] = 0x3Bu
8
185 else if c
== 0x2Fu
8 then
186 nits
[outpos
] = 0x26u
8
187 nits
[outpos
+ 1] = 0x23u
8
188 nits
[outpos
+ 2] = 0x34u
8
189 nits
[outpos
+ 3] = 0x37u
8
190 nits
[outpos
+ 4] = 0x3Bu
8
198 var s
= new FlatString.with_infos
(nits
, nlen
, 0)
202 # By escaping `self` to C, how many more bytes will be needed ?
204 # This enables a double-optimization in `escape_to_c` since if this
205 # method returns 0, then `self` does not need escaping and can be
207 fun chars_to_escape_to_c
: Int do
216 else if c
== 0x09u
8 then
218 else if c
== 0x22u
8 then
220 else if c
== 0x27u
8 then
222 else if c
== 0x5Cu
8 then
224 else if c
< 32u8
then
232 redef fun escape_to_c
do
233 var ln_extra
= chars_to_escape_to_c
234 if ln_extra
== 0 then return self.to_s
237 var nlen
= _bytelen
+ ln_extra
238 var nns
= new NativeString(nlen
)
245 # Any byte with value < 32 is a control character
246 # All their uses will be replaced by their octal
249 # There are two exceptions however:
254 # Aside from the code points above, the following are:
261 nns
[opos
+ 1] = 0x74u
8
263 else if c
== 0x0Au
8 then
265 nns
[opos
+ 1] = 0x6Eu
8
267 else if c
== 0x22u
8 then
269 nns
[opos
+ 1] = 0x22u
8
271 else if c
== 0x27u
8 then
273 nns
[opos
+ 1] = 0x27u
8
275 else if c
== 0x5Cu
8 then
277 nns
[opos
+ 1] = 0x5Cu
8
279 else if c
< 32u8
then
281 nns
[opos
+ 1] = 0x30u
8
282 nns
[opos
+ 2] = ((c
& 0x38u
8) >> 3) + 0x30u
8
283 nns
[opos
+ 3] = (c
& 0x07u
8) + 0x30u
8
291 return nns
.to_s_unsafe
(nlen
)
294 redef fun [](index
) do
295 assert index
>= 0 and index
< _length
296 return fetch_char_at
(index
)
299 # Gets a `Char` at `index` in `self`
301 # WARNING: Use at your own risks as no bound-checking is done
302 fun fetch_char_at
(index
: Int): Char do
303 var i
= char_to_byte_index
(index
)
306 if b
& 0x80u
8 == 0x00u
8 then return b
.ascii
307 return items
.char_at
(i
)
310 # If `self` contains only digits and alpha <= 'f', return the corresponding integer.
312 # assert "ff".to_hex == 255
313 redef fun to_hex
(pos
, ln
) do
315 if pos
== null then pos
= 0
316 if ln
== null then ln
= length
- pos
317 pos
= char_to_byte_index
(pos
)
320 for i
in [pos
.. max
[ do
322 res
+= its
[i
].ascii
.from_hex
328 # Immutable strings of characters.
333 # Index at which `self` begins in `_items`, inclusively
334 redef var first_byte
is noinit
336 redef var chars
= new FlatStringCharView(self) is lazy
338 redef var bytes
= new FlatStringByteView(self) is lazy
340 redef var to_cstring
is lazy
do
342 var new_items
= new NativeString(blen
+ 1)
343 _items
.copy_to
(new_items
, blen
, _first_byte
, 0)
344 new_items
[blen
] = 0u8
348 redef fun reversed
do
349 var b
= new FlatBuffer.with_capacity
(_bytelen
+ 1)
352 b
.add
self.fetch_char_at
(i
)
355 var s
= b
.to_s
.as(FlatString)
356 s
._length
= self._length
360 redef fun fast_cstring
do return _items
.fast_cstring
(_first_byte
)
362 redef fun substring_from
(from
) do
363 if from
>= self._length
then return empty
364 if from
<= 0 then return self
365 var c
= char_to_byte_index
(from
)
366 var st
= c
- _first_byte
367 var fln
= bytelen
- st
368 return new FlatString.full
(items
, fln
, c
, _length
- from
)
371 redef fun substring
(from
, count
)
377 if count
< 0 then return ""
382 if (count
+ from
) > ln
then count
= ln
- from
383 if count
<= 0 then return ""
384 var end_index
= from
+ count
- 1
385 return substring_impl
(from
, count
, end_index
)
388 private fun substring_impl
(from
, count
, end_index
: Int): String do
389 var cache
= _position
390 var dfrom
= (cache
- from
).abs
391 var dend
= (end_index
- from
).abs
396 bytefrom
= char_to_byte_index
(from
)
397 byteto
= char_to_byte_index
(end_index
)
399 byteto
= char_to_byte_index
(end_index
)
400 bytefrom
= char_to_byte_index
(from
)
404 byteto
+= its
.length_of_char_at
(byteto
) - 1
406 var s
= new FlatString.full
(its
, byteto
- bytefrom
+ 1, bytefrom
, count
)
410 redef fun empty
do return "".as(FlatString)
414 var outstr
= new FlatBuffer.with_capacity
(self._bytelen
+ 1)
420 outstr
.add
(chars
[pos
].to_upper
)
429 var outstr
= new FlatBuffer.with_capacity
(self._bytelen
+ 1)
435 outstr
.add
(chars
[pos
].to_lower
)
444 for i
in chars
do i
.output
447 ##################################################
448 # String Specific Methods #
449 ##################################################
451 # Low-level creation of a new string with minimal data.
453 # `_items` will be used as is, without copy, to retrieve the characters of the string.
454 # Aliasing issues is the responsibility of the caller.
455 private init with_infos
(items
: NativeString, bytelen
, from
: Int)
458 self._bytelen
= bytelen
461 _length
= _items
.utf8_length
(_first_byte
, last_byte
)
464 # Low-level creation of a new string with all the data.
466 # `_items` will be used as is, without copy, to retrieve the characters of the string.
467 # Aliasing issues is the responsibility of the caller.
468 private init full
(items
: NativeString, bytelen
, from
, length
: Int)
471 self._length
= length
472 self._bytelen
= bytelen
479 if not other
isa FlatText then return super
481 if self.object_id
== other
.object_id
then return true
483 var my_length
= _bytelen
485 if other
._bytelen
!= my_length
then return false
487 var my_index
= _first_byte
488 var its_index
= other
.first_byte
490 var last_iteration
= my_index
+ my_length
492 var its_items
= other
._items
493 var my_items
= self._items
495 while my_index
< last_iteration
do
496 if my_items
[my_index
] != its_items
[its_index
] then return false
506 if not other
isa FlatText then return super
508 if self.object_id
== other
.object_id
then return false
511 var itsits
= other
._items
514 var obt
= other
.bytelen
516 var minln
= if mbt
< obt
then mbt
else obt
517 var mst
= _first_byte
518 var ost
= other
.first_byte
520 for i
in [0 .. minln
[ do
521 var my_curr_char
= myits
[mst
]
522 var its_curr_char
= itsits
[ost
]
524 if my_curr_char
> its_curr_char
then return false
525 if my_curr_char
< its_curr_char
then return true
538 var nlen
= mlen
+ slen
540 var mifrom
= _first_byte
541 if s
isa FlatText then
543 var sifrom
= s
.first_byte
544 var ns
= new NativeString(nlen
+ 1)
545 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
546 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
547 return new FlatString.full
(ns
, nlen
, 0, _length
+ o
.length
)
554 var mybtlen
= _bytelen
555 var new_bytelen
= mybtlen
* i
557 var newlen
= mylen
* i
560 var ns
= new NativeString(new_bytelen
+ 1)
561 ns
[new_bytelen
] = 0u8
564 its
.copy_to
(ns
, mybtlen
, fb
, offset
)
568 return new FlatString.full
(ns
, new_bytelen
, 0, newlen
)
574 if hash_cache
== null then
575 # djb2 hash algorithm
579 var my_items
= _items
583 h
= (h
<< 5) + h
+ my_items
[i
].to_i
590 return hash_cache
.as(not null)
593 redef fun substrings
do return new FlatSubstringsIter(self)
596 private class FlatStringCharReverseIterator
597 super IndexedIterator[Char]
599 var target
: FlatString
603 redef fun is_ok
do return curr_pos
>= 0
605 redef fun item
do return target
[curr_pos
]
607 redef fun next
do curr_pos
-= 1
609 redef fun index
do return curr_pos
613 private class FlatStringCharIterator
614 super IndexedIterator[Char]
616 var target
: FlatString
618 var max
: Int is noautoinit
622 init do max
= target
._length
- 1
624 redef fun is_ok
do return curr_pos
<= max
626 redef fun item
do return target
[curr_pos
]
628 redef fun next
do curr_pos
+= 1
630 redef fun index
do return curr_pos
634 private class FlatStringCharView
637 redef type SELFTYPE: FlatString
639 redef fun [](index
) do return target
[index
]
641 redef fun iterator_from
(start
) do return new FlatStringCharIterator(target
, start
)
643 redef fun reverse_iterator_from
(start
) do return new FlatStringCharReverseIterator(target
, start
)
647 private class FlatStringByteReverseIterator
648 super IndexedIterator[Byte]
650 var target
: FlatString
652 var target_items
: NativeString is noautoinit
659 target_items
= tgt
._items
660 curr_pos
+= tgt
._first_byte
663 redef fun is_ok
do return curr_pos
>= target
._first_byte
665 redef fun item
do return target_items
[curr_pos
]
667 redef fun next
do curr_pos
-= 1
669 redef fun index
do return curr_pos
- target
._first_byte
673 private class FlatStringByteIterator
674 super IndexedIterator[Byte]
676 var target
: FlatString
678 var target_items
: NativeString is noautoinit
685 target_items
= tgt
._items
686 curr_pos
+= tgt
._first_byte
689 redef fun is_ok
do return curr_pos
<= target
.last_byte
691 redef fun item
do return target_items
[curr_pos
]
693 redef fun next
do curr_pos
+= 1
695 redef fun index
do return curr_pos
- target
._first_byte
699 private class FlatStringByteView
702 redef type SELFTYPE: FlatString
706 # Check that the index (+ _first_byte) is not larger than last_byte
707 # In other terms, if the index is valid
709 assert index
>= 0 and index
< target
._bytelen
710 var ind
= index
+ target
._first_byte
711 return target
._items
[ind
]
714 redef fun iterator_from
(start
) do return new FlatStringByteIterator(target
, start
)
716 redef fun reverse_iterator_from
(start
) do return new FlatStringByteReverseIterator(target
, start
)
721 redef new do return new FlatBuffer
723 redef new with_cap
(i
) do return new FlatBuffer.with_capacity
(i
)
726 # Mutable strings of characters.
731 redef var chars
: Sequence[Char] = new FlatBufferCharView(self) is lazy
733 redef var bytes
= new FlatBufferByteView(self) is lazy
735 private var char_cache
: Int = -1
737 private var byte_cache
: Int = -1
739 private var capacity
= 0
741 # Real items, used as cache for when to_cstring is called
742 private var real_items
: NativeString is noinit
744 redef fun fast_cstring
do return _items
.fast_cstring
(0)
746 redef fun substrings
do return new FlatSubstringsIter(self)
748 # Re-copies the `NativeString` into a new one and sets it as the new `Buffer`
750 # This happens when an operation modifies the current `Buffer` and
751 # the Copy-On-Write flag `written` is set at true.
753 var nns
= new NativeString(capacity
)
754 if _bytelen
!= 0 then _items
.copy_to
(nns
, _bytelen
, 0, 0)
759 # Shifts the content of the buffer by `len` bytes to the right, starting at byte `from`
761 # Internal only, does not modify _bytelen or length, this is the caller's responsability
762 private fun rshift_bytes
(from
: Int, len
: Int) do
766 if bt
+ len
> capacity
then
767 capacity
= capacity
* 2 + 2
768 nit
= new NativeString(capacity
)
769 oit
.copy_to
(nit
, 0, 0, from
)
771 oit
.copy_to
(nit
, bt
- from
, from
, from
+ len
)
774 # Shifts the content of the buffer by `len` bytes to the left, starting at `from`
776 # Internal only, does not modify _bytelen or length, this is the caller's responsability
777 private fun lshift_bytes
(from
: Int, len
: Int) do
779 it
.copy_to
(it
, _bytelen
- from
, from
, from
- len
)
782 redef fun []=(index
, item
)
784 assert index
>= 0 and index
<= _length
785 if written
then reset
787 if index
== _length
then
792 var ip
= it
.char_to_byte_index
(index
)
793 var c
= it
.char_at
(ip
)
794 var clen
= c
.u8char_len
795 var itemlen
= item
.u8char_len
796 var size_diff
= itemlen
- clen
797 if size_diff
> 0 then
798 rshift_bytes
(ip
+ clen
, size_diff
)
799 else if size_diff
< 0 then
800 lshift_bytes
(ip
+ clen
, -size_diff
)
802 _bytelen
+= size_diff
803 it
.set_char_at
(ip
, item
)
808 if written
then reset
810 var clen
= c
.u8char_len
813 _items
.set_char_at
(bt
, c
)
820 if written
then reset
825 redef fun empty
do return new Buffer
827 redef fun enlarge
(cap
)
830 if cap
<= c
then return
831 while c
<= cap
do c
= c
* 2 + 2
832 # The COW flag can be set at false here, since
833 # it does a copy of the current `Buffer`
836 var a
= new NativeString(c
+1)
839 if bln
> 0 then it
.copy_to
(a
, bln
, 0, 0)
849 if bln
== 0 then _items
= new NativeString(1)
850 return new FlatString.full
(_items
, bln
, 0, _length
)
857 var new_native
= new NativeString(bln
+ 1)
858 new_native
[bln
] = 0u8
859 if _length
> 0 then _items
.copy_to
(new_native
, bln
, 0, 0)
860 real_items
= new_native
866 # Create a new empty string.
869 # Low-level creation a new buffer with given data.
871 # `_items` will be used as is, without copy, to store the characters of the buffer.
872 # Aliasing issues is the responsibility of the caller.
874 # If `_items` is shared, `written` should be set to true after the creation
875 # so that a modification will do a copy-on-write.
876 private init with_infos
(items
: NativeString, capacity
, bytelen
, length
: Int)
879 self.capacity
= capacity
880 self._bytelen
= bytelen
881 self._length
= length
884 # Create a new string copied from `s`.
887 _items
= new NativeString(s
.bytelen
)
888 if s
isa FlatText then
891 for i
in substrings
do i
.as(FlatString)._items
.copy_to
(_items
, i
._bytelen
, 0, 0)
899 # Create a new empty string with a given capacity.
900 init with_capacity
(cap
: Int)
903 _items
= new NativeString(cap
+ 1)
910 if s
.is_empty
then return
913 var nln
= _bytelen
+ sl
915 if s
isa FlatText then
916 s
._items
.copy_to
(_items
, sl
, s
.first_byte
, _bytelen
)
918 for i
in s
.substrings
do append i
925 # Copies the content of self in `dest`
926 fun copy
(start
: Int, len
: Int, dest
: Buffer, new_start
: Int)
928 var self_chars
= self.chars
929 var dest_chars
= dest
.chars
930 for i
in [0..len-1
] do
931 dest_chars
[new_start
+i
] = self_chars
[start
+i
]
935 redef fun substring
(from
, count
)
938 if from
< 0 then from
= 0
939 if (from
+ count
) > _length
then count
= _length
- from
940 if count
<= 0 then return new Buffer
942 var bytefrom
= its
.char_to_byte_index
(from
)
943 var byteto
= its
.char_to_byte_index
(count
+ from
- 1)
944 byteto
+= its
.char_at
(byteto
).u8char_len
- 1
945 var byte_length
= byteto
- bytefrom
+ 1
946 var r_items
= new NativeString(byte_length
)
947 its
.copy_to
(r_items
, byte_length
, bytefrom
, 0)
948 return new FlatBuffer.with_infos
(r_items
, byte_length
, byte_length
, count
)
954 var ns
= new FlatBuffer.with_capacity
(capacity
)
955 for i
in chars
.reverse_iterator
do ns
.add i
959 redef fun times
(repeats
)
962 var x
= new FlatString.full
(_items
, bln
, 0, _length
)
963 for i
in [1 .. repeats
[ do
970 if written
then reset
971 for i
in [0 .. _length
[ do self[i
] = self[i
].to_upper
976 if written
then reset
977 for i
in [0 .. _length
[ do self[i
] = self[i
].to_lower
981 private class FlatBufferByteReverseIterator
982 super IndexedIterator[Byte]
984 var target
: FlatBuffer
986 var target_items
: NativeString is noautoinit
990 init do target_items
= target
._items
992 redef fun index
do return curr_pos
994 redef fun is_ok
do return curr_pos
>= 0
996 redef fun item
do return target_items
[curr_pos
]
998 redef fun next
do curr_pos
-= 1
1002 private class FlatBufferByteView
1003 super BufferByteView
1005 redef type SELFTYPE: FlatBuffer
1007 redef fun [](index
) do return target
._items
[index
]
1009 redef fun iterator_from
(pos
) do return new FlatBufferByteIterator(target
, pos
)
1011 redef fun reverse_iterator_from
(pos
) do return new FlatBufferByteReverseIterator(target
, pos
)
1015 private class FlatBufferByteIterator
1016 super IndexedIterator[Byte]
1018 var target
: FlatBuffer
1020 var target_items
: NativeString is noautoinit
1024 init do target_items
= target
._items
1026 redef fun index
do return curr_pos
1028 redef fun is_ok
do return curr_pos
< target
._bytelen
1030 redef fun item
do return target_items
[curr_pos
]
1032 redef fun next
do curr_pos
+= 1
1036 private class FlatBufferCharReverseIterator
1037 super IndexedIterator[Char]
1039 var target
: FlatBuffer
1043 redef fun index
do return curr_pos
1045 redef fun is_ok
do return curr_pos
>= 0
1047 redef fun item
do return target
[curr_pos
]
1049 redef fun next
do curr_pos
-= 1
1053 private class FlatBufferCharView
1054 super BufferCharView
1056 redef type SELFTYPE: FlatBuffer
1058 redef fun [](index
) do return target
[index
]
1060 redef fun []=(index
, item
)
1062 assert index
>= 0 and index
<= length
1063 if index
== length
then
1067 target
[index
] = item
1080 fun enlarge
(cap
: Int)
1087 var s_length
= s
.length
1088 if target
.capacity
< s
.length
then enlarge
(s_length
+ target
._length
)
1089 for i
in s
do target
.add i
1092 redef fun iterator_from
(pos
) do return new FlatBufferCharIterator(target
, pos
)
1094 redef fun reverse_iterator_from
(pos
) do return new FlatBufferCharReverseIterator(target
, pos
)
1098 private class FlatBufferCharIterator
1099 super IndexedIterator[Char]
1101 var target
: FlatBuffer
1103 var max
: Int is noautoinit
1107 init do max
= target
._length
- 1
1109 redef fun index
do return curr_pos
1111 redef fun is_ok
do return curr_pos
<= max
1113 redef fun item
do return target
[curr_pos
]
1115 redef fun next
do curr_pos
+= 1
1119 redef class NativeString
1122 return to_s_with_length
(cstring_length
)
1125 # Returns `self` as a String of `length`.
1126 redef fun to_s_with_length
(length
): FlatString
1129 return clean_utf8
(length
)
1132 redef fun to_s_full
(bytelen
, unilen
) do
1133 return new FlatString.full
(self, bytelen
, 0, unilen
)
1136 redef fun to_s_unsafe
(len
) do
1137 if len
== null then len
= cstring_length
1138 return new FlatString.with_infos
(self, len
, 0)
1141 # Returns `self` as a new String.
1142 redef fun to_s_with_copy
: FlatString
1144 var length
= cstring_length
1145 var r
= clean_utf8
(length
)
1146 if r
.items
!= self then return r
1147 var new_self
= new NativeString(length
+ 1)
1148 copy_to
(new_self
, length
, 0, 0)
1149 var str
= new FlatString.with_infos
(new_self
, length
, 0)
1150 new_self
[length
] = 0u8
1151 str
.to_cstring
= new_self
1155 # Cleans a NativeString if necessary
1156 fun clean_utf8
(len
: Int): FlatString do
1157 var replacements
: nullable Array[Int] = null
1158 var end_length
= len
1164 var i
= fetch_4_chars
(pos
)
1165 if i
& 0x80808080 != 0 then break
1170 if rem
== 0 then break
1172 if b
& 0x80u
8 == 0x00u
8 then
1178 var nxst
= length_of_char_at
(pos
)
1181 ok_st
= b
& 0x80u
8 == 0u8
1182 else if nxst
== 2 then
1183 ok_st
= b
& 0xE0u
8 == 0xC0u
8
1184 else if nxst
== 3 then
1185 ok_st
= b
& 0xF0u
8 == 0xE0u
8
1187 ok_st
= b
& 0xF8u
8 == 0xF0u
8
1190 if replacements
== null then replacements
= new Array[Int]
1191 replacements
.add pos
1199 var c
= char_at
(pos
)
1200 var cp
= c
.code_point
1202 ok_c
= cp
>= 0 and cp
<= 0x7F
1203 else if nxst
== 2 then
1204 ok_c
= cp
>= 0x80 and cp
<= 0x7FF
1205 else if nxst
== 3 then
1206 ok_c
= cp
>= 0x800 and cp
<= 0xFFFF
1207 ok_c
= ok_c
and not (cp
>= 0xD800 and cp
<= 0xDFFF) and cp
!= 0xFFFE and cp
!= 0xFFFF
1209 ok_c
= cp
>= 0x10000 and cp
<= 0x10FFFF
1212 if replacements
== null then replacements
= new Array[Int]
1213 replacements
.add pos
1220 var clen
= c
.u8char_len
1226 if end_length
!= len
then
1227 ret
= new NativeString(end_length
)
1230 var repls
= replacements
.as(not null)
1231 var r
= repls
.items
.as(not null)
1232 var imax
= repls
.length
1233 for i
in [0 .. imax
[ do
1235 var chkln
= repl_pos
- old_repl
1236 copy_to
(ret
, chkln
, old_repl
, off
)
1239 ret
[off
+ 1] = 0xBFu
8
1240 ret
[off
+ 2] = 0xBDu
8
1241 old_repl
= repl_pos
+ 1
1244 copy_to
(ret
, len
- old_repl
, old_repl
, off
)
1246 return new FlatString.full
(ret
, end_length
, 0, chr_ln
)
1249 # Sets the next bytes at position `pos` to the value of `c`, encoded in UTF-8
1251 # Very unsafe, make sure to have room for this char prior to calling this function.
1252 private fun set_char_at
(pos
: Int, c
: Char) do
1253 var ln
= c
.u8char_len
1254 native_set_char
(pos
, c
, ln
)
1257 private fun native_set_char
(pos
: Int, c
: Char, ln
: Int) `{
1258 char* dst = self + pos;
1264 dst[0] = 0xC0 | ((c & 0x7C0) >> 6);
1265 dst[1] = 0x80 | (c & 0x3F);
1268 dst[0] = 0xE0 | ((c & 0xF000) >> 12);
1269 dst[1] = 0x80 | ((c & 0xFC0) >> 6);
1270 dst[2] = 0x80 | (c & 0x3F);
1273 dst[0] = 0xF0 | ((c & 0x1C0000) >> 18);
1274 dst[1] = 0x80 | ((c & 0x3F000) >> 12);
1275 dst[2] = 0x80 | ((c & 0xFC0) >> 6);
1276 dst[3] = 0x80 | (c & 0x3F);
1283 redef fun to_base
(base
, signed
)
1285 var l
= digit_count
(base
)
1286 var s
= new FlatBuffer.from
(" " * l
)
1287 fill_buffer
(s
, base
, signed
)
1291 # return displayable int in base 10 and signed
1293 # assert 1.to_s == "1"
1294 # assert (-123).to_s == "-123"
1296 # Fast case for common numbers
1297 if self == 0 then return "0"
1298 if self == 1 then return "1"
1300 var nslen
= int_to_s_len
1301 var ns
= new NativeString(nslen
+ 1)
1303 native_int_to_s
(ns
, nslen
+ 1)
1304 return new FlatString.full
(ns
, nslen
, 0, nslen
)
1308 redef class Array[E
]
1310 # Fast implementation
1311 redef fun plain_to_s
1314 if l
== 0 then return ""
1315 var its
= _items
.as(not null)
1317 if l
== 1 then if first
== null then return "" else return first
.to_s
1318 var na
= new NativeArray[String](l
)
1324 if itsi
== null then
1334 var ns
= new NativeString(sl
+ 1)
1340 if tmp
isa FlatString then
1341 var tpl
= tmp
._bytelen
1342 tmp
._items
.copy_to
(ns
, tpl
, tmp
._first_byte
, off
)
1345 for j
in tmp
.substrings
do
1346 var s
= j
.as(FlatString)
1347 var slen
= s
._bytelen
1348 s
._items
.copy_to
(ns
, slen
, s
._first_byte
, off
)
1354 return new FlatString.with_infos
(ns
, sl
, 0)
1358 redef class NativeArray[E
]
1359 redef fun native_to_s
do
1360 assert self isa NativeArray[String]
1371 var ns
= new NativeString(sl
+ 1)
1377 if tmp
isa FlatString then
1378 var tpl
= tmp
._bytelen
1379 tmp
._items
.copy_to
(ns
, tpl
, tmp
._first_byte
, off
)
1382 for j
in tmp
.substrings
do
1383 var s
= j
.as(FlatString)
1384 var slen
= s
._bytelen
1385 s
._items
.copy_to
(ns
, slen
, s
._first_byte
, off
)
1391 return new FlatString.with_infos
(ns
, sl
, 0)
1395 redef class Map[K
,V
]
1396 redef fun join
(sep
, couple_sep
)
1398 if is_empty
then return ""
1400 var s
= new Buffer # Result
1406 s
.append
("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
1408 # Concat other _items
1414 s
.append
("{k or else "<null>"}{couple_sep}{e or else "<null>"}")