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 private fun first_byte
: Int do return 0
41 private fun last_byte
: Int do return _bytelen
- 1
43 # Cache of the latest position (char) explored in the string
44 private var position
: Int = 0
46 # Cached position (bytes) in the NativeString underlying the String
47 private var bytepos
: Int = 0
49 # Index of the character `index` in `_items`
50 private fun char_to_byte_index
(index
: Int): Int do
56 # Find best insertion point
57 var delta_begin
= index
58 var delta_end
= (ln
- 1) - index
59 var delta_cache
= (pos
- index
).abs
63 if delta_cache
< min
then min
= delta_cache
64 if delta_end
< min
then min
= delta_end
69 if min
== delta_begin
then
72 else if min
== delta_cache
then
76 ns_i
= its
.find_beginning_of_char_at
(last_byte
)
80 ns_i
= its
.char_to_byte_index_cached
(index
, my_i
, ns_i
)
88 # By escaping `self` to C, how many more bytes will be needed ?
90 # This enables a double-optimization in `escape_to_c` since if this
91 # method returns 0, then `self` does not need escaping and can be
93 protected fun chars_to_escape_to_c
: Int do
102 else if c
== 0x09u
8 then
104 else if c
== 0x22u
8 then
106 else if c
== 0x27u
8 then
108 else if c
== 0x5Cu
8 then
110 else if c
< 32u8
then
118 redef fun escape_to_c
do
119 var ln_extra
= chars_to_escape_to_c
120 if ln_extra
== 0 then return self.to_s
123 var nlen
= _bytelen
+ ln_extra
124 var nns
= new NativeString(nlen
)
131 # Any byte with value < 32 is a control character
132 # All their uses will be replaced by their octal
135 # There are two exceptions however:
140 # Aside from the code points above, the following are:
147 nns
[opos
+ 1] = 0x74u
8
149 else if c
== 0x0Au
8 then
151 nns
[opos
+ 1] = 0x6Eu
8
153 else if c
== 0x22u
8 then
155 nns
[opos
+ 1] = 0x22u
8
157 else if c
== 0x27u
8 then
159 nns
[opos
+ 1] = 0x27u
8
161 else if c
== 0x5Cu
8 then
163 nns
[opos
+ 1] = 0x5Cu
8
165 else if c
< 32u8
then
167 nns
[opos
+ 1] = 0x30u
8
168 nns
[opos
+ 2] = ((c
& 0x38u
8) >> 3) + 0x30u
8
169 nns
[opos
+ 3] = (c
& 0x07u
8) + 0x30u
8
177 return nns
.to_s_with_length
(nlen
)
180 redef fun [](index
) do return _items
.char_at
(char_to_byte_index
(index
))
183 # Immutable strings of characters.
188 # Index at which `self` begins in `_items`, inclusively
189 redef var first_byte
is noinit
191 # Index at which `self` ends in `_items`, inclusively
192 redef var last_byte
is noinit
194 redef var chars
= new FlatStringCharView(self) is lazy
196 redef var bytes
= new FlatStringByteView(self) is lazy
198 redef var length
is lazy
do
199 if _bytelen
== 0 then return 0
200 return _items
.utf8_length
(_first_byte
, _last_byte
)
205 var b
= new FlatBuffer.with_capacity
(_bytelen
+ 1)
206 for i
in [length
- 1 .. 0].step
(-1) do
209 var s
= b
.to_s
.as(FlatString)
210 s
.length
= self.length
214 redef fun fast_cstring
do return _items
.fast_cstring
(_first_byte
)
216 redef fun substring
(from
, count
)
222 if count
< 0 then count
= 0
226 if (count
+ from
) > length
then count
= length
- from
227 if count
<= 0 then return ""
228 var end_index
= from
+ count
- 1
230 var bytefrom
= char_to_byte_index
(from
)
231 var byteto
= char_to_byte_index
(end_index
)
233 byteto
+= its
.length_of_char_at
(byteto
) - 1
235 var s
= new FlatString.full
(its
, byteto
- bytefrom
+ 1, bytefrom
, byteto
, count
)
239 redef fun empty
do return "".as(FlatString)
243 var outstr
= new FlatBuffer.with_capacity
(self._bytelen
+ 1)
249 outstr
.add
(chars
[pos
].to_upper
)
258 var outstr
= new FlatBuffer.with_capacity
(self._bytelen
+ 1)
264 outstr
.add
(chars
[pos
].to_lower
)
273 for i
in chars
do i
.output
276 ##################################################
277 # String Specific Methods #
278 ##################################################
280 # Low-level creation of a new string with minimal data.
282 # `_items` will be used as is, without copy, to retrieve the characters of the string.
283 # Aliasing issues is the responsibility of the caller.
284 private init with_infos
(items
: NativeString, bytelen
, from
, to
: Int)
287 self._bytelen
= bytelen
293 # Low-level creation of a new string with all the data.
295 # `_items` will be used as is, without copy, to retrieve the characters of the string.
296 # Aliasing issues is the responsibility of the caller.
297 private init full
(items
: NativeString, bytelen
, from
, to
, length
: Int)
301 self._bytelen
= bytelen
307 redef fun to_cstring
do
308 if real_items
!= null then return real_items
.as(not null)
310 var new_items
= new NativeString(blen
+ 1)
311 _items
.copy_to
(new_items
, blen
, _first_byte
, 0)
312 new_items
[blen
] = 0u8
313 real_items
= new_items
319 if not other
isa FlatString then return super
321 if self.object_id
== other
.object_id
then return true
323 var my_length
= _bytelen
325 if other
._bytelen
!= my_length
then return false
327 var my_index
= _first_byte
328 var its_index
= other
._first_byte
330 var last_iteration
= my_index
+ my_length
332 var its_items
= other
._items
333 var my_items
= self._items
335 while my_index
< last_iteration
do
336 if my_items
[my_index
] != its_items
[its_index
] then return false
346 if not other
isa FlatString then return super
348 if self.object_id
== other
.object_id
then return false
350 var my_length
= self._bytelen
351 var its_length
= other
._bytelen
353 var max
= if my_length
< its_length
then my_length
else its_length
355 var myits
= self.bytes
356 var itsits
= other
.bytes
358 for i
in [0 .. max
[ do
359 var my_curr_char
= myits
[i
]
360 var its_curr_char
= itsits
[i
]
362 if my_curr_char
!= its_curr_char
then
363 if my_curr_char
< its_curr_char
then return true
368 return my_length
< its_length
375 var nlen
= mlen
+ slen
377 var mifrom
= _first_byte
378 if s
isa FlatText then
380 var sifrom
= s
.first_byte
381 var ns
= new NativeString(nlen
+ 1)
382 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
383 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
384 return new FlatString.full
(ns
, nlen
, 0, nlen
- 1, length
+ o
.length
)
391 var mybtlen
= _bytelen
392 var new_bytelen
= mybtlen
* i
394 var newlen
= mylen
* i
397 var ns
= new NativeString(new_bytelen
+ 1)
398 ns
[new_bytelen
] = 0u8
401 its
.copy_to
(ns
, mybtlen
, fb
, offset
)
405 return new FlatString.full
(ns
, new_bytelen
, 0, new_bytelen
- 1, newlen
)
411 if hash_cache
== null then
412 # djb2 hash algorithm
416 var my_items
= _items
420 h
= (h
<< 5) + h
+ my_items
[i
].to_i
427 return hash_cache
.as(not null)
430 redef fun substrings
do return new FlatSubstringsIter(self)
433 private class FlatStringCharReverseIterator
434 super IndexedIterator[Char]
436 var target
: FlatString
440 init with_pos
(tgt
: FlatString, pos
: Int)
445 redef fun is_ok
do return curr_pos
>= 0
447 redef fun item
do return target
[curr_pos
]
449 redef fun next
do curr_pos
-= 1
451 redef fun index
do return curr_pos
455 private class FlatStringCharIterator
456 super IndexedIterator[Char]
458 var target
: FlatString
464 init with_pos
(tgt
: FlatString, pos
: Int)
466 init(tgt
, tgt
.length
- 1, pos
)
469 redef fun is_ok
do return curr_pos
<= max
471 redef fun item
do return target
[curr_pos
]
473 redef fun next
do curr_pos
+= 1
475 redef fun index
do return curr_pos
479 private class FlatStringCharView
482 redef type SELFTYPE: FlatString
484 redef fun [](index
) do return target
[index
]
486 redef fun iterator_from
(start
) do return new FlatStringCharIterator.with_pos
(target
, start
)
488 redef fun reverse_iterator_from
(start
) do return new FlatStringCharReverseIterator.with_pos
(target
, start
)
492 private class FlatStringByteReverseIterator
493 super IndexedIterator[Byte]
495 var target
: FlatString
497 var target_items
: NativeString
501 init with_pos
(tgt
: FlatString, pos
: Int)
503 init(tgt
, tgt
._items
, pos
+ tgt
._first_byte
)
506 redef fun is_ok
do return curr_pos
>= target
._first_byte
508 redef fun item
do return target_items
[curr_pos
]
510 redef fun next
do curr_pos
-= 1
512 redef fun index
do return curr_pos
- target
._first_byte
516 private class FlatStringByteIterator
517 super IndexedIterator[Byte]
519 var target
: FlatString
521 var target_items
: NativeString
525 init with_pos
(tgt
: FlatString, pos
: Int)
527 init(tgt
, tgt
._items
, pos
+ tgt
._first_byte
)
530 redef fun is_ok
do return curr_pos
<= target
._last_byte
532 redef fun item
do return target_items
[curr_pos
]
534 redef fun next
do curr_pos
+= 1
536 redef fun index
do return curr_pos
- target
._first_byte
540 private class FlatStringByteView
543 redef type SELFTYPE: FlatString
547 # Check that the index (+ _first_byte) is not larger than _last_byte
548 # In other terms, if the index is valid
550 var target
= self.target
551 var ind
= index
+ target
._first_byte
552 assert ind
<= target
._last_byte
553 return target
._items
[ind
]
556 redef fun iterator_from
(start
) do return new FlatStringByteIterator.with_pos
(target
, start
)
558 redef fun reverse_iterator_from
(start
) do return new FlatStringByteReverseIterator.with_pos
(target
, start
)
563 redef new do return new FlatBuffer
565 redef new with_cap
(i
) do return new FlatBuffer.with_capacity
(i
)
568 # Mutable strings of characters.
573 redef var chars
: Sequence[Char] = new FlatBufferCharView(self) is lazy
575 redef var bytes
= new FlatBufferByteView(self) is lazy
579 private var char_cache
: Int = -1
581 private var byte_cache
: Int = -1
583 private var capacity
= 0
585 redef fun fast_cstring
do return _items
.fast_cstring
(0)
587 redef fun substrings
do return new FlatSubstringsIter(self)
589 # Re-copies the `NativeString` into a new one and sets it as the new `Buffer`
591 # This happens when an operation modifies the current `Buffer` and
592 # the Copy-On-Write flag `written` is set at true.
594 var nns
= new NativeString(capacity
)
595 if _bytelen
!= 0 then _items
.copy_to
(nns
, _bytelen
, 0, 0)
600 # Shifts the content of the buffer by `len` bytes to the right, starting at byte `from`
602 # Internal only, does not modify _bytelen or length, this is the caller's responsability
603 private fun rshift_bytes
(from
: Int, len
: Int) do
607 if bt
+ len
> capacity
then
608 capacity
= capacity
* 2 + 2
609 nit
= new NativeString(capacity
)
610 oit
.copy_to
(nit
, 0, 0, from
)
612 oit
.copy_to
(nit
, bt
- from
, from
, from
+ len
)
615 # Shifts the content of the buffer by `len` bytes to the left, starting at `from`
617 # Internal only, does not modify _bytelen or length, this is the caller's responsability
618 private fun lshift_bytes
(from
: Int, len
: Int) do
620 it
.copy_to
(it
, _bytelen
- from
, from
, from
- len
)
623 redef fun []=(index
, item
)
625 assert index
>= 0 and index
<= length
626 if written
then reset
628 if index
== length
then
633 var ip
= it
.char_to_byte_index
(index
)
634 var c
= it
.char_at
(ip
)
635 var clen
= c
.u8char_len
636 var itemlen
= item
.u8char_len
637 var size_diff
= itemlen
- clen
638 if size_diff
> 0 then
639 rshift_bytes
(ip
+ clen
, size_diff
)
640 else if size_diff
< 0 then
641 lshift_bytes
(ip
+ clen
, -size_diff
)
643 _bytelen
+= size_diff
645 it
.set_char_at
(ip
, item
)
650 if written
then reset
652 var clen
= c
.u8char_len
655 _items
.set_char_at
(bt
, c
)
662 if written
then reset
667 redef fun empty
do return new Buffer
669 redef fun enlarge
(cap
)
672 if cap
<= c
then return
673 while c
<= cap
do c
= c
* 2 + 2
674 # The COW flag can be set at false here, since
675 # it does a copy of the current `Buffer`
678 var a
= new NativeString(c
+1)
681 if bln
> 0 then it
.copy_to
(a
, bln
, 0, 0)
691 if bln
== 0 then _items
= new NativeString(1)
692 return new FlatString.full
(_items
, bln
, 0, bln
- 1, length
)
699 var new_native
= new NativeString(bln
+ 1)
700 new_native
[bln
] = 0u8
701 if length
> 0 then _items
.copy_to
(new_native
, bln
, 0, 0)
702 real_items
= new_native
705 return real_items
.as(not null)
708 # Create a new empty string.
711 # Low-level creation a new buffer with given data.
713 # `_items` will be used as is, without copy, to store the characters of the buffer.
714 # Aliasing issues is the responsibility of the caller.
716 # If `_items` is shared, `written` should be set to true after the creation
717 # so that a modification will do a copy-on-write.
718 private init with_infos
(items
: NativeString, capacity
, bytelen
, length
: Int)
721 self.capacity
= capacity
722 self._bytelen
= bytelen
726 # Create a new string copied from `s`.
729 _items
= new NativeString(s
.bytelen
)
730 if s
isa FlatText then
733 for i
in substrings
do i
.as(FlatString)._items
.copy_to
(_items
, i
._bytelen
, 0, 0)
741 # Create a new empty string with a given capacity.
742 init with_capacity
(cap
: Int)
745 _items
= new NativeString(cap
+ 1)
752 if s
.is_empty
then return
755 var nln
= _bytelen
+ sl
757 if s
isa FlatText then
758 s
._items
.copy_to
(_items
, sl
, s
.first_byte
, _bytelen
)
760 for i
in s
.substrings
do append i
767 # Copies the content of self in `dest`
768 fun copy
(start
: Int, len
: Int, dest
: Buffer, new_start
: Int)
770 var self_chars
= self.chars
771 var dest_chars
= dest
.chars
772 for i
in [0..len-1
] do
773 dest_chars
[new_start
+i
] = self_chars
[start
+i
]
777 redef fun substring
(from
, count
)
780 if from
< 0 then from
= 0
781 if (from
+ count
) > length
then count
= length
- from
784 var bytefrom
= its
.char_to_byte_index
(from
)
785 var byteto
= its
.char_to_byte_index
(count
+ from
- 1)
786 byteto
+= its
.char_at
(byteto
).u8char_len
- 1
787 var byte_length
= byteto
- bytefrom
+ 1
788 var r_items
= new NativeString(byte_length
)
789 its
.copy_to
(r_items
, byte_length
, bytefrom
, 0)
790 return new FlatBuffer.with_infos
(r_items
, byte_length
, byte_length
, count
)
799 var ns
= new FlatBuffer.with_capacity
(capacity
)
800 for i
in chars
.reverse_iterator
do ns
.add i
804 redef fun times
(repeats
)
807 var x
= new FlatString.full
(_items
, bln
, 0, bln
- 1, length
)
808 for i
in [1 .. repeats
[ do
815 if written
then reset
816 for i
in [0 .. length
[ do self[i
] = self[i
].to_upper
821 if written
then reset
822 for i
in [0 .. length
[ do self[i
] = self[i
].to_lower
826 private class FlatBufferByteReverseIterator
827 super IndexedIterator[Byte]
829 var target
: FlatBuffer
831 var target_items
: NativeString
835 init with_pos
(tgt
: FlatBuffer, pos
: Int)
837 init(tgt
, tgt
._items
, pos
)
840 redef fun index
do return curr_pos
842 redef fun is_ok
do return curr_pos
>= 0
844 redef fun item
do return target_items
[curr_pos
]
846 redef fun next
do curr_pos
-= 1
850 private class FlatBufferByteView
853 redef type SELFTYPE: FlatBuffer
855 redef fun [](index
) do return target
._items
[index
]
857 redef fun iterator_from
(pos
) do return new FlatBufferByteIterator.with_pos
(target
, pos
)
859 redef fun reverse_iterator_from
(pos
) do return new FlatBufferByteReverseIterator.with_pos
(target
, pos
)
863 private class FlatBufferByteIterator
864 super IndexedIterator[Byte]
866 var target
: FlatBuffer
868 var target_items
: NativeString
872 init with_pos
(tgt
: FlatBuffer, pos
: Int)
874 init(tgt
, tgt
._items
, pos
)
877 redef fun index
do return curr_pos
879 redef fun is_ok
do return curr_pos
< target
._bytelen
881 redef fun item
do return target_items
[curr_pos
]
883 redef fun next
do curr_pos
+= 1
887 private class FlatBufferCharReverseIterator
888 super IndexedIterator[Char]
890 var target
: FlatBuffer
894 init with_pos
(tgt
: FlatBuffer, pos
: Int)
899 redef fun index
do return curr_pos
901 redef fun is_ok
do return curr_pos
>= 0
903 redef fun item
do return target
[curr_pos
]
905 redef fun next
do curr_pos
-= 1
909 private class FlatBufferCharView
912 redef type SELFTYPE: FlatBuffer
914 redef fun [](index
) do return target
[index
]
916 redef fun []=(index
, item
)
918 assert index
>= 0 and index
<= length
919 if index
== length
then
936 fun enlarge
(cap
: Int)
943 var s_length
= s
.length
944 if target
.capacity
< s
.length
then enlarge
(s_length
+ target
.length
)
945 for i
in s
do target
.add i
948 redef fun iterator_from
(pos
) do return new FlatBufferCharIterator.with_pos
(target
, pos
)
950 redef fun reverse_iterator_from
(pos
) do return new FlatBufferCharReverseIterator.with_pos
(target
, pos
)
954 private class FlatBufferCharIterator
955 super IndexedIterator[Char]
957 var target
: FlatBuffer
963 init with_pos
(tgt
: FlatBuffer, pos
: Int)
965 init(tgt
, tgt
.length
- 1, pos
)
968 redef fun index
do return curr_pos
970 redef fun is_ok
do return curr_pos
<= max
972 redef fun item
do return target
[curr_pos
]
974 redef fun next
do curr_pos
+= 1
978 redef class NativeString
981 return to_s_with_length
(cstring_length
)
984 # Returns `self` as a String of `length`.
985 redef fun to_s_with_length
(length
): FlatString
988 return clean_utf8
(length
)
991 redef fun to_s_full
(bytelen
, unilen
) do
992 return new FlatString.full
(self, bytelen
, 0, bytelen
- 1, unilen
)
995 # Returns `self` as a new String.
996 redef fun to_s_with_copy
: FlatString
998 var length
= cstring_length
999 var r
= clean_utf8
(length
)
1000 if r
.items
!= self then return r
1001 var new_self
= new NativeString(length
+ 1)
1002 copy_to
(new_self
, length
, 0, 0)
1003 var str
= new FlatString.with_infos
(new_self
, length
, 0, length
- 1)
1004 new_self
[length
] = 0u8
1005 str
.real_items
= new_self
1009 # Cleans a NativeString if necessary
1010 fun clean_utf8
(len
: Int): FlatString do
1011 var replacements
: nullable Array[Int] = null
1012 var end_length
= len
1017 var nxst
= length_of_char_at
(pos
)
1020 ok_st
= b
& 0x80u
8 == 0u8
1021 else if nxst
== 2 then
1022 ok_st
= b
& 0xE0u
8 == 0xC0u
8
1023 else if nxst
== 3 then
1024 ok_st
= b
& 0xF0u
8 == 0xE0u
8
1026 ok_st
= b
& 0xF8u
8 == 0xF0u
8
1029 if replacements
== null then replacements
= new Array[Int]
1030 replacements
.add pos
1037 var c
= char_at
(pos
)
1038 var cp
= c
.code_point
1040 ok_c
= cp
>= 0 and cp
<= 0x7F
1041 else if nxst
== 2 then
1042 ok_c
= cp
>= 0x80 and cp
<= 0x7FF
1043 else if nxst
== 3 then
1044 ok_c
= cp
>= 0x800 and cp
<= 0xFFFF
1045 ok_c
= ok_c
and not (cp
>= 0xD800 and cp
<= 0xDFFF) and cp
!= 0xFFFE and cp
!= 0xFFFF
1047 ok_c
= cp
>= 0x10000 and cp
<= 0x10FFFF
1050 if replacements
== null then replacements
= new Array[Int]
1051 replacements
.add pos
1061 if end_length
!= len
then
1062 ret
= new NativeString(end_length
)
1065 var repls
= replacements
.as(not null)
1066 var r
= repls
.items
.as(not null)
1067 var imax
= repls
.length
1068 for i
in [0 .. imax
[ do
1070 var chkln
= repl_pos
- old_repl
1071 copy_to
(ret
, chkln
, old_repl
, off
)
1074 ret
[off
+ 1] = 0xBFu
8
1075 ret
[off
+ 2] = 0xBDu
8
1076 old_repl
= repl_pos
+ 1
1079 copy_to
(ret
, len
- old_repl
, old_repl
, off
)
1081 return new FlatString.full
(ret
, end_length
, 0, end_length
- 1, chr_ln
)
1084 # Sets the next bytes at position `pos` to the value of `c`, encoded in UTF-8
1086 # Very unsafe, make sure to have room for this char prior to calling this function.
1087 private fun set_char_at
(pos
: Int, c
: Char) do
1088 var ln
= c
.u8char_len
1089 native_set_char
(pos
, c
, ln
)
1092 private fun native_set_char
(pos
: Int, c
: Char, ln
: Int) `{
1093 char* dst = self + pos;
1099 dst[0] = 0xC0 | ((c & 0x7C0) >> 6);
1100 dst[1] = 0x80 | (c & 0x3F);
1103 dst[0] = 0xE0 | ((c & 0xF000) >> 12);
1104 dst[1] = 0x80 | ((c & 0xFC0) >> 6);
1105 dst[2] = 0x80 | (c & 0x3F);
1108 dst[0] = 0xF0 | ((c & 0x1C0000) >> 18);
1109 dst[1] = 0x80 | ((c & 0x3F000) >> 12);
1110 dst[2] = 0x80 | ((c & 0xFC0) >> 6);
1111 dst[3] = 0x80 | (c & 0x3F);
1118 redef fun to_base
(base
, signed
)
1120 var l
= digit_count
(base
)
1121 var s
= new FlatBuffer.from
(" " * l
)
1122 fill_buffer
(s
, base
, signed
)
1126 # return displayable int in base 10 and signed
1128 # assert 1.to_s == "1"
1129 # assert (-123).to_s == "-123"
1131 # Fast case for common numbers
1132 if self == 0 then return "0"
1133 if self == 1 then return "1"
1135 var nslen
= int_to_s_len
1136 var ns
= new NativeString(nslen
+ 1)
1138 native_int_to_s
(ns
, nslen
+ 1)
1139 return new FlatString.full
(ns
, nslen
, 0, nslen
- 1, nslen
)
1143 redef class Array[E
]
1145 # Fast implementation
1146 redef fun plain_to_s
1149 if l
== 0 then return ""
1150 if l
== 1 then if self[0] == null then return "" else return self[0].to_s
1152 var na
= new NativeArray[String](l
)
1158 if itsi
== null then
1168 var ns
= new NativeString(sl
+ 1)
1174 if tmp
isa FlatString then
1175 var tpl
= tmp
._bytelen
1176 tmp
._items
.copy_to
(ns
, tpl
, tmp
._first_byte
, off
)
1179 for j
in tmp
.substrings
do
1180 var s
= j
.as(FlatString)
1181 var slen
= s
._bytelen
1182 s
._items
.copy_to
(ns
, slen
, s
._first_byte
, off
)
1188 return new FlatString.with_infos
(ns
, sl
, 0, sl
- 1)
1192 redef class NativeArray[E
]
1193 redef fun native_to_s
do
1194 assert self isa NativeArray[String]
1205 var ns
= new NativeString(sl
+ 1)
1211 if tmp
isa FlatString then
1212 var tpl
= tmp
._bytelen
1213 tmp
._items
.copy_to
(ns
, tpl
, tmp
._first_byte
, off
)
1216 for j
in tmp
.substrings
do
1217 var s
= j
.as(FlatString)
1218 var slen
= s
._bytelen
1219 s
._items
.copy_to
(ns
, slen
, s
._first_byte
, off
)
1225 return new FlatString.with_infos
(ns
, sl
, 0, sl
- 1)
1229 redef class Map[K
,V
]
1230 redef fun join
(sep
, couple_sep
)
1232 if is_empty
then return ""
1234 var s
= new Buffer # Result
1240 s
.append
("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
1242 # Concat other _items
1248 s
.append
("{k or else "<null>"}{couple_sep}{e or else "<null>"}")