Class: Rope::InteriorNode
- Defined in:
- lib/rope/interior_node.rb
Overview
Specifies an interior node. Its underlying data is retrieved by combining its children recursively.
Instance Attribute Summary collapse
-
#left ⇒ Object
readonly
Left and right nodes.
-
#right ⇒ Object
readonly
Left and right nodes.
Attributes inherited from BasicNode
Instance Method Summary collapse
-
#data ⇒ Object
Gets the underlying data in the tree.
-
#freeze ⇒ Object
Freeze is redefined to freeze the subtree; used when dup’ing a Rope to protect against aliasing.
-
#initialize(left, right) ⇒ InteriorNode
constructor
Initializes a new concatenation node.
-
#rebalance! ⇒ Object
Rebalances this tree.
-
#replace!(index, length, substr) ⇒ Object
Overwrites data at index with substr.
-
#slice(arg0, *args) ⇒ Object
Gets a slice of the underlying data in the tree.
-
#subtree(from, length) ⇒ Object
Returns a node that represents a slice of this tree.
Methods inherited from BasicNode
Constructor Details
#initialize(left, right) ⇒ InteriorNode
Initializes a new concatenation node.
11 12 13 14 15 16 17 |
# File 'lib/rope/interior_node.rb', line 11 def initialize(left, right) @left = left @right = right @length = left.length + right.length @depth = [left.depth, right.depth].max + 1 end |
Instance Attribute Details
#left ⇒ Object (readonly)
Left and right nodes
8 9 10 |
# File 'lib/rope/interior_node.rb', line 8 def left @left end |
#right ⇒ Object (readonly)
Left and right nodes
8 9 10 |
# File 'lib/rope/interior_node.rb', line 8 def right @right end |
Instance Method Details
#data ⇒ Object
Gets the underlying data in the tree
20 21 22 |
# File 'lib/rope/interior_node.rb', line 20 def data left.data + right.data end |
#freeze ⇒ Object
Freeze is redefined to freeze the subtree; used when dup’ing a Rope to protect against aliasing
73 74 75 76 77 78 79 80 |
# File 'lib/rope/interior_node.rb', line 73 def freeze unless frozen? super @left.freeze unless @left.frozen? @right.freeze unless @right.frozen? end self end |
#rebalance! ⇒ Object
Rebalances this tree
83 84 85 |
# File 'lib/rope/interior_node.rb', line 83 def rebalance! # TODO end |
#replace!(index, length, substr) ⇒ Object
Overwrites data at index with substr
Returns self, however leaf nodes may return a new interior node if the replace! causes a leaf to be split
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/rope/interior_node.rb', line 120 def replace!(index, length, substr) # We may be frozen, so this all gets reified into a new node or overwrites on ourselves new_left = @left new_right = @right # Translate to positive index if given a negative one if index < 0 index += @length end rindex = index - @left.length if(index == 0 && length == @left.length) #substr exactly replaces left sub-tree new_left = LeafNode.new(substr) elsif(index == @left.length && length == @right.length) #substr exactly replaces right sub-tree new_right = LeafNode.new(substr) elsif rindex < 0 if(index + length <= @left.length) #Replacement segment is a subsection of the left tree #Requested index is in the left subtree, and a split may occur new_left = @left.replace!(index, length, substr) else #Replacement segement is a subsection of left tree along with a subsection of the right tree left_count = @left.length - index new_left = InteriorNode.new( @left.subtree(0, index), LeafNode.new(substr) ) new_right = @right.subtree(rindex + length, @right.length - (rindex + length)) end else # Requested index is in the right subtree, and a split may occur new_right = @right.replace!(rindex, length, substr) end if(frozen?) InteriorNode.new(new_left, new_right) else #Length could have changed if the substr replaced a section of a different size or there was an append @left = new_left @right = new_right @length = @left.length + @right.length @depth = [left.depth, right.depth].max + 1 self end end |
#slice(arg0, *args) ⇒ Object
Gets a slice of the underlying data in the tree
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/rope/interior_node.rb', line 25 def slice(arg0, *args) if args.length == 0 if arg0.is_a?(Fixnum) slice(arg0, 1) elsif arg0.is_a?(Range) from, to = arg0.minmax # Special case when the range doesn't actually describe a valid range return nil if from.nil? || to.nil? # Normalize so both from and to are positive indices if from < 0 from += @length end if to < 0 to += @length end if from <= to subtree(from, (to - from) + 1) else # Range first is greater than range last # Return empty string to match what String does raise "TODO" end end # TODO: arg0.is_a?(Range) # TODO: arg0.is_a?(Regexp) # TODO: arg0.is_a?(String) else arg1 = args[0] # may be slightly confusing; refer to method definition if arg0.is_a?(Fixnum) && arg1.is_a?(Fixnum) # Fixnum, Fixnum if arg1 >= 0 subtree(arg0, arg1) else # Negative length, return nil to match what String does nil end end # TODO: arg0.is_a?(Regexp) && arg1.is_a?(Fixnum) end end |
#subtree(from, length) ⇒ Object
Returns a node that represents a slice of this tree
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/rope/interior_node.rb', line 88 def subtree(from, length) # Translate to positive index if given a negative one if from < 0 from += @length end # If more than @length characters are requested, truncate length = [(@length - from), length].min # Entire length requested return self if length == @length # Check if the requested subtree is entirely in the right subtree rfrom = from - @left.length return @right.subtree(rfrom, length) if rfrom >= 0 llen = @left.length - from rlen = length - llen if rlen > 0 # Requested subtree overlaps both the left and the right subtree @left.subtree(from, llen) + @right.subtree(0, rlen) else # Requested subtree is entirely in the left subtree @left.subtree(from, length) end end |