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 _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
58 # Find best insertion point
59 var delta_begin
= index
60 var delta_end
= (ln
- 1) - index
61 var delta_cache
= (pos
- index
).abs
65 if delta_cache
< min
then min
= delta_cache
66 if delta_end
< min
then min
= delta_end
71 if min
== delta_begin
then
74 else if min
== delta_cache
then
78 ns_i
= its
.find_beginning_of_char_at
(last_byte
)
82 ns_i
= its
.char_to_byte_index_cached
(index
, my_i
, ns_i
)
90 # By escaping `self` to HTML, how many more bytes will be needed ?
91 fun chars_to_html_escape
: Int do
100 else if c
== 0x3Eu
8 then
102 else if c
== 0x26u
8 then
104 else if c
== 0x22u
8 then
106 else if c
== 0x27u
8 then
108 else if c
== 0x2Fu
8 then
116 redef fun html_escape
118 var extra
= chars_to_html_escape
119 if extra
== 0 then return to_s
123 var nlen
= extra
+ _bytelen
124 var nits
= new NativeString(nlen
)
129 # Some HTML characters are used as meta-data, they need
130 # to be replaced by an HTML-Escaped equivalent
134 # * 0x26 (&) => &
135 # * 0x22 (") => "
136 # * 0x27 (') => '
137 # * 0x2F (/) => /
139 nits
[outpos
] = 0x26u
8
140 nits
[outpos
+ 1] = 0x6Cu
8
141 nits
[outpos
+ 2] = 0x74u
8
142 nits
[outpos
+ 3] = 0x3Bu
8
144 else if c
== 0x3Eu
8 then
145 nits
[outpos
] = 0x26u
8
146 nits
[outpos
+ 1] = 0x67u
8
147 nits
[outpos
+ 2] = 0x74u
8
148 nits
[outpos
+ 3] = 0x3Bu
8
150 else if c
== 0x26u
8 then
151 nits
[outpos
] = 0x26u
8
152 nits
[outpos
+ 1] = 0x61u
8
153 nits
[outpos
+ 2] = 0x6Du
8
154 nits
[outpos
+ 3] = 0x70u
8
155 nits
[outpos
+ 4] = 0x3Bu
8
157 else if c
== 0x22u
8 then
158 nits
[outpos
] = 0x26u
8
159 nits
[outpos
+ 1] = 0x23u
8
160 nits
[outpos
+ 2] = 0x33u
8
161 nits
[outpos
+ 3] = 0x34u
8
162 nits
[outpos
+ 4] = 0x3Bu
8
164 else if c
== 0x27u
8 then
165 nits
[outpos
] = 0x26u
8
166 nits
[outpos
+ 1] = 0x23u
8
167 nits
[outpos
+ 2] = 0x33u
8
168 nits
[outpos
+ 3] = 0x39u
8
169 nits
[outpos
+ 4] = 0x3Bu
8
171 else if c
== 0x2Fu
8 then
172 nits
[outpos
] = 0x26u
8
173 nits
[outpos
+ 1] = 0x23u
8
174 nits
[outpos
+ 2] = 0x34u
8
175 nits
[outpos
+ 3] = 0x37u
8
176 nits
[outpos
+ 4] = 0x3Bu
8
184 var s
= new FlatString.with_infos
(nits
, nlen
, 0, nlen
- 1)
188 # By escaping `self` to C, how many more bytes will be needed ?
190 # This enables a double-optimization in `escape_to_c` since if this
191 # method returns 0, then `self` does not need escaping and can be
193 fun chars_to_escape_to_c
: Int do
202 else if c
== 0x09u
8 then
204 else if c
== 0x22u
8 then
206 else if c
== 0x27u
8 then
208 else if c
== 0x5Cu
8 then
210 else if c
< 32u8
then
218 redef fun escape_to_c
do
219 var ln_extra
= chars_to_escape_to_c
220 if ln_extra
== 0 then return self.to_s
223 var nlen
= _bytelen
+ ln_extra
224 var nns
= new NativeString(nlen
)
231 # Any byte with value < 32 is a control character
232 # All their uses will be replaced by their octal
235 # There are two exceptions however:
240 # Aside from the code points above, the following are:
247 nns
[opos
+ 1] = 0x74u
8
249 else if c
== 0x0Au
8 then
251 nns
[opos
+ 1] = 0x6Eu
8
253 else if c
== 0x22u
8 then
255 nns
[opos
+ 1] = 0x22u
8
257 else if c
== 0x27u
8 then
259 nns
[opos
+ 1] = 0x27u
8
261 else if c
== 0x5Cu
8 then
263 nns
[opos
+ 1] = 0x5Cu
8
265 else if c
< 32u8
then
267 nns
[opos
+ 1] = 0x30u
8
268 nns
[opos
+ 2] = ((c
& 0x38u
8) >> 3) + 0x30u
8
269 nns
[opos
+ 3] = (c
& 0x07u
8) + 0x30u
8
277 return nns
.to_s_with_length
(nlen
)
280 redef fun [](index
) do return _items
.char_at
(char_to_byte_index
(index
))
283 # Immutable strings of characters.
288 # Index at which `self` begins in `_items`, inclusively
289 redef var first_byte
is noinit
291 # Index at which `self` ends in `_items`, inclusively
292 redef var last_byte
is noinit
294 redef var chars
= new FlatStringCharView(self) is lazy
296 redef var bytes
= new FlatStringByteView(self) is lazy
298 redef var length
is lazy
do
299 if _bytelen
== 0 then return 0
300 return _items
.utf8_length
(_first_byte
, _last_byte
)
303 redef var to_cstring
is lazy
do
305 var new_items
= new NativeString(blen
+ 1)
306 _items
.copy_to
(new_items
, blen
, _first_byte
, 0)
307 new_items
[blen
] = 0u8
313 var b
= new FlatBuffer.with_capacity
(_bytelen
+ 1)
314 for i
in [length
- 1 .. 0].step
(-1) do
317 var s
= b
.to_s
.as(FlatString)
318 s
.length
= self.length
322 redef fun fast_cstring
do return _items
.fast_cstring
(_first_byte
)
324 redef fun substring
(from
, count
)
330 if count
< 0 then count
= 0
334 if (count
+ from
) > length
then count
= length
- from
335 if count
<= 0 then return ""
336 var end_index
= from
+ count
- 1
338 var bytefrom
= char_to_byte_index
(from
)
339 var byteto
= char_to_byte_index
(end_index
)
341 byteto
+= its
.length_of_char_at
(byteto
) - 1
343 var s
= new FlatString.full
(its
, byteto
- bytefrom
+ 1, bytefrom
, byteto
, count
)
347 redef fun empty
do return "".as(FlatString)
351 var outstr
= new FlatBuffer.with_capacity
(self._bytelen
+ 1)
357 outstr
.add
(chars
[pos
].to_upper
)
366 var outstr
= new FlatBuffer.with_capacity
(self._bytelen
+ 1)
372 outstr
.add
(chars
[pos
].to_lower
)
381 for i
in chars
do i
.output
384 ##################################################
385 # String Specific Methods #
386 ##################################################
388 # Low-level creation of a new string with minimal data.
390 # `_items` will be used as is, without copy, to retrieve the characters of the string.
391 # Aliasing issues is the responsibility of the caller.
392 private init with_infos
(items
: NativeString, bytelen
, from
, to
: Int)
395 self._bytelen
= bytelen
401 # Low-level creation of a new string with all the data.
403 # `_items` will be used as is, without copy, to retrieve the characters of the string.
404 # Aliasing issues is the responsibility of the caller.
405 private init full
(items
: NativeString, bytelen
, from
, to
, length
: Int)
409 self._bytelen
= bytelen
417 if not other
isa FlatText then return super
419 if self.object_id
== other
.object_id
then return true
421 var my_length
= _bytelen
423 if other
._bytelen
!= my_length
then return false
425 var my_index
= _first_byte
426 var its_index
= other
.first_byte
428 var last_iteration
= my_index
+ my_length
430 var its_items
= other
._items
431 var my_items
= self._items
433 while my_index
< last_iteration
do
434 if my_items
[my_index
] != its_items
[its_index
] then return false
444 if not other
isa FlatText then return super
446 if self.object_id
== other
.object_id
then return false
449 var itsits
= other
._items
452 var obt
= other
.bytelen
454 var minln
= if mbt
< obt
then mbt
else obt
455 var mst
= _first_byte
456 var ost
= other
.first_byte
458 for i
in [0 .. minln
[ do
459 var my_curr_char
= myits
[mst
]
460 var its_curr_char
= itsits
[ost
]
462 if my_curr_char
> its_curr_char
then return false
463 if my_curr_char
< its_curr_char
then return true
476 var nlen
= mlen
+ slen
478 var mifrom
= _first_byte
479 if s
isa FlatText then
481 var sifrom
= s
.first_byte
482 var ns
= new NativeString(nlen
+ 1)
483 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
484 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
485 return new FlatString.full
(ns
, nlen
, 0, nlen
- 1, length
+ o
.length
)
492 var mybtlen
= _bytelen
493 var new_bytelen
= mybtlen
* i
495 var newlen
= mylen
* i
498 var ns
= new NativeString(new_bytelen
+ 1)
499 ns
[new_bytelen
] = 0u8
502 its
.copy_to
(ns
, mybtlen
, fb
, offset
)
506 return new FlatString.full
(ns
, new_bytelen
, 0, new_bytelen
- 1, newlen
)
512 if hash_cache
== null then
513 # djb2 hash algorithm
517 var my_items
= _items
521 h
= (h
<< 5) + h
+ my_items
[i
].to_i
528 return hash_cache
.as(not null)
531 redef fun substrings
do return new FlatSubstringsIter(self)
534 private class FlatStringCharReverseIterator
535 super IndexedIterator[Char]
537 var target
: FlatString
541 redef fun is_ok
do return curr_pos
>= 0
543 redef fun item
do return target
[curr_pos
]
545 redef fun next
do curr_pos
-= 1
547 redef fun index
do return curr_pos
551 private class FlatStringCharIterator
552 super IndexedIterator[Char]
554 var target
: FlatString
556 var max
: Int is noautoinit
560 init do max
= target
.length
- 1
562 redef fun is_ok
do return curr_pos
<= max
564 redef fun item
do return target
[curr_pos
]
566 redef fun next
do curr_pos
+= 1
568 redef fun index
do return curr_pos
572 private class FlatStringCharView
575 redef type SELFTYPE: FlatString
577 redef fun [](index
) do return target
[index
]
579 redef fun iterator_from
(start
) do return new FlatStringCharIterator(target
, start
)
581 redef fun reverse_iterator_from
(start
) do return new FlatStringCharReverseIterator(target
, start
)
585 private class FlatStringByteReverseIterator
586 super IndexedIterator[Byte]
588 var target
: FlatString
590 var target_items
: NativeString is noautoinit
597 target_items
= tgt
._items
598 curr_pos
+= tgt
._first_byte
601 redef fun is_ok
do return curr_pos
>= target
._first_byte
603 redef fun item
do return target_items
[curr_pos
]
605 redef fun next
do curr_pos
-= 1
607 redef fun index
do return curr_pos
- target
._first_byte
611 private class FlatStringByteIterator
612 super IndexedIterator[Byte]
614 var target
: FlatString
616 var target_items
: NativeString is noautoinit
623 target_items
= tgt
._items
624 curr_pos
+= tgt
._first_byte
627 redef fun is_ok
do return curr_pos
<= target
._last_byte
629 redef fun item
do return target_items
[curr_pos
]
631 redef fun next
do curr_pos
+= 1
633 redef fun index
do return curr_pos
- target
._first_byte
637 private class FlatStringByteView
640 redef type SELFTYPE: FlatString
644 # Check that the index (+ _first_byte) is not larger than _last_byte
645 # In other terms, if the index is valid
647 var target
= self.target
648 var ind
= index
+ target
._first_byte
649 assert ind
<= target
._last_byte
650 return target
._items
[ind
]
653 redef fun iterator_from
(start
) do return new FlatStringByteIterator(target
, start
)
655 redef fun reverse_iterator_from
(start
) do return new FlatStringByteReverseIterator(target
, start
)
660 redef new do return new FlatBuffer
662 redef new with_cap
(i
) do return new FlatBuffer.with_capacity
(i
)
665 # Mutable strings of characters.
670 redef var chars
: Sequence[Char] = new FlatBufferCharView(self) is lazy
672 redef var bytes
= new FlatBufferByteView(self) is lazy
676 private var char_cache
: Int = -1
678 private var byte_cache
: Int = -1
680 private var capacity
= 0
682 # Real items, used as cache for when to_cstring is called
683 private var real_items
: NativeString is noinit
685 redef fun fast_cstring
do return _items
.fast_cstring
(0)
687 redef fun substrings
do return new FlatSubstringsIter(self)
689 # Re-copies the `NativeString` into a new one and sets it as the new `Buffer`
691 # This happens when an operation modifies the current `Buffer` and
692 # the Copy-On-Write flag `written` is set at true.
694 var nns
= new NativeString(capacity
)
695 if _bytelen
!= 0 then _items
.copy_to
(nns
, _bytelen
, 0, 0)
700 # Shifts the content of the buffer by `len` bytes to the right, starting at byte `from`
702 # Internal only, does not modify _bytelen or length, this is the caller's responsability
703 private fun rshift_bytes
(from
: Int, len
: Int) do
707 if bt
+ len
> capacity
then
708 capacity
= capacity
* 2 + 2
709 nit
= new NativeString(capacity
)
710 oit
.copy_to
(nit
, 0, 0, from
)
712 oit
.copy_to
(nit
, bt
- from
, from
, from
+ len
)
715 # Shifts the content of the buffer by `len` bytes to the left, starting at `from`
717 # Internal only, does not modify _bytelen or length, this is the caller's responsability
718 private fun lshift_bytes
(from
: Int, len
: Int) do
720 it
.copy_to
(it
, _bytelen
- from
, from
, from
- len
)
723 redef fun []=(index
, item
)
725 assert index
>= 0 and index
<= length
726 if written
then reset
728 if index
== length
then
733 var ip
= it
.char_to_byte_index
(index
)
734 var c
= it
.char_at
(ip
)
735 var clen
= c
.u8char_len
736 var itemlen
= item
.u8char_len
737 var size_diff
= itemlen
- clen
738 if size_diff
> 0 then
739 rshift_bytes
(ip
+ clen
, size_diff
)
740 else if size_diff
< 0 then
741 lshift_bytes
(ip
+ clen
, -size_diff
)
743 _bytelen
+= size_diff
745 it
.set_char_at
(ip
, item
)
750 if written
then reset
752 var clen
= c
.u8char_len
755 _items
.set_char_at
(bt
, c
)
762 if written
then reset
767 redef fun empty
do return new Buffer
769 redef fun enlarge
(cap
)
772 if cap
<= c
then return
773 while c
<= cap
do c
= c
* 2 + 2
774 # The COW flag can be set at false here, since
775 # it does a copy of the current `Buffer`
778 var a
= new NativeString(c
+1)
781 if bln
> 0 then it
.copy_to
(a
, bln
, 0, 0)
791 if bln
== 0 then _items
= new NativeString(1)
792 return new FlatString.full
(_items
, bln
, 0, bln
- 1, length
)
799 var new_native
= new NativeString(bln
+ 1)
800 new_native
[bln
] = 0u8
801 if length
> 0 then _items
.copy_to
(new_native
, bln
, 0, 0)
802 real_items
= new_native
808 # Create a new empty string.
811 # Low-level creation a new buffer with given data.
813 # `_items` will be used as is, without copy, to store the characters of the buffer.
814 # Aliasing issues is the responsibility of the caller.
816 # If `_items` is shared, `written` should be set to true after the creation
817 # so that a modification will do a copy-on-write.
818 private init with_infos
(items
: NativeString, capacity
, bytelen
, length
: Int)
821 self.capacity
= capacity
822 self._bytelen
= bytelen
826 # Create a new string copied from `s`.
829 _items
= new NativeString(s
.bytelen
)
830 if s
isa FlatText then
833 for i
in substrings
do i
.as(FlatString)._items
.copy_to
(_items
, i
._bytelen
, 0, 0)
841 # Create a new empty string with a given capacity.
842 init with_capacity
(cap
: Int)
845 _items
= new NativeString(cap
+ 1)
852 if s
.is_empty
then return
855 var nln
= _bytelen
+ sl
857 if s
isa FlatText then
858 s
._items
.copy_to
(_items
, sl
, s
.first_byte
, _bytelen
)
860 for i
in s
.substrings
do append i
867 # Copies the content of self in `dest`
868 fun copy
(start
: Int, len
: Int, dest
: Buffer, new_start
: Int)
870 var self_chars
= self.chars
871 var dest_chars
= dest
.chars
872 for i
in [0..len-1
] do
873 dest_chars
[new_start
+i
] = self_chars
[start
+i
]
877 redef fun substring
(from
, count
)
880 if from
< 0 then from
= 0
881 if (from
+ count
) > length
then count
= length
- from
882 if count
<= 0 then return new Buffer
884 var bytefrom
= its
.char_to_byte_index
(from
)
885 var byteto
= its
.char_to_byte_index
(count
+ from
- 1)
886 byteto
+= its
.char_at
(byteto
).u8char_len
- 1
887 var byte_length
= byteto
- bytefrom
+ 1
888 var r_items
= new NativeString(byte_length
)
889 its
.copy_to
(r_items
, byte_length
, bytefrom
, 0)
890 return new FlatBuffer.with_infos
(r_items
, byte_length
, byte_length
, count
)
896 var ns
= new FlatBuffer.with_capacity
(capacity
)
897 for i
in chars
.reverse_iterator
do ns
.add i
901 redef fun times
(repeats
)
904 var x
= new FlatString.full
(_items
, bln
, 0, bln
- 1, length
)
905 for i
in [1 .. repeats
[ do
912 if written
then reset
913 for i
in [0 .. length
[ do self[i
] = self[i
].to_upper
918 if written
then reset
919 for i
in [0 .. length
[ do self[i
] = self[i
].to_lower
923 private class FlatBufferByteReverseIterator
924 super IndexedIterator[Byte]
926 var target
: FlatBuffer
928 var target_items
: NativeString is noautoinit
932 init do target_items
= target
._items
934 redef fun index
do return curr_pos
936 redef fun is_ok
do return curr_pos
>= 0
938 redef fun item
do return target_items
[curr_pos
]
940 redef fun next
do curr_pos
-= 1
944 private class FlatBufferByteView
947 redef type SELFTYPE: FlatBuffer
949 redef fun [](index
) do return target
._items
[index
]
951 redef fun iterator_from
(pos
) do return new FlatBufferByteIterator(target
, pos
)
953 redef fun reverse_iterator_from
(pos
) do return new FlatBufferByteReverseIterator(target
, pos
)
957 private class FlatBufferByteIterator
958 super IndexedIterator[Byte]
960 var target
: FlatBuffer
962 var target_items
: NativeString is noautoinit
966 init do target_items
= target
._items
968 redef fun index
do return curr_pos
970 redef fun is_ok
do return curr_pos
< target
._bytelen
972 redef fun item
do return target_items
[curr_pos
]
974 redef fun next
do curr_pos
+= 1
978 private class FlatBufferCharReverseIterator
979 super IndexedIterator[Char]
981 var target
: FlatBuffer
985 redef fun index
do return curr_pos
987 redef fun is_ok
do return curr_pos
>= 0
989 redef fun item
do return target
[curr_pos
]
991 redef fun next
do curr_pos
-= 1
995 private class FlatBufferCharView
998 redef type SELFTYPE: FlatBuffer
1000 redef fun [](index
) do return target
[index
]
1002 redef fun []=(index
, item
)
1004 assert index
>= 0 and index
<= length
1005 if index
== length
then
1009 target
[index
] = item
1022 fun enlarge
(cap
: Int)
1029 var s_length
= s
.length
1030 if target
.capacity
< s
.length
then enlarge
(s_length
+ target
.length
)
1031 for i
in s
do target
.add i
1034 redef fun iterator_from
(pos
) do return new FlatBufferCharIterator(target
, pos
)
1036 redef fun reverse_iterator_from
(pos
) do return new FlatBufferCharReverseIterator(target
, pos
)
1040 private class FlatBufferCharIterator
1041 super IndexedIterator[Char]
1043 var target
: FlatBuffer
1045 var max
: Int is noautoinit
1049 init do max
= target
.length
- 1
1051 redef fun index
do return curr_pos
1053 redef fun is_ok
do return curr_pos
<= max
1055 redef fun item
do return target
[curr_pos
]
1057 redef fun next
do curr_pos
+= 1
1061 redef class NativeString
1064 return to_s_with_length
(cstring_length
)
1067 # Returns `self` as a String of `length`.
1068 redef fun to_s_with_length
(length
): FlatString
1071 return clean_utf8
(length
)
1074 redef fun to_s_full
(bytelen
, unilen
) do
1075 return new FlatString.full
(self, bytelen
, 0, bytelen
- 1, unilen
)
1078 # Returns `self` as a new String.
1079 redef fun to_s_with_copy
: FlatString
1081 var length
= cstring_length
1082 var r
= clean_utf8
(length
)
1083 if r
.items
!= self then return r
1084 var new_self
= new NativeString(length
+ 1)
1085 copy_to
(new_self
, length
, 0, 0)
1086 var str
= new FlatString.with_infos
(new_self
, length
, 0, length
- 1)
1087 new_self
[length
] = 0u8
1088 str
.to_cstring
= new_self
1092 # Cleans a NativeString if necessary
1093 fun clean_utf8
(len
: Int): FlatString do
1094 var replacements
: nullable Array[Int] = null
1095 var end_length
= len
1100 var nxst
= length_of_char_at
(pos
)
1103 ok_st
= b
& 0x80u
8 == 0u8
1104 else if nxst
== 2 then
1105 ok_st
= b
& 0xE0u
8 == 0xC0u
8
1106 else if nxst
== 3 then
1107 ok_st
= b
& 0xF0u
8 == 0xE0u
8
1109 ok_st
= b
& 0xF8u
8 == 0xF0u
8
1112 if replacements
== null then replacements
= new Array[Int]
1113 replacements
.add pos
1120 var c
= char_at
(pos
)
1121 var cp
= c
.code_point
1123 ok_c
= cp
>= 0 and cp
<= 0x7F
1124 else if nxst
== 2 then
1125 ok_c
= cp
>= 0x80 and cp
<= 0x7FF
1126 else if nxst
== 3 then
1127 ok_c
= cp
>= 0x800 and cp
<= 0xFFFF
1128 ok_c
= ok_c
and not (cp
>= 0xD800 and cp
<= 0xDFFF) and cp
!= 0xFFFE and cp
!= 0xFFFF
1130 ok_c
= cp
>= 0x10000 and cp
<= 0x10FFFF
1133 if replacements
== null then replacements
= new Array[Int]
1134 replacements
.add pos
1144 if end_length
!= len
then
1145 ret
= new NativeString(end_length
)
1148 var repls
= replacements
.as(not null)
1149 var r
= repls
.items
.as(not null)
1150 var imax
= repls
.length
1151 for i
in [0 .. imax
[ do
1153 var chkln
= repl_pos
- old_repl
1154 copy_to
(ret
, chkln
, old_repl
, off
)
1157 ret
[off
+ 1] = 0xBFu
8
1158 ret
[off
+ 2] = 0xBDu
8
1159 old_repl
= repl_pos
+ 1
1162 copy_to
(ret
, len
- old_repl
, old_repl
, off
)
1164 return new FlatString.full
(ret
, end_length
, 0, end_length
- 1, chr_ln
)
1167 # Sets the next bytes at position `pos` to the value of `c`, encoded in UTF-8
1169 # Very unsafe, make sure to have room for this char prior to calling this function.
1170 private fun set_char_at
(pos
: Int, c
: Char) do
1171 var ln
= c
.u8char_len
1172 native_set_char
(pos
, c
, ln
)
1175 private fun native_set_char
(pos
: Int, c
: Char, ln
: Int) `{
1176 char* dst = self + pos;
1182 dst[0] = 0xC0 | ((c & 0x7C0) >> 6);
1183 dst[1] = 0x80 | (c & 0x3F);
1186 dst[0] = 0xE0 | ((c & 0xF000) >> 12);
1187 dst[1] = 0x80 | ((c & 0xFC0) >> 6);
1188 dst[2] = 0x80 | (c & 0x3F);
1191 dst[0] = 0xF0 | ((c & 0x1C0000) >> 18);
1192 dst[1] = 0x80 | ((c & 0x3F000) >> 12);
1193 dst[2] = 0x80 | ((c & 0xFC0) >> 6);
1194 dst[3] = 0x80 | (c & 0x3F);
1201 redef fun to_base
(base
, signed
)
1203 var l
= digit_count
(base
)
1204 var s
= new FlatBuffer.from
(" " * l
)
1205 fill_buffer
(s
, base
, signed
)
1209 # return displayable int in base 10 and signed
1211 # assert 1.to_s == "1"
1212 # assert (-123).to_s == "-123"
1214 # Fast case for common numbers
1215 if self == 0 then return "0"
1216 if self == 1 then return "1"
1218 var nslen
= int_to_s_len
1219 var ns
= new NativeString(nslen
+ 1)
1221 native_int_to_s
(ns
, nslen
+ 1)
1222 return new FlatString.full
(ns
, nslen
, 0, nslen
- 1, nslen
)
1226 redef class Array[E
]
1228 # Fast implementation
1229 redef fun plain_to_s
1232 if l
== 0 then return ""
1233 var its
= _items
.as(not null)
1235 if l
== 1 then if first
== null then return "" else return first
.to_s
1236 var na
= new NativeArray[String](l
)
1242 if itsi
== null then
1252 var ns
= new NativeString(sl
+ 1)
1258 if tmp
isa FlatString then
1259 var tpl
= tmp
._bytelen
1260 tmp
._items
.copy_to
(ns
, tpl
, tmp
._first_byte
, off
)
1263 for j
in tmp
.substrings
do
1264 var s
= j
.as(FlatString)
1265 var slen
= s
._bytelen
1266 s
._items
.copy_to
(ns
, slen
, s
._first_byte
, off
)
1272 return new FlatString.with_infos
(ns
, sl
, 0, sl
- 1)
1276 redef class NativeArray[E
]
1277 redef fun native_to_s
do
1278 assert self isa NativeArray[String]
1289 var ns
= new NativeString(sl
+ 1)
1295 if tmp
isa FlatString then
1296 var tpl
= tmp
._bytelen
1297 tmp
._items
.copy_to
(ns
, tpl
, tmp
._first_byte
, off
)
1300 for j
in tmp
.substrings
do
1301 var s
= j
.as(FlatString)
1302 var slen
= s
._bytelen
1303 s
._items
.copy_to
(ns
, slen
, s
._first_byte
, off
)
1309 return new FlatString.with_infos
(ns
, sl
, 0, sl
- 1)
1313 redef class Map[K
,V
]
1314 redef fun join
(sep
, couple_sep
)
1316 if is_empty
then return ""
1318 var s
= new Buffer # Result
1324 s
.append
("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
1326 # Concat other _items
1332 s
.append
("{k or else "<null>"}{couple_sep}{e or else "<null>"}")