-# Abstract class, represents all the services offered by both mutable and immutable ropes
-abstract class Rope
- super Comparable
- super StringCapable
-
- # Cached version of self as a flat String
- private var str_representation: nullable String = null
-
- redef type OTHER: Rope
-
- # The first node of the hierarchy
- private var parent_node: RopeNode
-
- # Needed by the compiler to avoid producing an error with constructors in subclasses
- init do
- self.parent_node = new ConcatNode
- end
-
- # Initializes a new Rope with a text embedded in directly
- init with_string(str: String) do
- self.parent_node = new ConcatNode
- parent_node.as(ConcatNode).right_child = new LeafNode(str)
- parent_node.as(ConcatNode).update_data
- end
-
- # Returns a view on the rope
- fun chars: SequenceRead[Char]
- do
- return new CharRopeView(self)
- end
-
- # Gets the total length of the Rope
- fun length: Int
- do
- return parent_node.length
- end
-
- # Returns a flat version of self
- redef fun to_s
- do
- if self.str_representation == null then flatten
- return str_representation.as(not null)
- end
-
- # Stores a flat version of self in cache
- private fun flatten: String
- do
- var native_final_str = calloc_string(length + 1)
-
- native_final_str[length] = '\0'
-
- var offset = 0
-
- var iter = new DFSRopeLeafIterator(self)
-
- while iter.is_ok do
- iter.item.value.items.copy_to(native_final_str, iter.item.value.length, 0, offset)
- offset += iter.item.value.length
- iter.next
- end
-
- return native_final_str.to_s_with_length(length)
- end
-
- # Gets a node containing the substring to seek the char at the require position
- private fun get_node_for_pos(position: Int): TupleLeafNodePos
- do
- assert position >= 0 and position < self.length
-
- var curr_node: nullable RopeNode = parent_node
-
- var visit_stack = new List[TupleVisitNode]
-
- var curr_visit_tuple: TupleVisitNode
-
- loop
- if curr_node isa ConcatNode then
- curr_visit_tuple = new TupleVisitNode(curr_node)
- if curr_node.left_child != null and position < curr_node.left_child.length then
- curr_visit_tuple.left_visited = true
- curr_node = curr_node.left_child
- else if curr_node.right_child != null then
- curr_visit_tuple.left_visited = true
- curr_visit_tuple.right_visited = true
- if curr_node.left_child != null then position -= curr_node.left_child.length
- curr_node = curr_node.right_child
- else
- print "Fatal Error"
- abort
- end
- visit_stack.push(curr_visit_tuple)
- else if curr_node isa LeafNode then
- return new TupleLeafNodePos(curr_node, position, visit_stack)
- end
- end
- end
-
- # Concats two ropes and returns a new one
- fun +(other: Rope): Rope do
- var new_rope = new BufferRope
-
- var first_iter = new DFSRopeLeafIterator(self)
-
- while first_iter.is_ok do
- new_rope.append(first_iter.item.value)
- first_iter.next
- end
-
- var second_iter = new DFSRopeLeafIterator(other)
-
- while second_iter.is_ok do
- new_rope.append(second_iter.item.value)
- second_iter.next
- end
-
- return new_rope
- end
-
- # Returns a copy of several ropes concatenated
- #
- # Is equivalent to a chain of + operations
- # Except this one is optimized for performance
- fun multi_concat(ropes: Rope...): Rope
- do
- var new_rope = new BufferRope
-
- var self_iter = self.iterator
- while self_iter.is_ok do
- new_rope.append(self_iter.item.value)
- self_iter.next
- end
-
- for i in ropes do
- var iter = i.iterator
- while iter.is_ok do
- new_rope.append(iter.item.value)
- iter.next
- end
- end
-
- return new_rope
- end
-
- # Appends the content of self multiple times in a new Rope object
- fun *(repeats: Int): Rope do
-
- var new_rope = new BufferRope