internal static RopeNode <T> Concat(RopeNode <T> left, RopeNode <T> right) { if (left.length == 0) { return(right); } if (right.length == 0) { return(left); } if (left.length + right.length <= NodeSize) { left = left.CloneIfShared(); // left is guaranteed to be leaf node after cloning: // - it cannot be function node (due to clone) // - it cannot be concat node (too short) right.CopyTo(0, left.contents, left.length, right.length); left.length += right.length; return(left); } else { RopeNode <T> concatNode = new RopeNode <T>(); concatNode.left = left; concatNode.right = right; concatNode.length = left.length + right.length; concatNode.Rebalance(); return(concatNode); } }
void MergeIfPossible() { Debug.Assert(!isShared); if (this.length <= NodeSize) { // Convert this concat node to leaf node. // We know left and right cannot be concat nodes (they would have merged already), // but they could be function nodes. this.height = 0; int lengthOnLeftSide = this.left.length; if (this.left.isShared) { this.contents = new T[NodeSize]; left.CopyTo(0, this.contents, 0, lengthOnLeftSide); } else { // must be a leaf node: function nodes are always marked shared Debug.Assert(this.left.contents != null); // steal buffer from left side this.contents = this.left.contents; #if DEBUG // In debug builds, explicitly mark left node as 'damaged' - but no one else should be using it // because it's not shared. this.left.contents = Empty <T> .Array; #endif } this.left = null; right.CopyTo(0, this.contents, lengthOnLeftSide, this.right.length); this.right = null; } }
/// <summary> /// Copies the a part of the rope into the specified array. /// Runs in O(lg N + M). /// </summary> /// <remarks> /// This method counts as a read access and may be called concurrently to other read accesses. /// </remarks> public void CopyTo(int index, T[] array, int arrayIndex, int count) { VerifyRange(index, count); VerifyArrayWithRange(array, arrayIndex, count); root.CopyTo(index, array, arrayIndex, count); }