X-Git-Url: http://nitlanguage.org?ds=sidebyside diff --git a/lib/core/text/ropes.nit b/lib/core/text/ropes.nit index 3b4de21..f57b33d 100644 --- a/lib/core/text/ropes.nit +++ b/lib/core/text/ropes.nit @@ -83,11 +83,13 @@ private class Concat redef fun empty do return "" # Cache for the latest accessed FlatString in `self` - var flat_cache: String = "" + var flat_cache: FlatString is noinit # Position of the beginning of `flat_cache` in `self` var flat_last_pos_start: Int = -1 + var flat_last_pos_end: Int = -1 + redef var to_cstring is lazy do var len = _bytelen var ns = new NativeString(len + 1) @@ -113,6 +115,8 @@ private class Concat _bytelen = l.bytelen + r.bytelen end + redef fun is_empty do return _bytelen == 0 + redef fun output do _left.output _right.output @@ -127,38 +131,65 @@ private class Concat end redef fun [](i) do - 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] + assert i >= 0 and i <= _length + var flps = _flat_last_pos_start + if flps != -1 and i >= flps and i <= _flat_last_pos_end then + return _flat_cache.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 flps != -1 and pos >= flps and pos <= _flat_last_pos_end then + return _flat_cache end var s: String = self - var st = i + var st = pos loop if s isa FlatString then break s = s.as(Concat) var lft = s._left var llen = lft.length - if i >= llen then + if pos >= llen then s = s._right - i -= llen + pos -= llen else s = lft end end - flat_last_pos_start = st - i - flat_cache = s - return s[i] + _flat_last_pos_start = st - pos + _flat_last_pos_end = st - pos + s.length - 1 + _flat_cache = s + return s end - redef fun substring(from, len) do + 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 flps != -1 and from >= flps and end_index <= _flat_last_pos_end then + return _flat_cache.substring_impl(from - flps, count, end_index - flps) + end + var lft = _left var llen = lft.length if from < llen then - if from + len < llen then return lft.substring(from,len) + if from + count < llen then return lft.substring(from, count) var lsublen = llen - from - return lft.substring_from(from) + _right.substring(0, len - lsublen) + return lft.substring_from(from) + _right.substring(0, count - lsublen) else - return _right.substring(from - llen, len) + return _right.substring(from - llen, count) end end @@ -190,23 +221,16 @@ private class Concat end redef fun copy_to_native(dest, n, src_offset, dest_offset) do - var subs = new RopeSubstrings.from(self, src_offset) - var st = src_offset - subs.pos - var off = dest_offset - while n > 0 do - var it = subs.item - if n > it.length then - var cplen = it.length - st - it._items.copy_to(dest, cplen, st, off) - off += cplen - n -= cplen - else - it._items.copy_to(dest, n, st, off) - n = 0 - end - subs.next - st = 0 + var l = _left + if src_offset < l.bytelen then + var lcopy = l.bytelen - 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` @@ -425,12 +449,12 @@ class RopeBuffer var rem = count - subpos var nns = new NativeString(rem) ns.copy_to(nns, rem, dumped, 0) - return new RopeBuffer.from(l + nns.to_s_with_length(rem)) + return new RopeBuffer.from(l + nns.to_s_unsafe(rem)) end else var nns = new NativeString(count) ns.copy_to(nns, count, dumped, 0) - return new RopeBuffer.from(nns.to_s_with_length(count)) + return new RopeBuffer.from(nns.to_s_unsafe(count)) end end @@ -479,7 +503,7 @@ class RopeBuffer # the final String and re-allocates a new larger Buffer. private fun dump_buffer do written = false - var nstr = new FlatString.with_infos(ns, rpos - dumped, dumped, rpos - 1) + var nstr = new FlatString.with_infos(ns, rpos - dumped, dumped) str += nstr var bs = buf_size bs = bs * 2 @@ -492,14 +516,14 @@ class RopeBuffer # Similar to dump_buffer, but does not reallocate a new NativeString private fun persist_buffer do if rpos == dumped then return - var nstr = new FlatString.with_infos(ns, rpos - dumped, dumped, rpos - 1) + var nstr = new FlatString.with_infos(ns, rpos - dumped, dumped) str += nstr dumped = rpos end redef fun output do str.output - new FlatString.with_infos(ns, rpos - dumped, dumped, rpos - 1).output + new FlatString.with_infos(ns, rpos - dumped, dumped).output end # Enlarge is useless here since the `Buffer` @@ -521,7 +545,7 @@ class RopeBuffer redef fun reverse do # Flush the buffer in order to only have to reverse `str`. if rpos > 0 and dumped != rpos then - str += new FlatString.with_infos(ns, rpos - dumped, dumped, rpos - 1) + str += new FlatString.with_infos(ns, rpos - dumped, dumped) dumped = rpos end str = str.reversed @@ -564,7 +588,7 @@ redef class FlatString var ns = new NativeString(nlen + 1) mits.copy_to(ns, mlen, mifrom, 0) sits.copy_to(ns, slen, sifrom, mlen) - return new FlatString.full(ns, nlen, 0, nlen - 1, length + s.length) + return new FlatString.full(ns, nlen, 0, length + s.length) else if s isa Concat then var sl = s._left var sllen = sl.bytelen @@ -625,7 +649,7 @@ private class RopeByteReverseIterator if not subs.is_ok then return var s = subs.item ns = s._items - pns = s._last_byte + pns = s.last_byte end end @@ -639,7 +663,7 @@ private class RopeByteIterator var ns: NativeString is noautoinit # Substrings of the Rope var subs: IndexedIterator[FlatString] is noautoinit - # Maximum position to iterate on (e.g. Rope.length) + # Maximum position to iterate on (e.g. Rope.bytelen) var max: Int is noautoinit # Position (char) in the Rope (0-indexed) var pos: Int is noautoinit @@ -649,7 +673,7 @@ private class RopeByteIterator pns = pos - subs.index self.pos = pos ns = subs.item._items - max = root.length - 1 + max = root.bytelen - 1 end redef fun item do return ns[pns] @@ -797,7 +821,7 @@ private class ReverseRopeSubstrings redef fun next do if pos < 0 then return var curr = iter.prev - var currit = curr.node + var currit = curr.as(not null).node while curr != null do currit = curr.node if not currit isa Concat then @@ -834,7 +858,7 @@ private class RopeBufSubstringIterator init from(str: RopeBuffer) do iter = str.str.substrings - nsstr = new FlatString.with_infos(str.ns, str.rpos - str.dumped, str.dumped, str.rpos - 1) + nsstr = new FlatString.with_infos(str.ns, str.rpos - str.dumped, str.dumped) if str.length == 0 then nsstr_done = true end @@ -904,14 +928,14 @@ private class RopeSubstrings redef fun next do pos += str.length if pos > max then return - var it = iter.prev + var it = iter.prev.as(not null) var rnod = it.node loop if not rnod isa Concat then it.ldone = true it.rdone = true str = rnod.as(FlatString) - iter = it.as(not null) + iter = it break end if not it.ldone then @@ -923,7 +947,7 @@ private class RopeSubstrings rnod = rnod._right it = new RopeCharIteratorPiece(rnod, false, false, it) else - it = it.prev + it = it.prev.as(not null) rnod = it.node continue end @@ -953,18 +977,45 @@ private class RopeBytes redef type SELFTYPE: Concat + var cache: FlatString is noinit + + var cache_start: Int = -1 + + var cache_end: Int = -1 + redef fun [](i) do - var nod: String = target + assert i >= 0 and i < target._bytelen + var flps = _cache_start + if i >= flps and i <= _cache_end then + return _cache.bytes[i - flps] + end + var lf = get_leaf_at(i) + return lf.bytes[i - _cache_start] + end + + fun get_leaf_at(pos: Int): FlatString do + var flps = _cache_start + if pos >= flps and pos <= _cache_end then + return _cache + end + var s: String = target + var st = pos loop - if nod isa FlatString then return nod._items[i] - if not nod isa Concat then abort - var lft = nod._left - if lft.bytelen >= i then - nod = nod._right + if s isa FlatString then break + s = s.as(Concat) + var lft = s._left + var llen = lft.bytelen + if pos >= llen then + s = s._right + pos -= llen else - nod = lft + s = lft end end + _cache_start = st - pos + _cache_end = st - pos + s.bytelen - 1 + _cache = s + return s end redef fun iterator_from(i) do return new RopeByteIterator.from(target, i)