X-Git-Url: http://nitlanguage.org diff --git a/lib/standard/string.nit b/lib/standard/string.nit index a9ebc63..a55e72a 100644 --- a/lib/standard/string.nit +++ b/lib/standard/string.nit @@ -20,88 +20,86 @@ intrude import array # String # ############################################################################### -# Strings are arrays of characters. -class String -special AbstractArray[Char] -special Comparable -special StringCapable - - redef type OTHER: String +abstract class AbstractString +special AbstractArrayRead[Char] + readable private attr _items: NativeString redef meth [](index) do return _items[index] - redef meth []=(index, item) + # Create a substring. + # + # "abcd".substring(1, 2) # --> "bc" + # "abcd".substring(-1, 2) # --> "a" + # "abcd".substring(1, 0) # --> "" + # "abcd".substring(2, 5) # --> "cd" + meth substring(from: Int, count: Int): String do - if index == length then - add(item) - return + assert count >= 0 + count += from + if from < 0 then from = 0 + if count > length then count = length + if from < count then + var r = new Buffer.with_capacity(count - from) + while from < count do + r.push(_items[from]) + from += 1 + end + return r.to_s + else + return "" end - assert index >= 0 and index < length - _items[index] = item - end - - redef meth add(c) - do - if _capacity <= length then enlarge(length + 5) - _items[length] = c - _length += 1 end - redef meth enlarge(cap) + # Create a substring with the string beginning at the 'from' position + # + # "abcd".substring(1) # --> "bcd" + # "abcd".substring(-1) # --> "abcd" + # "abcd".substring(2) # --> "cd" + meth substring_from(from: Int): String do - var c = _capacity - if cap <= c then return - while c <= cap do c = c * 2 + 2 - var a = calloc_string(c) - _items.copy_to(a, length, 0, 0) - _items = a - _capacity = c + assert from < length + return substring(from, length - from) end - redef meth append(s) + # is this string a substring of the 'of' string from pos 'pos' + # + # "bc".is_substring("abcd",1) # --> true + # "bc".is_substring("abcd",2) # --> false + meth has_substring(str: String, pos: Int): Bool do - if s isa String then - var sl = s.length - if _capacity < length + sl then enlarge(length + sl) - s.items.copy_to(_items, sl, 0, length) - _length += sl - else - super + var itsindex = str.length - 1 + var myindex = pos + itsindex + var myitems = _items + var itsitems = str._items + if myindex > length or itsindex > myindex then return false + while itsindex > 0 do + if myitems[myindex] != itsitems[itsindex] then return false + myindex -= myindex + itsindex -= itsindex end + return true end - # The concatenation of `self' with `r' - meth +(s: String): String - do - var r = new String.with_capacity(length + s.length) - r.append(self) - r.append(s) - return r - end - - # i repetitions of self - meth *(i: Int): String - do - assert i >= 0 - var r = new String.with_capacity(length * i) - while i > 0 do - r.append(self) - i -= 1 - end - return r - end + # Is this string prefixed by 'prefix' + # + # "abc".is_prefix("abcd") # --> true + # "bc".is_prefix("abcd") # --> false + meth has_prefix(prefix: String): Bool do return has_substring(prefix,0) - # Clone. - redef meth to_s: String do return new String.from(self) + # Is this string suffixed by 'suffix' + # + # "abcd".has_suffix("abc") # --> false + # "abcd".has_suffix("bcd") # --> true + meth has_suffix(suffix: String): Bool do return has_substring(suffix, length - suffix.length) # If `self' contains only digits, return the corresponding integer meth to_i: Int do # Shortcut - return to_cstring.atoi + return to_s.to_cstring.atoi end - # If `self' contains only digits and alpha <= 'f', return the corresponding integer. + # If `self' contains only digits and alpha <= 'f', return the corresponding integer. meth to_hex: Int do return a_to(16) # If `self' contains only digits and letters, return the corresponding integer in a given base @@ -109,7 +107,7 @@ special StringCapable do var i = 0 var neg = false - + for c in self do var v = c.to_i @@ -132,79 +130,184 @@ special StringCapable end end + # String to upper case + meth to_upper: String + do + var s = new Buffer.with_capacity(length) + for i in self do s.add(i.to_upper) + return s.to_s + end + + # String to lower case + meth to_lower : String + do + var s = new Buffer.with_capacity(length) + for i in self do s.add(i.to_lower) + return s.to_s + end + + + redef meth output + do + var i = 0 + while i < length do + _items[i].output + i += 1 + end + end +end + + +class String +special Comparable +special AbstractString + redef type OTHER: String + + # Create a new string from a given char *. + init with_native(nat: NativeString, size: Int) + do + assert size >= 0 + _items = nat + _length = size + end + + # Create a new string from a null terminated char *. + init from_cstring(str: NativeString) + do + var size = str.cstring_length + _items = str + _length = size + end + # Return a null terminated char * meth to_cstring: NativeString do - self[length] = '\0' - _length -= 1 return _items end - # Create a substring. - # - # "abcd".substring(1, 2) # --> "bc" - # "abcd".substring(-1, 2) # --> "a" - # "abcd".substring(1, 0) # --> "" - # "abcd".substring(2, 5) # --> "cd" - meth substring(from: Int, count: Int): String + redef meth ==(o) do - assert count >= 0 - count += from - if from < 0 then from = 0 - if count > length then count = length - if from < count then - var r = new String.with_capacity(count - from) - while from < count do - r.push(_items[from]) - from += 1 + if not o isa String or o is null then return false + var l = length + if o.length != l then return false + var i = 0 + var it = _items + var oit = o._items + while i < l do + if it[i] != oit[i] then return false + i += 1 + end + return true + end + + redef meth <(s) + do + var i = 0 + var l1 = length + var l2 = s.length + var n1 = _items + var n2 = s._items + while i < l1 and i < l2 do + var c1 = n1[i].ascii + var c2 = n2[i].ascii + if c1 < c2 then + return true + else if c2 < c1 then + return false end - return r + i += 1 + end + if l1 < l2 then + return true else - return "" + return false end end - # Create a substring with the string beginning at the 'from' position - # - # "abcd".substring(1) # --> "bcd" - # "abcd".substring(-1) # --> "abcd" - # "abcd".substring(2) # --> "cd" - meth substring_from(from: Int): String + # The concatenation of `self' with `r' + meth +(s: String): String do - assert from < length - return substring(from, length - from) + var r = new Buffer.with_capacity(length + s.length) + r.append(self) + r.append(s) + return r.to_s end - # is this string a substring of the 'of' string from pos 'pos' - # - # "bc".is_substring("abcd",1) # --> true - # "bc".is_substring("abcd",2) # --> false - meth has_substring(str: String, pos: Int): Bool + # i repetitions of self + meth *(i: Int): String do - var itsindex = str.length - 1 - var myindex = pos + itsindex - var myitems = _items - var itsitems = str._items - if myindex > length or itsindex > myindex then return false - while itsindex > 0 do - if myitems[myindex] != itsitems[itsindex] then return false - myindex -= myindex - itsindex -= itsindex + assert i >= 0 + var r = new Buffer.with_capacity(length * i) + while i > 0 do + r.append(self) + i -= 1 end - return true + return r.to_s end - # Is this string prefixed by 'prefix' - # - # "abc".is_prefix("abcd") # --> true - # "bc".is_prefix("abcd") # --> false - meth has_prefix(prefix: String): Bool do return has_substring(prefix,0) + redef meth to_s do return self +end - # Is this string suffixed by 'suffix' - # - # "abcd".has_suffix("abc") # --> false - # "abcd".has_suffix("bcd") # --> true - meth has_suffix(suffix: String): Bool do return has_substring(suffix, length - suffix.length) +# Strings are arrays of characters. +class Buffer +special AbstractString +special Comparable +special StringCapable +special AbstractArray[Char] + + redef type OTHER: String + + redef meth []=(index, item) + do + if index == length then + add(item) + return + end + assert index >= 0 and index < length + _items[index] = item + end + + redef meth add(c) + do + if _capacity <= length then enlarge(length + 5) + _items[length] = c + _length += 1 + end + + redef meth enlarge(cap) + do + var c = _capacity + if cap <= c then return + while c <= cap do c = c * 2 + 2 + var a = calloc_string(c+1) + _items.copy_to(a, length, 0, 0) + _items = a + _capacity = c + end + + redef meth append(s) + do + if s isa String then + var sl = s.length + if _capacity < length + sl then enlarge(length + sl) + s.items.copy_to(_items, sl, 0, length) + _length += sl + else + super + end + end + + redef meth to_s: String + do + var l = length + var a = calloc_string(l+1) + _items.copy_to(a, l, 0, 0) + + # Ensure the afterlast byte is '\0' to nul-terminated char * + a[length] = '\0' + + return new String.with_native(a, length) + end redef meth <(s) do @@ -247,54 +350,14 @@ special StringCapable do assert cap >= 0 # _items = new NativeString.calloc(cap) - _items = calloc_string(cap) + _items = calloc_string(cap+1) _capacity = cap _length = 0 end - # Create a new string from a given char *. - init with_native(nat: NativeString, size: Int) - do - assert size >= 0 - _items = nat - _capacity = size - _length = size - end - - # Create a new string from a null terminated char *. - init from_cstring(str: NativeString) - do - var size = str.cstring_length - _items = str - _capacity = size + 1 # Since there is a trailing \n - _length = size - end - - # Create a string of `count' chararter `c' - init filled_with(c: Char, count: Int) - do - with_capacity(count) - var i = 0 - while i < count do - _items[i] = c - i += 1 - end - _length = count - end - - redef meth output - do - var i = 0 - while i < length do - _items[i].output - i += 1 - end - end - redef meth ==(o) do - if not o isa String or o is null then return false - assert o isa String + if not o isa Buffer or o is null then return false var l = length if o.length != l then return false var i = 0 @@ -307,23 +370,6 @@ special StringCapable return true end - # String to upper case - meth to_upper: String - do - var s = new String.with_capacity(length) - for i in self do s.add(i.to_upper) - return s - end - - # String to lower case - meth to_lower : String - do - var s = new String.with_capacity(length) - for i in self do s.add(i.to_lower) - return s - end - - readable private attr _items: NativeString readable private attr _capacity: Int end @@ -342,7 +388,7 @@ redef class Object meth inspect: String do var r = inspect_head - r.add('>') + # r.add('>') return r end @@ -371,7 +417,7 @@ redef class Bool end redef class Int - meth fill_string(s: String, base: Int, signed: Bool) + meth fill_buffer(s: Buffer, base: Int, signed: Bool) # Fill `s' with the digits in base 'base' of `self' (and with the '-' sign if 'signed' and negative). # assume < to_c max const of char do @@ -405,9 +451,9 @@ redef class Int meth to_base(base: Int, signed: Bool): String do var l = digit_count(base) - var s = new String.filled_with(' ', l) - fill_string(s, base, signed) - return s + var s = new Buffer.from(" " * l) + fill_buffer(s, base, signed) + return s.to_s end end @@ -433,9 +479,9 @@ end redef class Char redef meth to_s do - var s = new String.with_capacity(1) + var s = new Buffer.with_capacity(1) s[0] = self - return s + return s.to_s end end @@ -443,9 +489,9 @@ redef class Collection[E] # Concatenate elements. redef meth to_s do - var s = new String + var s = new Buffer for e in self do if e != null then s.append(e.to_s) - return s + return s.to_s end # Concatenate and separate each elements with `sep'. @@ -453,7 +499,7 @@ redef class Collection[E] do if is_empty then return "" - var s = new String # Result + var s = new Buffer # Result # Concat first item var i = iterator @@ -468,7 +514,23 @@ redef class Collection[E] if e != null then s.append(e.to_s) i.next end - return s + return s.to_s + end +end + +redef class Array[E] + # Fast implementation + redef meth to_s + do + var s = new Buffer + var i = 0 + var l = length + while i < l do + var e = self[i] + if e != null then s.append(e.to_s) + i += 1 + end + return s.to_s end end @@ -478,7 +540,7 @@ redef class Map[K,V] do if is_empty then return "" - var s = new String # Result + var s = new Buffer # Result # Concat first item var i = iterator @@ -495,7 +557,7 @@ redef class Map[K,V] if e != null then s.append("{k}{couple_sep}{e}") i.next end - return s + return s.to_s end end @@ -525,14 +587,14 @@ class StringCapable end redef class Sys - attr _args_cache: IndexedCollection[String] + attr _args_cache: nullable IndexedCollection[String] redef meth args: IndexedCollection[String] do if _args_cache == null then init_args - return _args_cache + return _args_cache.as(not null) end - + # The name of the program as given by the OS meth program_name: String do