X-Git-Url: http://nitlanguage.org diff --git a/lib/standard/string.nit b/lib/standard/string.nit index a9ebc63..d61b260 100644 --- a/lib/standard/string.nit +++ b/lib/standard/string.nit @@ -14,102 +14,101 @@ # This module is about character strings. package string -intrude import array +intrude import collection # FIXME should be collection::array +import hash ############################################################################### # String # ############################################################################### -# Strings are arrays of characters. -class String -special AbstractArray[Char] -special Comparable -special StringCapable - - redef type OTHER: String +abstract class AbstractString + super AbstractArrayRead[Char] + readable private var _items: NativeString - redef meth [](index) do return _items[index] + redef fun [](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" + fun 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" + fun 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 + fun 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 -= 1 + itsindex -= 1 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 + fun 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 + fun 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 + fun 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. - meth to_hex: Int do return a_to(16) + # If `self' contains only digits and alpha <= 'f', return the corresponding integer. + fun to_hex: Int do return a_to(16) # If `self' contains only digits and letters, return the corresponding integer in a given base - meth a_to(base: Int) : Int + fun a_to(base: Int) : Int do var i = 0 var neg = false - + for c in self do var v = c.to_i @@ -132,81 +131,200 @@ special StringCapable end end + # String to upper case + fun 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 + fun 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 fun output + do + var i = 0 + while i < length do + _items[i].output + i += 1 + end + end +end + + +class String + super Comparable + super 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 + fun 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 fun ==(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 fun <(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' + fun +(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 + fun *(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 fun to_s do return 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) + redef fun hash + do + # djb2 hash algorythm + var h = 5381 + var i = _length - 1 + var it = _items + while i >= 0 do + h = (h * 32) + h + it[i].ascii + i -= 1 + end + return h + + end +end + +# Strings are arrays of characters. +class Buffer + super AbstractString + super Comparable + super StringCapable + super AbstractArray[Char] - redef meth <(s) + redef type OTHER: String + + redef fun []=(index, item) + do + if index == length then + add(item) + return + end + assert index >= 0 and index < length + _items[index] = item + end + + redef fun add(c) + do + if _capacity <= length then enlarge(length + 5) + _items[length] = c + _length += 1 + end + + redef fun 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 fun 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 fun 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 fun <(s) do var i = 0 var l1 = length @@ -247,54 +365,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) + redef fun ==(o) 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,24 +385,7 @@ 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 + readable private var _capacity: Int end ############################################################################### @@ -332,35 +393,35 @@ end ############################################################################### redef class Object - # meth class_name: String is extern intern # The name of the class + # fun class_name: String is extern intern # The name of the class # User redeable representation of `self'. - meth to_s: String do return inspect + fun to_s: String do return inspect # Developper readable representation of `self'. # Usualy, it uses the form "" - meth inspect: String + fun inspect: String do var r = inspect_head - r.add('>') + # r.add('>') return r end # Return "