--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Introduces a self-balancing method on Rope, using a Splay Tree
+module splay_ropes
+
+import standard
+intrude import standard::ropes
+
+redef class Rope
+
+ # Performs a Left rotation on node `x`
+ # Since a Rope does not have any notion of parent in its node, they need to be passed as arguments if available.
+ private fun left_rotate(r: Concat): Concat
+ do
+ var rr = r.right.as(Concat)
+ var rl = r.left
+ var pl = rr.left
+ var pr = rr.right
+ var nr = new Concat(rl, pl)
+ var np = new Concat(nr, pr)
+ return np
+ end
+
+ # Performs a Right rotation on node `r`
+ # Since a Rope does not have any notion of parent in its node, they need to be passed as arguments if available.
+ private fun right_rotate(r: Concat): Concat
+ do
+ var rl = r.left.as(Concat)
+ var rr = r.right
+ var pr = rl.right
+ var pl = rl.left
+ var nr = new Concat(pr, rr)
+ var np = new Concat(pl, nr)
+ return np
+ end
+
+ # Performs a Splay operation on a complete path
+ # The last node of the path will become the root.
+ private fun splay(path: Path): nullable Concat
+ do
+ var st = path.stack
+ if st.is_empty then return null
+ var cct = st.pop.node
+ while not st.is_empty do
+ var tmp = st.pop
+ var nod: Concat
+ if tmp.left then
+ nod = new Concat(cct, tmp.node.right)
+ cct = right_rotate(nod)
+ else
+ nod = new Concat(tmp.node.left, cct)
+ cct = left_rotate(nod)
+ end
+ end
+ return cct
+ end
+end
+
+redef class RopeString
+
+ # Inserts a String `str` at position `pos`
+ redef fun insert_at(str, pos)
+ do
+ if str.length == 0 then return self
+ if self.length == 0 then return new RopeString.from(str)
+
+ assert pos >= 0 and pos <= length
+
+ var path = node_at(pos)
+
+ var last_concat: Concat
+
+ if path.offset == 0 then
+ if str isa FlatString then
+ last_concat = new Concat(new StringLeaf(str), path.leaf)
+ else
+ last_concat = new Concat(str.as(RopeString).root, path.leaf)
+ end
+ else if path.offset == path.leaf.length then
+ if str isa FlatString then
+ last_concat = new Concat(path.leaf, new StringLeaf(str))
+ else
+ last_concat = new Concat(path.leaf, str.as(RopeString).root)
+ end
+ else
+ var s = path.leaf.str
+ var l_half = s.substring(0, s.length - path.offset)
+ var r_half = s.substring_from(s.length - path.offset)
+ var cct: Concat
+ var ll = new StringLeaf(l_half.as(FlatString))
+ if str isa FlatString then
+ cct = new Concat(ll, new StringLeaf(str))
+ else
+ cct = new Concat(ll, str.as(RopeString).root)
+ end
+ last_concat = new Concat(cct, new StringLeaf(r_half.as(FlatString)))
+ end
+
+ var st = path.stack
+
+ if st.is_empty then return new RopeString.from_root(last_concat)
+
+ var tmp = st.pop
+
+ if tmp.left then
+ var n = tmp.node.right
+ var r = new Concat(last_concat, n)
+ st.push(new PathElement(r))
+ else
+ var n = tmp.node.left
+ var r = new Concat(n, last_concat)
+ st.push(new PathElement(r))
+ end
+
+ return new RopeString.from_root(splay(path).as(not null))
+ end
+
+end
+