#
# assert " \n\thello \n\t".l_trim == "hello \n\t"
#
- # A whitespace is defined as any character which ascii value is less than or equal to 32
+ # `Char::is_whitespace` determines what is a whitespace.
fun l_trim: SELFTYPE
do
var iter = self.chars.iterator
while iter.is_ok do
- if iter.item.ascii > 32 then break
+ if not iter.item.is_whitespace then break
iter.next
end
if iter.index == length then return self.empty
#
# assert " \n\thello \n\t".r_trim == " \n\thello"
#
- # A whitespace is defined as any character which ascii value is less than or equal to 32
+ # `Char::is_whitespace` determines what is a whitespace.
fun r_trim: SELFTYPE
do
var iter = self.chars.reverse_iterator
while iter.is_ok do
- if iter.item.ascii > 32 then break
+ if not iter.item.is_whitespace then break
iter.next
end
if iter.index < 0 then return self.empty
end
# Trims trailing and preceding white spaces
- # A whitespace is defined as any character which ascii value is less than or equal to 32
#
# assert " Hello World ! ".trim == "Hello World !"
# assert "\na\nb\tc\t".trim == "a\nb\tc"
+ #
+ # `Char::is_whitespace` determines what is a whitespace.
fun trim: SELFTYPE do return (self.l_trim).r_trim
+ # Is the string non-empty but only made of whitespaces?
+ #
+ # assert " \n\t ".is_whitespace == true
+ # assert " hello ".is_whitespace == false
+ # assert "".is_whitespace == false
+ #
+ # `Char::is_whitespace` determines what is a whitespace.
+ fun is_whitespace: Bool
+ do
+ if is_empty then return false
+ for c in self.chars do
+ if not c.is_whitespace then return false
+ end
+ return true
+ end
+
# Returns `self` removed from its last line terminator (if any).
#
# assert "Hello\n".chomp == "Hello"
# assert "\r\n\r\n".chomp == "\r\n"
# assert "\r\n\r".chomp == "\r\n"
#
- # Note: unlike with most IO methods like `IStream::read_line`,
+ # Note: unlike with most IO methods like `Reader::read_line`,
# a single `\r` is considered here to be a line terminator and will be removed.
fun chomp: SELFTYPE
do
# REQUIRE: `left >= 0.0 and left <= 1.0`
# ENSURE: `self.length <= length implies result.length == length`
# ENSURE: `self.length >= length implies result == self`
- fun justify(length: Int, left: Float): SELFTYPE
+ fun justify(length: Int, left: Float): String
do
var diff = length - self.length
- if diff <= 0 then return self
+ if diff <= 0 then return to_s
assert left >= 0.0 and left <= 1.0
var before = (diff.to_f * left).to_i
return " " * before + self + " " * (diff-before)
# assert "a&b-<>\"x\"/'".html_escape == "a&b-<>"x"/'"
#
# SEE: <https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content>
- fun html_escape: SELFTYPE
+ fun html_escape: String
do
var buf = new FlatBuffer
abstract class String
super Text
- redef type SELFTYPE: String
+ redef type SELFTYPE: String is fixed
redef fun to_s do return self
# Indes in _items of the last item of the string
private var index_to: Int is noinit
- redef var chars: SequenceRead[Char] = new FlatStringCharView(self)
+ redef var chars: SequenceRead[Char] = new FlatStringCharView(self) is lazy
redef fun [](index)
do
from = 0
end
- var realFrom = index_from + from
+ var new_from = index_from + from
- if (realFrom + count) > index_to then return new FlatString.with_infos(items, index_to - realFrom + 1, realFrom, index_to)
+ if (new_from + count) > index_to then
+ var new_len = index_to - new_from + 1
+ if new_len <= 0 then return empty
+ return new FlatString.with_infos(items, new_len, new_from, index_to)
+ end
- if count == 0 then return empty
+ if count <= 0 then return empty
- var to = realFrom + count - 1
+ var to = new_from + count - 1
- return new FlatString.with_infos(items, to - realFrom + 1, realFrom, to)
+ return new FlatString.with_infos(items, to - new_from + 1, new_from, to)
end
redef fun empty do return "".as(FlatString)
# String Specific Methods #
##################################################
- private init with_infos(items: NativeString, len: Int, from: Int, to: Int)
+ # Low-level creation of a new string with given data.
+ #
+ # `items` will be used as is, without copy, to retrieve the characters of the string.
+ # Aliasing issues is the responsibility of the caller.
+ private init with_infos(items: NativeString, length: Int, from: Int, to: Int)
do
self.items = items
- length = len
+ self.length = length
index_from = from
index_to = to
end
abstract class Buffer
super Text
- redef type SELFTYPE: Buffer
+ redef type SELFTYPE: Buffer is fixed
# Specific implementations MUST set this to `true` in order to invalidate caches
protected var is_dirty = true
super FlatText
super Buffer
- redef type SELFTYPE: FlatBuffer
-
- redef var chars: Sequence[Char] = new FlatBufferCharView(self)
+ redef var chars: Sequence[Char] = new FlatBufferCharView(self) is lazy
private var capacity: Int = 0
# Create a new empty string.
init do end
+ # Low-level creation a new buffer with given data.
+ #
+ # `items` will be used as is, without copy, to store the characters of the buffer.
+ # Aliasing issues is the responsibility of the caller.
+ #
+ # If `items` is shared, `written` should be set to true after the creation
+ # so that a modification will do a copy-on-write.
+ private init with_infos(items: NativeString, capacity, length: Int)
+ do
+ self.items = items
+ self.length = length
+ self.capacity = capacity
+ end
+
# Create a new string copied from `s`.
init from(s: Text)
do
init with_capacity(cap: Int)
do
assert cap >= 0
- # _items = new NativeString.calloc(cap)
items = new NativeString(cap+1)
capacity = cap
length = 0
if from < 0 then from = 0
if count > length then count = length
if from < count then
- var r = new FlatBuffer.with_capacity(count - from)
- while from < count do
- r.chars.push(items[from])
- from += 1
- end
+ var len = count - from
+ var r_items = new NativeString(len)
+ items.copy_to(r_items, len, from, 0)
+ var r = new FlatBuffer.with_infos(r_items, len, len)
return r
else
return new FlatBuffer
end
end
+ # C function to calculate the length of the `NativeString` to receive `self`
+ private fun int_to_s_len: Int is extern "native_int_length_str"
+
# C function to convert an nit Int to a NativeString (char*)
- private fun native_int_to_s: NativeString is extern "native_int_to_s"
+ private fun native_int_to_s(nstr: NativeString, strlen: Int) is extern "native_int_to_s"
# return displayable int in base 10 and signed
#
# assert 1.to_s == "1"
# assert (-123).to_s == "-123"
redef fun to_s do
- return native_int_to_s.to_s
+ var nslen = int_to_s_len
+ var ns = new NativeString(nslen + 1)
+ ns[nslen] = '\0'
+ native_int_to_s(ns, nslen + 1)
+ return ns.to_s_with_length(nslen)
end
# return displayable int in hexadecimal
return p1 + "." + p2
end
-
- # `self` representation with `nb` digits after the '.'.
- #
- # assert 12.345.to_precision_native(1) == "12.3"
- # assert 12.345.to_precision_native(2) == "12.35"
- # assert 12.345.to_precision_native(3) == "12.345"
- # assert 12.345.to_precision_native(4) == "12.3450"
- fun to_precision_native(nb: Int): String import NativeString.to_s `{
- int size;
- char *str;
-
- size = snprintf(NULL, 0, "%.*f", (int)nb, recv);
- str = malloc(size + 1);
- sprintf(str, "%.*f", (int)nb, recv );
-
- return NativeString_to_s( str );
- `}
end
redef class Char
var i = iterator
var k = i.key
var e = i.item
- s.append("{k}{couple_sep}{e or else "<null>"}")
+ s.append("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
# Concat other items
i.next
s.append(sep)
k = i.key
e = i.item
- s.append("{k}{couple_sep}{e or else "<null>"}")
+ s.append("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
i.next
end
return s.to_s