core :: Concat :: defaultinit
# Node that represents a concatenation between two `String`
private class Concat
super Rope
super String
redef fun chars do return new RopeChars(self)
redef fun bytes do return new RopeBytes(self)
redef var length is noinit
redef var byte_length is noinit
redef fun substrings do return new RopeSubstrings.from(self, 0)
redef fun empty do return ""
# Cache for the latest accessed FlatString in `self`
var flat_cache: FlatString is noinit
# Position of the beginning of `flat_cache` in `self`
var flat_last_pos_start: Int is noinit
redef fun to_cstring do
var len = _byte_length
var ns = new CString(len + 1)
ns[len] = 0
var off = 0
for i in substrings do
var ilen = i._byte_length
i.as(FlatString)._items.copy_to(ns, ilen, i.as(FlatString)._first_byte, off)
off += ilen
end
return ns
end
# Left child of the node
var left: String
# Right child of the node
var right: String
init do
var l = _left
var r = _right
_length = l.length + r.length
_byte_length = l.byte_length + r.byte_length
_flat_last_pos_start = _length
end
redef fun is_empty do return _byte_length == 0
redef fun output do
_left.output
_right.output
end
redef fun iterator do return new RopeCharIterator.from(self, 0)
redef fun *(i) do
var x: String = self
for j in [1 .. i[ do x += self
return x
end
redef fun [](i) do
assert i >= 0 and i < _length
var flps = _flat_last_pos_start
if i >= flps then
var fc = _flat_cache
if i < flps + fc._length then return fc.fetch_char_at(i - flps)
end
var lf = get_leaf_at(i)
return lf.fetch_char_at(i - _flat_last_pos_start)
end
fun get_leaf_at(pos: Int): FlatString do
var flps = _flat_last_pos_start
if pos >= flps then
var fc = _flat_cache
if pos < flps + fc._length then return fc
end
var s: String = self
var st = pos
loop
if s isa FlatString then break
s = s.as(Concat)
var lft = s._left
var llen = lft.length
if pos >= llen then
s = s._right
pos -= llen
else
s = lft
end
end
_flat_last_pos_start = st - pos
_flat_cache = s
return s
end
redef fun substring(from, count) do
if from < 0 then
count += from
if count < 0 then return ""
from = 0
end
var ln = _length
if (count + from) > ln then count = ln - from
if count <= 0 then return ""
var end_index = from + count - 1
var flps = _flat_last_pos_start
if from >= flps then
var fc = _flat_cache
if end_index < flps + fc._length then
return fc.substring_impl(from - flps, count, end_index - flps)
end
end
var lft = _left
var llen = lft.length
if from < llen then
if from + count < llen then return lft.substring(from, count)
var lsublen = llen - from
return lft.substring_from(from) + _right.substring(0, count - lsublen)
else
return _right.substring(from - llen, count)
end
end
redef fun reversed do return new Concat(_right.reversed, _left.reversed)
redef fun insert_at(s, pos) do
var lft = _left
if pos > lft.length then
return lft + _right.insert_at(s, pos - lft.length)
end
return lft.insert_at(s, pos) + _right
end
redef fun to_upper do return new Concat(_left.to_upper, _right.to_upper)
redef fun to_lower do return new Concat(_left.to_lower, _right.to_lower)
redef fun +(o) do
var s = o.to_s
var slen = s.byte_length
if s isa Concat then
return new Concat(self, s)
else
var r = _right
var rlen = r.byte_length
if rlen + slen > maxlen then return new Concat(self, s)
return new Concat(_left, r + s)
end
end
redef fun copy_to_native(dest, n, src_offset, dest_offset) do
var l = _left
if src_offset < l.byte_length then
var lcopy = l.byte_length - src_offset
lcopy = if lcopy > n then n else lcopy
l.copy_to_native(dest, lcopy, src_offset, dest_offset)
dest_offset += lcopy
n -= lcopy
src_offset = 0
end
_right.copy_to_native(dest, n, src_offset, dest_offset)
end
# Returns a balanced version of `self`
fun balance: String do
var children = new Array[String]
var rnod: String
var iter: nullable RopeCharIteratorPiece = new RopeCharIteratorPiece(self, false, false, null)
loop
if iter == null then break
rnod = iter.node
if not rnod isa Concat then
children.push rnod
iter = iter.prev
continue
end
if not iter.ldone then
iter.ldone = true
iter = new RopeCharIteratorPiece(rnod._left, false, false, iter)
else if not iter.rdone then
iter.rdone = true
iter = new RopeCharIteratorPiece(rnod._right, false, false, iter)
else
iter = iter.prev
end
end
return recurse_balance(children, children.length)
end
fun recurse_balance(nodes: Array[String], len: Int): String do
var finpos = 0
var stpos = 0
while stpos < len do
if len - stpos > 1 then
nodes[finpos] = new Concat(nodes[stpos], nodes[stpos + 1])
stpos += 2
else
nodes[finpos] = nodes[stpos]
stpos += 1
end
finpos += 1
end
if finpos == 1 then return nodes[0]
return recurse_balance(nodes, finpos)
end
end
lib/core/text/ropes.nit:68,1--282,3