redef fun empty do return ""
+ # Cache for the latest accessed FlatString in `self`
+ var flat_cache: String = ""
+
+ # Position of the beginning of `flat_cache` in `self`
+ var flat_last_pos_start: Int = -1
+
redef var to_cstring is lazy do
var len = bytelen
var ns = new NativeString(len + 1)
end
redef fun [](i) do
- var llen = left.length
- if i >= llen then return right[i - llen]
- return left[i]
+ if flat_last_pos_start != -1 then
+ var fsp = i - flat_last_pos_start
+ if fsp >= 0 and fsp < flat_cache.length then return flat_cache[fsp]
+ end
+ var s: String = self
+ var st = i
+ loop
+ if s isa FlatString then break
+ s = s.as(Concat)
+ var lft = s.left
+ var llen = lft.length
+ if i >= llen then
+ s = s.right
+ i -= llen
+ else
+ s = s.left
+ end
+ end
+ flat_last_pos_start = st - i
+ flat_cache = s
+ return s[i]
end
redef fun substring(from, len) do
st = 0
end
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
# Mutable `Rope`, optimized for concatenation operations
redef var chars: Sequence[Char] is lazy do return new RopeBufferChars(self)
- redef var bytes: Sequence[Byte] is lazy do return new RopeBufferBytes(self)
+ redef var bytes is lazy do return new RopeBufferBytes(self)
# The final string being built on the fly
private var str: String = ""
# Next available (e.g. unset) character in the `Buffer`
private var rpos = 0
+ # Length (in chars) of the buffered part
+ private var nslen = 0
+
# Keeps track of the buffer's currently dumped part
#
# This might happen if for instance, a String was being
rpos = rp
end
- private fun add_byte(b: Byte) do
- var rp = rpos
- if rp >= buf_size then
- dump_buffer
- rp = 0
- end
- ns[rp] = b
- rp += 1
- bytelen += 1
- rpos = rp
- end
-
# Converts the Buffer to a FlatString, appends it to
# the final String and re-allocates a new larger Buffer.
private fun dump_buffer do
end
end
- redef fun []=(i,c) do
- if i == target.length then target.add_byte c
- if i < target.str.length then
- # FIXME: Will need to be optimized and rewritten with Unicode
- var s = target.str
- var l = s.substring(0, i)
- var r = s.substring_from(i + 1)
- target.str = l + c.to_i.ascii.to_s + r
- else
- target.ns[i - target.str.length] = c
- end
- end
-
- redef fun add(c) do target.add_byte c
-
- redef fun push(c) do target.add_byte c
-
redef fun iterator_from(i) do return new RopeBufferByteIterator.from(target, i)
redef fun reverse_iterator_from(i) do return new RopeBufferByteReverseIterator.from(target, i)