66e7734c82f43ac148dee95b4caad4cff7224a24
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
21 private class FlatSubstringsIter
22 super Iterator[FlatText]
24 var tgt
: nullable FlatText
28 return tgt
.as(not null)
31 redef fun is_ok
do return tgt
!= null
33 redef fun next
do tgt
= null
36 # Immutable strings of characters.
41 # Index in _items of the start of the string
42 private var index_from
: Int is noinit
44 # Indes in _items of the last item of the string
45 private var index_to
: Int is noinit
47 redef var chars
= new FlatStringCharView(self) is lazy
49 redef var bytes
= new FlatStringByteView(self) is lazy
53 # Check that the index (+ index_from) is not larger than indexTo
54 # In other terms, if the index is valid
56 assert (index
+ index_from
) <= index_to
57 return items
[index
+ index_from
].to_i
.ascii
60 ################################################
61 # AbstractString specific methods #
62 ################################################
66 var b
= new FlatBuffer.with_capacity
(bytelen
+ 1)
67 for i
in [length
- 1 .. 0].step
(-1) do
70 var s
= b
.to_s
.as(FlatString)
71 s
.length
= self.length
75 redef fun fast_cstring
do return items
.fast_cstring
(index_from
)
77 redef fun substring
(from
, count
)
83 if count
< 0 then count
= 0
87 var new_from
= index_from
+ from
89 if (new_from
+ count
) > index_to
then
90 var new_len
= index_to
- new_from
+ 1
91 if new_len
<= 0 then return empty
92 return new FlatString.with_infos
(items
, new_len
, new_from
, index_to
)
95 if count
<= 0 then return empty
97 var to
= new_from
+ count
- 1
99 return new FlatString.with_infos
(items
, to
- new_from
+ 1, new_from
, to
)
102 redef fun empty
do return "".as(FlatString)
106 var outstr
= new FlatBuffer.with_capacity
(self.bytelen
+ 1)
112 outstr
.add
(chars
[pos
].to_upper
)
121 var outstr
= new FlatBuffer.with_capacity
(self.bytelen
+ 1)
127 outstr
.add
(chars
[pos
].to_lower
)
136 for i
in chars
do i
.output
139 ##################################################
140 # String Specific Methods #
141 ##################################################
143 # Low-level creation of a new string with given data.
145 # `items` will be used as is, without copy, to retrieve the characters of the string.
146 # Aliasing issues is the responsibility of the caller.
147 private init with_infos
(items
: NativeString, length
: Int, from
: Int, to
: Int)
157 if real_items
!= null then
158 return real_items
.as(not null)
160 var newItems
= new NativeString(length
+ 1)
161 self.items
.copy_to
(newItems
, length
, index_from
, 0)
162 newItems
[length
] = 0u8
163 self.real_items
= newItems
170 if not other
isa FlatString then return super
172 if self.object_id
== other
.object_id
then return true
174 var my_length
= length
176 if other
.length
!= my_length
then return false
178 var my_index
= index_from
179 var its_index
= other
.index_from
181 var last_iteration
= my_index
+ my_length
183 var itsitems
= other
.items
184 var myitems
= self.items
186 while my_index
< last_iteration
do
187 if myitems
[my_index
] != itsitems
[its_index
] then return false
197 if not other
isa FlatString then return super
199 if self.object_id
== other
.object_id
then return false
201 var my_curr_char
: Char
202 var its_curr_char
: Char
204 var my_length
= self.length
205 var its_length
= other
.length
208 if my_length
< its_length
then
215 var its_chars
= other
.chars
219 my_curr_char
= my_chars
[pos
]
220 its_curr_char
= its_chars
[pos
]
222 if my_curr_char
!= its_curr_char
then
223 if my_curr_char
< its_curr_char
then return true
230 return my_length
< its_length
237 var nlen
= mlen
+ slen
239 var mifrom
= first_byte
240 if s
isa FlatText then
242 var sifrom
= s
.as(FlatString).first_byte
243 var ns
= new NativeString(nlen
+ 1)
244 mits
.copy_to
(ns
, mlen
, mifrom
, 0)
245 sits
.copy_to
(ns
, slen
, sifrom
, mlen
)
246 return ns
.to_s_with_length
(nlen
)
253 var mybtlen
= bytelen
254 var new_bytelen
= mybtlen
* i
256 var newlen
= mylen
* i
257 var ns
= new NativeString(new_bytelen
+ 1)
258 ns
[new_bytelen
] = 0u8
261 items
.copy_to
(ns
, bytelen
, first_byte
, offset
)
265 return new FlatString.full
(ns
, new_bytelen
, 0, new_bytelen
- 1, newlen
)
270 if hash_cache
== null then
271 # djb2 hash algorithm
277 while i
<= index_to
do
278 h
= h
.lshift
(5) + h
+ myitems
[i
].to_i
285 return hash_cache
.as(not null)
288 redef fun substrings
do return new FlatSubstringsIter(self)
291 private class FlatStringCharReverseIterator
292 super IndexedIterator[Char]
294 var target
: FlatString
298 init with_pos
(tgt
: FlatString, pos
: Int)
303 redef fun is_ok
do return curr_pos
>= 0
305 redef fun item
do return target
[curr_pos
]
307 redef fun next
do curr_pos
-= 1
309 redef fun index
do return curr_pos
313 private class FlatStringCharIterator
314 super IndexedIterator[Char]
316 var target
: FlatString
322 init with_pos
(tgt
: FlatString, pos
: Int)
324 init(tgt
, tgt
.length
- 1, pos
)
327 redef fun is_ok
do return curr_pos
<= max
329 redef fun item
do return target
[curr_pos
]
331 redef fun next
do curr_pos
+= 1
333 redef fun index
do return curr_pos
337 private class FlatStringCharView
340 redef type SELFTYPE: FlatString
342 redef fun [](index
) do return target
[index
]
344 redef fun iterator_from
(start
) do return new FlatStringCharIterator.with_pos
(target
, start
)
346 redef fun reverse_iterator_from
(start
) do return new FlatStringCharReverseIterator.with_pos
(target
, start
)
350 private class FlatStringByteReverseIterator
351 super IndexedIterator[Byte]
353 var target
: FlatString
355 var target_items
: NativeString
359 init with_pos
(tgt
: FlatString, pos
: Int)
361 init(tgt
, tgt
.items
, pos
+ tgt
.index_from
)
364 redef fun is_ok
do return curr_pos
>= target
.index_from
366 redef fun item
do return target_items
[curr_pos
]
368 redef fun next
do curr_pos
-= 1
370 redef fun index
do return curr_pos
- target
.index_from
374 private class FlatStringByteIterator
375 super IndexedIterator[Byte]
377 var target
: FlatString
379 var target_items
: NativeString
383 init with_pos
(tgt
: FlatString, pos
: Int)
385 init(tgt
, tgt
.items
, pos
+ tgt
.index_from
)
388 redef fun is_ok
do return curr_pos
<= target
.index_to
390 redef fun item
do return target_items
[curr_pos
]
392 redef fun next
do curr_pos
+= 1
394 redef fun index
do return curr_pos
- target
.index_from
398 private class FlatStringByteView
401 redef type SELFTYPE: FlatString
405 # Check that the index (+ index_from) is not larger than indexTo
406 # In other terms, if the index is valid
408 var target
= self.target
409 assert (index
+ target
.index_from
) <= target
.index_to
410 return target
.items
[index
+ target
.index_from
]
413 redef fun iterator_from
(start
) do return new FlatStringByteIterator.with_pos
(target
, start
)
415 redef fun reverse_iterator_from
(start
) do return new FlatStringByteReverseIterator.with_pos
(target
, start
)
420 redef new do return new FlatBuffer
422 redef new with_cap
(i
) do return new FlatBuffer.with_capacity
(i
)
425 # Mutable strings of characters.
430 redef var chars
: Sequence[Char] = new FlatBufferCharView(self) is lazy
432 redef var bytes
: Sequence[Byte] = new FlatBufferByteView(self) is lazy
434 private var capacity
: Int = 0
436 redef fun fast_cstring
do return items
.fast_cstring
(0)
438 redef fun substrings
do return new FlatSubstringsIter(self)
440 # Re-copies the `NativeString` into a new one and sets it as the new `Buffer`
442 # This happens when an operation modifies the current `Buffer` and
443 # the Copy-On-Write flag `written` is set at true.
445 var nns
= new NativeString(capacity
)
446 items
.copy_to
(nns
, length
, 0, 0)
454 assert index
< length
455 return items
[index
].to_i
.ascii
458 redef fun []=(index
, item
)
461 if index
== length
then
465 if written
then reset
466 assert index
>= 0 and index
< length
467 items
[index
] = item
.ascii
.to_b
473 if capacity
<= length
then enlarge
(length
+ 5)
474 items
[length
] = c
.ascii
.to_b
478 private fun add_byte
(b
: Byte) do
480 if capacity
<= length
then enlarge
(length
+ 5)
487 if written
then reset
491 redef fun empty
do return new Buffer
493 redef fun enlarge
(cap
)
496 if cap
<= c
then return
497 while c
<= cap
do c
= c
* 2 + 2
498 # The COW flag can be set at false here, since
499 # it does a copy of the current `Buffer`
501 var a
= new NativeString(c
+1)
502 if length
> 0 then items
.copy_to
(a
, length
, 0, 0)
510 if length
== 0 then items
= new NativeString(1)
511 return new FlatString.with_infos
(items
, length
, 0, length
- 1)
517 var new_native
= new NativeString(length
+ 1)
518 new_native
[length
] = 0u8
519 if length
> 0 then items
.copy_to
(new_native
, length
, 0, 0)
520 real_items
= new_native
523 return real_items
.as(not null)
526 # Create a new empty string.
529 # Low-level creation a new buffer with given data.
531 # `items` will be used as is, without copy, to store the characters of the buffer.
532 # Aliasing issues is the responsibility of the caller.
534 # If `items` is shared, `written` should be set to true after the creation
535 # so that a modification will do a copy-on-write.
536 private init with_infos
(items
: NativeString, capacity
, length
: Int)
540 self.capacity
= capacity
543 # Create a new string copied from `s`.
546 capacity
= s
.length
+ 1
548 items
= new NativeString(capacity
)
549 if s
isa FlatString then
550 s
.items
.copy_to
(items
, length
, s
.index_from
, 0)
551 else if s
isa FlatBuffer then
552 s
.items
.copy_to
(items
, length
, 0, 0)
562 # Create a new empty string with a given capacity.
563 init with_capacity
(cap
: Int)
566 items
= new NativeString(cap
+1)
573 if s
.is_empty
then return
576 if capacity
< length
+ sl
then enlarge
(length
+ sl
)
577 if s
isa FlatString then
578 s
.items
.copy_to
(items
, sl
, s
.index_from
, length
)
579 else if s
isa FlatBuffer then
580 s
.items
.copy_to
(items
, sl
, 0, length
)
582 var curr_pos
= self.length
591 # Copies the content of self in `dest`
592 fun copy
(start
: Int, len
: Int, dest
: Buffer, new_start
: Int)
594 var self_chars
= self.chars
595 var dest_chars
= dest
.chars
596 for i
in [0..len-1
] do
597 dest_chars
[new_start
+i
] = self_chars
[start
+i
]
601 redef fun substring
(from
, count
)
605 if from
< 0 then from
= 0
606 if count
> length
then count
= length
608 var len
= count
- from
609 var r_items
= new NativeString(len
)
610 items
.copy_to
(r_items
, len
, from
, 0)
611 var r
= new FlatBuffer.with_infos
(r_items
, len
, len
)
621 var ns
= new NativeString(capacity
)
633 redef fun times
(repeats
)
635 var x
= new FlatString.with_infos
(items
, length
, 0, length
- 1)
636 for i
in [1..repeats
[ do
643 if written
then reset
646 self[id
] = self[id
].to_upper
653 if written
then reset
656 self[id
] = self[id
].to_lower
662 private class FlatBufferByteReverseIterator
663 super IndexedIterator[Byte]
665 var target
: FlatBuffer
667 var target_items
: NativeString
671 init with_pos
(tgt
: FlatBuffer, pos
: Int)
673 init(tgt
, tgt
.items
, pos
)
676 redef fun index
do return curr_pos
678 redef fun is_ok
do return curr_pos
>= 0
680 redef fun item
do return target_items
[curr_pos
]
682 redef fun next
do curr_pos
-= 1
686 private class FlatBufferByteView
689 redef type SELFTYPE: FlatBuffer
691 redef fun [](index
) do return target
.items
[index
]
693 redef fun []=(index
, item
)
695 assert index
>= 0 and index
<= target
.bytelen
696 if index
== target
.bytelen
then
700 target
.items
[index
] = item
708 fun enlarge
(cap
: Int)
715 var s_length
= s
.length
716 if target
.capacity
< (target
.length
+ s_length
) then enlarge
(s_length
+ target
.length
)
717 var pos
= target
.length
718 var its
= target
.items
723 target
.length
+= s
.length
726 redef fun iterator_from
(pos
) do return new FlatBufferByteIterator.with_pos
(target
, pos
)
728 redef fun reverse_iterator_from
(pos
) do return new FlatBufferByteReverseIterator.with_pos
(target
, pos
)
732 private class FlatBufferByteIterator
733 super IndexedIterator[Byte]
735 var target
: FlatBuffer
737 var target_items
: NativeString
741 init with_pos
(tgt
: FlatBuffer, pos
: Int)
743 init(tgt
, tgt
.items
, pos
)
746 redef fun index
do return curr_pos
748 redef fun is_ok
do return curr_pos
< target
.length
750 redef fun item
do return target_items
[curr_pos
]
752 redef fun next
do curr_pos
+= 1
756 private class FlatBufferCharReverseIterator
757 super IndexedIterator[Char]
759 var target
: FlatBuffer
763 init with_pos
(tgt
: FlatBuffer, pos
: Int)
768 redef fun index
do return curr_pos
770 redef fun is_ok
do return curr_pos
>= 0
772 redef fun item
do return target
[curr_pos
]
774 redef fun next
do curr_pos
-= 1
778 private class FlatBufferCharView
781 redef type SELFTYPE: FlatBuffer
783 redef fun [](index
) do return target
[index
]
785 redef fun []=(index
, item
)
787 assert index
>= 0 and index
<= length
788 if index
== length
then
805 fun enlarge
(cap
: Int)
812 var s_length
= s
.length
813 if target
.capacity
< s
.length
then enlarge
(s_length
+ target
.length
)
814 for i
in s
do target
.add i
817 redef fun iterator_from
(pos
) do return new FlatBufferCharIterator.with_pos
(target
, pos
)
819 redef fun reverse_iterator_from
(pos
) do return new FlatBufferCharReverseIterator.with_pos
(target
, pos
)
823 private class FlatBufferCharIterator
824 super IndexedIterator[Char]
826 var target
: FlatBuffer
832 init with_pos
(tgt
: FlatBuffer, pos
: Int)
834 init(tgt
, tgt
.length
- 1, pos
)
837 redef fun index
do return curr_pos
839 redef fun is_ok
do return curr_pos
<= max
841 redef fun item
do return target
[curr_pos
]
843 redef fun next
do curr_pos
+= 1
847 redef class NativeString
850 return to_s_with_length
(cstring_length
)
853 # Returns `self` as a String of `length`.
854 redef fun to_s_with_length
(length
): FlatString
857 var str
= new FlatString.with_infos
(self, length
, 0, length
- 1)
861 # Returns `self` as a new String.
862 redef fun to_s_with_copy
: FlatString
864 var length
= cstring_length
865 var new_self
= new NativeString(length
+ 1)
866 copy_to
(new_self
, length
, 0, 0)
867 var str
= new FlatString.with_infos
(new_self
, length
, 0, length
- 1)
868 new_self
[length
] = 0u8
869 str
.real_items
= new_self
873 # Sets the next bytes at position `pos` to the value of `c`, encoded in UTF-8
875 # Very unsafe, make sure to have room for this char prior to calling this function.
876 private fun set_char_at
(pos
: Int, c
: Char) do
877 var ln
= c
.u8char_len
878 native_set_char
(pos
, c
, ln
)
881 private fun native_set_char
(pos
: Int, c
: Char, ln
: Int) `{
882 char* dst = self + pos;
888 dst[0] = 0xC0 | ((c & 0x7C0) >> 6);
889 dst[1] = 0x80 | (c & 0x3F);
892 dst[0] = 0xE0 | ((c & 0xF000) >> 12);
893 dst[1] = 0x80 | ((c & 0xFC0) >> 6);
894 dst[2] = 0x80 | (c & 0x3F);
897 dst[0] = 0xF0 | ((c & 0x1C0000) >> 18);
898 dst[1] = 0x80 | ((c & 0x3F000) >> 12);
899 dst[2] = 0x80 | ((c & 0xFC0) >> 6);
900 dst[3] = 0x80 | (c & 0x3F);
907 redef fun to_base
(base
, signed
)
909 var l
= digit_count
(base
)
910 var s
= new FlatBuffer.from
(" " * l
)
911 fill_buffer
(s
, base
, signed
)
915 # return displayable int in base 10 and signed
917 # assert 1.to_s == "1"
918 # assert (-123).to_s == "-123"
920 # Fast case for common numbers
921 if self == 0 then return "0"
922 if self == 1 then return "1"
924 var nslen
= int_to_s_len
925 var ns
= new NativeString(nslen
+ 1)
927 native_int_to_s
(ns
, nslen
+ 1)
928 return ns
.to_s_with_length
(nslen
)
934 # Fast implementation
938 if l
== 0 then return ""
939 if l
== 1 then if self[0] == null then return "" else return self[0].to_s
941 var na
= new NativeArray[String](l
)
957 var ns
= new NativeString(sl
+ 1)
964 if tmp
isa FlatString then
965 tmp
.items
.copy_to
(ns
, tpl
, tmp
.index_from
, off
)
968 for j
in tmp
.substrings
do
969 var s
= j
.as(FlatString)
971 s
.items
.copy_to
(ns
, slen
, s
.index_from
, off
)
977 return ns
.to_s_with_length
(sl
)
981 redef class NativeArray[E
]
982 redef fun native_to_s
do
983 assert self isa NativeArray[String]
994 var ns
= new NativeString(sl
+ 1)
1000 var tpl
= tmp
.length
1001 if tmp
isa FlatString then
1002 tmp
.items
.copy_to
(ns
, tpl
, tmp
.index_from
, off
)
1005 for j
in tmp
.substrings
do
1006 var s
= j
.as(FlatString)
1008 s
.items
.copy_to
(ns
, slen
, s
.index_from
, off
)
1014 return ns
.to_s_with_length
(sl
)
1018 redef class Map[K
,V
]
1019 redef fun join
(sep
, couple_sep
)
1021 if is_empty
then return ""
1023 var s
= new Buffer # Result
1029 s
.append
("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
1031 # Concat other items
1037 s
.append
("{k or else "<null>"}{couple_sep}{e or else "<null>"}")