1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
4 # Copyright 2006-2008 Floréal Morandat <morandat@lirmm.fr>
6 # This file is free software, which comes along with NIT. This software is
7 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
10 # is kept unaltered, and a notification of the changes is added.
11 # You are allowed to redistribute it and sell it, alone or is a part of
14 # Basic manipulations of strings of characters
17 intrude import collection
# FIXME should be collection::array
20 ###############################################################################
22 ###############################################################################
24 # Common subclass for String and Buffer
25 abstract class AbstractString
26 super AbstractArrayRead[Char]
28 readable private var _items
: NativeString
30 redef fun [](index
) do return _items
[index
]
34 # "abcd".substring(1, 2) # --> "bc"
35 # "abcd".substring(-1, 2) # --> "a"
36 # "abcd".substring(1, 0) # --> ""
37 # "abcd".substring(2, 5) # --> "cd"
38 fun substring
(from
: Int, count
: Int): String
42 if from
< 0 then from
= 0
43 if count
> length
then count
= length
45 var r
= new Buffer.with_capacity
(count
- from
)
56 # Create a substring from `self' beginning at the 'from' position
58 # "abcd".substring(1) # --> "bcd"
59 # "abcd".substring(-1) # --> "abcd"
60 # "abcd".substring(2) # --> "cd"
61 fun substring_from
(from
: Int): String
64 return substring
(from
, length
- from
)
67 # Is `self' a substring of the `str' string from pos `pos'
69 # "bc".is_substring("abcd",1) # --> true
70 # "bc".is_substring("abcd",2) # --> false
71 fun has_substring
(str
: String, pos
: Int): Bool
73 var itsindex
= str
.length
- 1
74 var myindex
= pos
+ itsindex
76 var itsitems
= str
._items
77 if myindex
> length
or itsindex
> myindex
then return false
78 var its_index_from
= str
._indexFrom
79 itsindex
+= its_index_from
80 while itsindex
>= its_index_from
do
81 if myitems
[myindex
] != itsitems
[itsindex
] then return false
88 # Is this string prefixed by 'prefix'
90 # "abc".is_prefix("abcd") # --> true
91 # "bc".is_prefix("abcd") # --> false
92 fun has_prefix
(prefix
: String): Bool do return has_substring
(prefix
,0)
94 # Is this string suffixed by 'suffix'
96 # "abcd".has_suffix("abc") # --> false
97 # "abcd".has_suffix("bcd") # --> true
98 fun has_suffix
(suffix
: String): Bool do return has_substring
(suffix
, length
- suffix
.length
)
100 # If `self' contains only digits, return the corresponding integer
104 return to_s
.to_cstring
.atoi
107 # If `self' contains a float, return the corresponding float
111 return to_s
.to_cstring
.atof
114 # If `self' contains only digits and alpha <= 'f', return the corresponding integer.
115 fun to_hex
: Int do return a_to
(16)
117 # If `self' contains only digits and letters, return the corresponding integer in a given base
118 fun a_to
(base
: Int) : Int
145 # A upper case version of `self'
148 var s
= new Buffer.with_capacity
(length
)
149 for i
in self do s
.add
(i
.to_upper
)
153 # A lower case version of `self'
154 fun to_lower
: String
156 var s
= new Buffer.with_capacity
(length
)
157 for i
in self do s
.add
(i
.to_lower
)
172 # Immutable strings of characters.
178 redef type OTHER: String
180 readable var _indexFrom
: Int
181 readable var _indexTo
: Int
183 ################################################
184 # AbstractString specific methods #
185 ################################################
187 # Access a character at index in String
189 redef fun [](index
) do
191 assert (index
+ _indexFrom
) < (_indexFrom
+ _length
)
192 return items
[index
+ _indexFrom
]
195 # Create a substring.
197 # "abcd".substring(1, 2) # --> "bc"
198 # "abcd".substring(-1, 2) # --> "a"
199 # "abcd".substring(1, 0) # --> ""
200 # "abcd".substring(2, 5) # --> "cd"
201 redef fun substring
(from
: Int, count
: Int): String
207 if count
< 0 then count
= 0
211 var realFrom
= _indexFrom
+ from
213 if (realFrom
+ count
) > _indexTo
then return new String.from_substring
(realFrom
, _indexTo
, _items
)
215 if count
== 0 then return ""
217 return new String.from_substring
(realFrom
, realFrom
+ count
- 1, _items
)
220 # Create a substring from `self' beginning at the 'from' position
222 # "abcd".substring(1) # --> "bcd"
223 # "abcd".substring(-1) # --> "abcd"
224 # "abcd".substring(2) # --> "cd"
225 redef fun substring_from
(from
: Int): String
227 if from
> _length
then return ""
228 if from
< 0 then from
= 0
229 return substring
(from
, _length
)
232 # Is `self' a substring of the `str' string from pos `pos'
234 # "bc".is_substring("abcd",1) # --> true
235 # "bc".is_substring("abcd",2) # --> false
236 redef fun has_substring
(str
: String, pos
: Int): Bool
238 var itsindex
= str
._length
- 1
240 var myindex
= pos
+ itsindex
243 var itsitems
= str
._items
245 if myindex
> _length
or itsindex
> myindex
then return false
247 var itsindexfrom
= str
.indexFrom
248 itsindex
+= itsindexfrom
251 while itsindex
>= itsindexfrom
do
252 if myitems
[myindex
] != itsitems
[itsindex
] then return false
260 # A upper case version of `self'
261 redef fun to_upper
: String
263 var outstr
= calloc_string
(self._length
+ 1)
266 var myitems
= self._items
267 var index_from
= self._indexFrom
268 var max
= self._indexTo
270 while index_from
<= max
do
271 outstr
[index
] = myitems
[index_from
].to_upper
276 outstr
[self.length
] = '\0'
278 return new String.with_native
(outstr
, self._length
)
281 # A lower case version of `self'
282 redef fun to_lower
: String
284 var outstr
= calloc_string
(self._length
+ 1)
287 var myitems
= self._items
288 var index_from
= self._indexFrom
289 var max
= self._indexTo
291 while index_from
<= max
do
292 outstr
[index
] = myitems
[index_from
].to_lower
297 outstr
[self.length
] = '\0'
299 return new String.with_native
(outstr
, self._length
)
304 var i
= self._indexFrom
311 ##################################################
312 # String Specific Methods #
313 ##################################################
315 # Creates a String object as a substring of another String
316 private init from_substring
(from
: Int, to
: Int, internalString
: NativeString)
318 _items
= internalString
321 _length
= to
- from
+ 1
324 # Create a new string from a given char *.
325 init with_native
(nat
: NativeString, size
: Int)
334 # Create a new string from a null terminated char *.
335 init from_cstring
(str
: NativeString)
337 with_native
(str
,str
.cstring_length
)
340 # Return a null terminated char *
341 fun to_cstring
: NativeString
344 if _indexFrom
> 0 or _indexTo
!= items
.cstring_length-1
then
345 var newItems
= calloc_string
(length
+1)
346 self.items
.copy_to
(newItems
, _length
, _indexFrom
, 0)
347 newItems
[length
] = '\0'
355 if not o
isa String or o
is null then return false
357 if self.object_id
== o
.object_id
then return true
361 if o
._length
!= l
then return false
365 var max
= l
+ _indexFrom
366 var itsitems
= o
._items
367 var myitems
= self._items
370 if myitems
[i
] != itsitems
[j
] then return false
380 if self.object_id
== s
.object_id
then return false
384 var currIdSelf
= self._indexFrom
385 var currIdOther
= s
._indexFrom
386 var my_items
= self._items
387 var its_items
= s
._items
389 if self._length
< s
._length
then
391 else if self.length
> s
._length
then
395 var self_upper_bound
= self._length
+ currIdSelf
396 var other_upper_bound
= s
._length
+ currIdOther
398 while currIdSelf
< self_upper_bound
and currIdOther
< other_upper_bound
do
399 c1
= my_items
[currIdSelf
].ascii
400 c2
= its_items
[currIdOther
].ascii
415 # The concatenation of `self' with `r'
416 fun +(s
: String): String
418 var newString
= calloc_string
(_length
+ s
._length
+ 1)
420 self._items
.copy_to
(newString
, _length
, _indexFrom
, 0)
421 s
._items
.copy_to
(newString
, s
._length
, s
._indexFrom
, _length
)
423 newString
[self._length
+ s
._length
] = '\0'
425 return new String.with_native
(newString
, _length
+ s
._length
)
428 # i repetitions of self
429 fun *(i
: Int): String
432 var r
= calloc_string
((_length
* i
) + 1)
434 r
[_length
* i
] = '\0'
436 var lastStr
= new String.with_native
(r
, (_length
* i
))
439 self._items
.copy_to
(r
, _length
, _indexFrom
, _length
*(i-1
))
446 redef fun to_s
do return self
450 # djb2 hash algorythm
454 var myitems
= self.items
455 var index_from
= self._indexFrom
459 while i
>= index_from
do
460 h
= (h
* 32) + h
+ self._items
[i
].ascii
468 # Mutable strings of characters.
473 super AbstractArray[Char]
475 redef type OTHER: String
477 redef fun []=(index
, item
)
479 if index
== length
then
483 assert index
>= 0 and index
< length
489 if _capacity
<= length
then enlarge
(length
+ 5)
494 redef fun enlarge
(cap
)
497 if cap
<= c
then return
498 while c
<= cap
do c
= c
* 2 + 2
499 var a
= calloc_string
(c
+1)
500 _items
.copy_to
(a
, length
, 0, 0)
509 if _capacity
< _length
+ sl
then enlarge
(_length
+ sl
)
510 s
.items
.copy_to
(_items
, sl
, s
._indexFrom
, _length
)
517 redef fun to_s
: String
520 var a
= calloc_string
(l
+1)
521 _items
.copy_to
(a
, l
, 0, 0)
523 # Ensure the afterlast byte is '\0' to nul-terminated char *
526 return new String.with_native
(a
, length
)
534 while i
< l1
and i
< l2
do
535 var c1
= self[i
].ascii
551 # Create a new empty string.
559 _capacity
= s
.length
+ 1
561 _items
= calloc_string
(_capacity
)
562 s
.items
.copy_to
(_items
, _length
, s
._indexFrom
, 0)
565 # Create a new empty string with a given capacity.
566 init with_capacity
(cap
: Int)
569 # _items = new NativeString.calloc(cap)
570 _items
= calloc_string
(cap
+1)
577 if not o
isa Buffer or o
is null then return false
579 if o
.length
!= l
then return false
584 if it
[i
] != oit
[i
] then return false
590 readable private var _capacity
: Int
593 ###############################################################################
595 ###############################################################################
598 # User readable representation of `self'.
599 fun to_s
: String do return inspect
601 # The class name of the object in NativeString format.
602 private fun native_class_name
: NativeString is intern
604 # The class name of the object.
605 # FIXME: real type information is not available at runtime.
606 # Therefore, for instance, an instance of List[Bool] has just
607 # "List" for class_name
608 fun class_name
: String do return new String.from_cstring
(native_class_name
)
610 # Developer readable representation of `self'.
611 # Usually, it uses the form "<CLASSNAME:#OBJECTID bla bla bla>"
614 return "<{inspect_head}>"
617 # Return "CLASSNAME:#OBJECTID".
618 # This function is mainly used with the redefinition of the inspect method
619 protected fun inspect_head
: String
621 return "{class_name}:#{object_id.to_hex}"
624 protected fun args
: Sequence[String]
642 fun fill_buffer
(s
: Buffer, base
: Int, signed
: Bool)
643 # Fill `s' with the digits in base 'base' of `self' (and with the '-' sign if 'signed' and negative).
644 # assume < to_c max const of char
651 else if self == 0 then
658 var pos
= digit_count
(base
) - 1
659 while pos
>= 0 and n
> 0 do
660 s
[pos
] = (n
% base
).to_c
666 # return displayable int in base 10 and signed
667 redef fun to_s
do return to_base
(10,true)
669 # return displayable int in hexadecimal (unsigned (not now))
670 fun to_hex
: String do return to_base
(16,false)
672 # return displayable int in base base and signed
673 fun to_base
(base
: Int, signed
: Bool): String
675 var l
= digit_count
(base
)
676 var s
= new Buffer.from
(" " * l
)
677 fill_buffer
(s
, base
, signed
)
683 redef fun to_s
do return to_precision
(6)
685 # `self' representation with `nb' digits after the '.'.
686 fun to_precision
(nb
: Int): String
688 if nb
== 0 then return to_i
.to_s
696 var d
= ((self-i
.to_f
)*dec
).to_i
704 var s
= new Buffer.with_capacity
(1)
710 redef class Collection[E
]
711 # Concatenate elements.
715 for e
in self do if e
!= null then s
.append
(e
.to_s
)
719 # Concatenate and separate each elements with `sep'.
720 fun join
(sep
: String): String
722 if is_empty
then return ""
724 var s
= new Buffer # Result
729 if e
!= null then s
.append
(e
.to_s
)
736 if e
!= null then s
.append
(e
.to_s
)
744 # Fast implementation
752 if e
!= null then s
.append
(e
.to_s
)
760 # Concatenate couple of 'key value'.
761 # key and value are separated by 'couple_sep'.
762 # each couple is separated each couple with `sep'.
763 fun join
(sep
: String, couple_sep
: String): String
765 if is_empty
then return ""
767 var s
= new Buffer # Result
773 if e
!= null then s
.append
("{k}{couple_sep}{e}")
781 if e
!= null then s
.append
("{k}{couple_sep}{e}")
788 ###############################################################################
790 ###############################################################################
792 # Native strings are simple C char *
794 fun [](index
: Int): Char is intern
795 fun []=(index
: Int, item
: Char) is intern
796 fun copy_to
(dest
: NativeString, length
: Int, from
: Int, to
: Int) is intern
798 # Position of the first nul character.
799 fun cstring_length
: Int
802 while self[l
] != '\0' do l
+= 1
805 fun atoi
: Int is intern
806 fun atof
: Float is extern "atof"
809 # StringCapable objects can create native strings
810 interface StringCapable
811 protected fun calloc_string
(size
: Int): NativeString is intern
815 var _args_cache
: nullable Sequence[String]
817 redef fun args
: Sequence[String]
819 if _args_cache
== null then init_args
820 return _args_cache
.as(not null)
823 # The name of the program as given by the OS
824 fun program_name
: String
826 return new String.from_cstring
(native_argv
(0))
829 # Initialize `args' with the contents of `native_argc' and `native_argv'.
830 private fun init_args
832 var argc
= native_argc
833 var args
= new Array[String].with_capacity
(0)
836 args
[i-1
] = new String.from_cstring
(native_argv
(i
))
842 private fun native_argc
: Int is extern "kernel_Sys_Sys_native_argc_0" # First argument of the main C function.
844 private fun native_argv
(i
: Int): NativeString is extern "kernel_Sys_Sys_native_argv_1" # Second argument of the main C function.