import math
import collection
+intrude import collection::array
`{
#include <stdio.h>
return self.chars.iterator
end
- # Is 'c' contained in self ?
- #
- # DEPRECATED : Use self.chars.has instead
- fun has(c: Char): Bool
- do
- return self.chars.has(c)
- end
# Gets an Array containing the chars of self
#
# As with substring, a `from` index < 0 will be replaced by 0
fun substring_from(from: Int): SELFTYPE
do
- if from > self.length then return empty
+ if from >= self.length then return empty
if from < 0 then from = 0
return substring(from, length - from)
end
var i = 0
var neg = false
- for c in self.chars
- do
+ for j in [0..length[ do
+ var c = chars[j]
var v = c.to_i
if v > base then
if neg then
fun is_numeric: Bool
do
var has_point_or_comma = false
- for i in self.chars
- do
- if not i.is_numeric
- then
- if (i == '.' or i == ',') and not has_point_or_comma
- then
+ for i in [0..length[ do
+ var c = chars[i]
+ if not c.is_numeric then
+ if (c == '.' or c == ',') and not has_point_or_comma then
has_point_or_comma = true
else
return false
# assert "0G".is_hex == false
fun is_hex: Bool
do
- for c in self.chars do
+ for i in [0..length[ do
+ var c = chars[i]
if not (c >= 'a' and c <= 'f') and
not (c >= 'A' and c <= 'F') and
not (c >= '0' and c <= '9') then return false
# assert "Hello World".is_upper == false
fun is_upper: Bool
do
- for char in self.chars do
+ for i in [0..length[ do
+ var char = chars[i]
if char.is_lower then return false
end
return true
# assert "Hello World".is_lower == false
fun is_lower: Bool
do
- for char in self.chars do
+ for i in [0..length[ do
+ var char = chars[i]
if char.is_upper then return false
end
return true
if iter.item.ascii > 32 then break
iter.next
end
- if iter.index == length then return self.empty
+ if iter.index < 0 then return self.empty
return self.substring(0, iter.index + 1)
end
do
var res = new FlatBuffer
var underscore = false
- for c in self.chars do
+ for i in [0..length[ do
+ var c = chars[i]
if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
res.add(c)
underscore = false
fun escape_to_c: String
do
var b = new FlatBuffer
- for c in self.chars do
+ for i in [0..length[ do
+ var c = chars[i]
if c == '\n' then
b.append("\\n")
else if c == '\0' then
do
var res = new FlatBuffer.with_capacity(self.length)
var was_slash = false
- for c in chars do
+ for i in [0..length[ do
+ var c = chars[i]
if not was_slash then
if c == '\\' then
was_slash = true
do
var buf = new FlatBuffer
- for c in self.chars do
+ for i in [0..length[ do
+ var c = chars[i]
if (c >= '0' and c <= '9') or
(c >= 'a' and c <= 'z') or
(c >= 'A' and c <= 'Z') or
end
end
+ # Escape string used in labels for graphviz
+ #
+ # assert ">><<".escape_to_dot == "\\>\\>\\<\\<"
+ fun escape_to_dot: String
+ do
+ return escape_more_to_c("|\{\}<>")
+ end
+
# Flat representation of self
fun flatten: FlatText is abstract
# djb2 hash algorithm
var h = 5381
- for char in self.chars do
+ for i in [0..length[ do
+ var char = chars[i]
h = h.lshift(5) + h + char.ascii
end
abstract class FlatText
super Text
- private var items: NativeString
+ # Underlying C-String (`char*`)
+ #
+ # Warning : Might be void in some subclasses, be sure to check
+ # if set before using it.
+ private var items: NativeString is noinit
# Real items, used as cache for to_cstring is called
private var real_items: nullable NativeString = null
var new_str = new FlatBuffer.with_capacity(self.length)
var is_first_char = true
- for char in self.chars do
+ for i in [0..length[ do
+ var char = chars[i]
if is_first_char then
new_str.add(char.to_lower)
is_first_char = false
var is_first_char = true
var follows_us = false
- for char in self.chars do
+ for i in [0..length[ do
+ var char = chars[i]
if is_first_char then
new_str.add(char)
is_first_char = false
return new_str.to_s
end
+
+ # Returns a capitalized `self`
+ #
+ # Letters that follow a letter are lowercased
+ # Letters that follow a non-letter are upcased.
+ #
+ # SEE : `Char::is_letter` for the definition of letter.
+ #
+ # assert "jAVASCRIPT".capitalized == "Javascript"
+ # assert "i am root".capitalized == "I Am Root"
+ # assert "ab_c -ab0c ab\nc".capitalized == "Ab_C -Ab0C Ab\nC"
+ fun capitalized: SELFTYPE do
+ if length == 0 then return self
+
+ var buf = new FlatBuffer.with_capacity(length)
+
+ var curr = chars[0].to_upper
+ var prev = curr
+ buf[0] = curr
+
+ for i in [1 .. length[ do
+ prev = curr
+ curr = self[i]
+ if prev.is_letter then
+ buf[i] = curr.to_lower
+ else
+ buf[i] = curr.to_upper
+ end
+ end
+
+ return buf.to_s
+ end
end
private class FlatSubstringsIter
super String
# Index in _items of the start of the string
- private var index_from: Int
+ private var index_from: Int is noinit
# Indes in _items of the last item of the string
- private var index_to: Int
+ private var index_to: Int is noinit
redef var chars: SequenceRead[Char] = new FlatStringCharView(self)
+ redef fun [](index)
+ do
+ # Check that the index (+ index_from) is not larger than indexTo
+ # In other terms, if the index is valid
+ assert index >= 0
+ assert (index + index_from) <= index_to
+ return items[index + index_from]
+ end
+
################################################
# AbstractString specific methods #
################################################
redef fun to_cstring: NativeString
do
- if real_items != null then return real_items.as(not null)
- if index_from > 0 or index_to != items.cstring_length - 1 then
+ if real_items != null then
+ return real_items.as(not null)
+ else
var newItems = calloc_string(length + 1)
self.items.copy_to(newItems, length, index_from, 0)
newItems[length] = '\0'
self.real_items = newItems
return newItems
end
- return items
end
redef fun ==(other)
s.items.copy_to(target_string, its_length, 0, my_length)
else
var curr_pos = my_length
- for i in s.chars do
- target_string[curr_pos] = i
+ for i in [0..s.length[ do
+ var c = s.chars[i]
+ target_string[curr_pos] = c
curr_pos += 1
end
end
curr_pos = pos + tgt.index_from
end
- redef fun is_ok do return curr_pos >= 0
+ redef fun is_ok do return curr_pos >= target.index_from
redef fun item do return target_items[curr_pos]
# Specific implementations MUST set this to `true` in order to invalidate caches
protected var is_dirty = true
+ # Copy-On-Write flag
+ #
+ # If the `Buffer` was to_s'd, the next in-place altering
+ # operation will cause the current `Buffer` to be re-allocated.
+ #
+ # The flag will then be set at `false`.
+ protected var written = false
+
# Modifies the char contained at pos `index`
#
# DEPRECATED : Use self.chars.[]= instead
# assert b == "hello world!"
fun lower is abstract
+ # Capitalizes each word in `self`
+ #
+ # Letters that follow a letter are lowercased
+ # Letters that follow a non-letter are upcased.
+ #
+ # SEE: `Char::is_letter` for the definition of a letter.
+ #
+ # var b = new FlatBuffer.from("jAVAsCriPt")"
+ # b.capitalize
+ # assert b == "Javascript"
+ # b = new FlatBuffer.from("i am root")
+ # b.capitalize
+ # assert b == "I Am Root"
+ # b = new FlatBuffer.from("ab_c -ab0c ab\nc")
+ # b.capitalize
+ # assert b == "Ab_C -Ab0C Ab\nC"
+ fun capitalize do
+ if length == 0 then return
+ var c = self[0].to_upper
+ self[0] = c
+ var prev: Char = c
+ for i in [1 .. length[ do
+ prev = c
+ c = self[i]
+ if prev.is_letter then
+ self[i] = c.to_lower
+ else
+ self[i] = c.to_upper
+ end
+ end
+ end
+
redef fun hash
do
if is_dirty then hash_cache = null
redef fun substrings do return new FlatSubstringsIter(self)
+ # Re-copies the `NativeString` into a new one and sets it as the new `Buffer`
+ #
+ # This happens when an operation modifies the current `Buffer` and
+ # the Copy-On-Write flag `written` is set at true.
+ private fun reset do
+ var nns = new NativeString(capacity)
+ items.copy_to(nns, length, 0, 0)
+ items = nns
+ written = false
+ end
+
+ redef fun [](index)
+ do
+ assert index >= 0
+ assert index < length
+ return items[index]
+ end
+
redef fun []=(index, item)
do
is_dirty = true
add(item)
return
end
+ if written then reset
assert index >= 0 and index < length
items[index] = item
end
redef fun clear do
is_dirty = true
+ if written then reset
length = 0
end
var c = capacity
if cap <= c then return
while c <= cap do c = c * 2 + 2
+ # The COW flag can be set at false here, since
+ # it does a copy of the current `Buffer`
+ written = false
var a = calloc_string(c+1)
if length > 0 then items.copy_to(a, length, 0, 0)
items = a
redef fun to_s: String
do
- return to_cstring.to_s_with_length(length)
+ written = true
+ if length == 0 then items = new NativeString(1)
+ return new FlatString.with_infos(items, length, 0, length - 1)
end
redef fun to_cstring
s.items.copy_to(items, length, 0, 0)
else
var curr_pos = 0
- for i in s.chars do
- items[curr_pos] = i
+ for i in [0..s.length[ do
+ var c = s.chars[i]
+ items[curr_pos] = c
curr_pos += 1
end
end
s.items.copy_to(items, sl, 0, length)
else
var curr_pos = self.length
- for i in s.chars do
- items[curr_pos] = i
+ for i in [0..s.length[ do
+ var c = s.chars[i]
+ items[curr_pos] = c
curr_pos += 1
end
end
redef fun reverse
do
+ written = false
var ns = calloc_string(capacity)
var si = length - 1
var ni = 0
redef fun upper
do
+ if written then reset
var it = items
var id = length - 1
while id >= 0 do
redef fun lower
do
+ if written then reset
var it = items
var id = length - 1
while id >= 0 do
end
redef class Array[E]
+
# Fast implementation
redef fun to_s
do
- var s = new FlatBuffer
- var i = 0
var l = length
+ if l == 0 then return ""
+ if l == 1 then if self[0] == null then return "" else return self[0].to_s
+ var its = _items
+ var na = new NativeArray[String](l)
+ var i = 0
+ var sl = 0
+ var mypos = 0
while i < l do
- var e = self[i]
- if e != null then s.append(e.to_s)
+ var itsi = its[i]
+ if itsi == null then
+ i += 1
+ continue
+ end
+ var tmp = itsi.to_s
+ sl += tmp.length
+ na[mypos] = tmp
i += 1
+ mypos += 1
end
- return s.to_s
+ var ns = new NativeString(sl + 1)
+ ns[sl] = '\0'
+ i = 0
+ var off = 0
+ while i < mypos do
+ var tmp = na[i]
+ var tpl = tmp.length
+ if tmp isa FlatString then
+ tmp.items.copy_to(ns, tpl, tmp.index_from, off)
+ off += tpl
+ else
+ for j in tmp.substrings do
+ var s = j.as(FlatString)
+ var slen = s.length
+ s.items.copy_to(ns, slen, s.index_from, off)
+ off += slen
+ end
+ end
+ i += 1
+ end
+ return ns.to_s_with_length(sl)
end
end
# Native strings are simple C char *
extern class NativeString `{ char* `}
super StringCapable
-
+ # Creates a new NativeString with a capacity of `length`
+ new(length: Int) is intern
fun [](index: Int): Char is intern
fun []=(index: Int, item: Char) is intern
fun copy_to(dest: NativeString, length: Int, from: Int, to: Int) is intern
fun to_s_with_length(length: Int): FlatString
do
assert length >= 0
- return new FlatString.with_infos(self, length, 0, length - 1)
+ var str = new FlatString.with_infos(self, length, 0, length - 1)
+ str.real_items = self
+ return str
end
fun to_s_with_copy: FlatString
var length = cstring_length
var new_self = calloc_string(length + 1)
copy_to(new_self, length, 0, 0)
- return new FlatString.with_infos(new_self, length, 0, length - 1)
+ var str = new FlatString.with_infos(new_self, length, 0, length - 1)
+ str.real_items = self
+ return str
end
end
end
redef class Sys
- var _args_cache: nullable Sequence[String]
+ private var args_cache: nullable Sequence[String]
# The arguments of the program as given by the OS
fun program_args: Sequence[String]