lib/standard/text: Removed byte-level modification on Buffers
[nit.git] / lib / standard / text / ropes.nit
index 4018339..870859a 100644 (file)
@@ -82,6 +82,12 @@ private class Concat
 
        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)
@@ -119,9 +125,27 @@ private class Concat
        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
@@ -180,6 +204,50 @@ private class Concat
                        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
@@ -202,7 +270,7 @@ class RopeBuffer
 
        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 = ""
@@ -213,6 +281,9 @@ class RopeBuffer
        # 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
@@ -399,18 +470,6 @@ class RopeBuffer
                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
@@ -1169,23 +1228,6 @@ class RopeBufferBytes
                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)