/** {@inheritDoc} */ @Override public void add(int index, T0 element) { tree.add(index, colors, color, element, 1); }
@Override public String toString() { return tree.asSequenceOfColors(); }
/** * Create a new node. * * @param color a bitmask value such as 1, 2, 4, 8 or 16. * @param size the size of the node * @param value the value of the node * @param parent the parent node in the tree, or <code>null</code> for the * root node. */ public FourColorNode/**/( byte color, int size, T0 value, FourColorNode < T0> parent) { assert(FourColorTree.colorAsIndex(color) >= 0 && FourColorTree.colorAsIndex(color) < 7); this.color = color; this.size = size; this.t0 = value; this.height = 1; this.parent = parent; if(color == 1) count1 += size; if(color == 2) count2 += size; if(color == 4) count4 += size; if(color == 8) count8 += size; }
/** * Replace all values at the specified index with the specified new value. * * <p>Currently this uses a naive implementation of remove then add. If * it proves desirable, it may be worthwhile to optimize this implementation * with one that performs the remove and insert simultaneously, to save * on tree navigation. * * @return the element that was updated. This is non-null unless the size * parameter is 0, in which case the result is always <code>null</code>. */ public Element<T0> set(int index, byte indexColors, byte color, T0 value, int size) { remove(index, indexColors, size); return add(index, indexColors, color, value, size); }
/** * Remove the specified element from the tree outright. */ public void remove(Element<T0> element) { FourColorNode < T0> node = ( FourColorNode < T0> )element; assert(node.size > 0); assert(root != null); // delete the node by adding to the zero queue fixCountsThruRoot(node, node.color, -node.size ); node.size = 0; zeroQueue.add(node); drainZeroQueue(); assert(valid()); }
/** * Remove size values at the specified index. Only values of the type * specified in indexColors will be removed. * * <p>Note that if the two nodes on either side of the removed node could * be merged, they probably will not be merged by this implementation. This * is to simplify the implementation, but it means that when iterating a * tree, sometimes multiple nodes of the same color and value will be * encountered in sequence. */ public void remove(int index, byte indexColors, int size) { if(size == 0) return; assert(index >= 0); assert(index + size <= size( indexColors )); assert(root != null); // remove values from the tree removeFromSubtree(root, index, indexColors, size); // clean up any nodes that got deleted drainZeroQueue(); assert(valid()); }
/** * <p>We should consider removing the loop from this method by counting * the inserted elements between startIndex and endIndex, removing those, * then removing everything else... * * @param startIndex the index of the first element to remove * @param endIndex the last index, exclusive * @param value the removed value */ public void targetDelete(int startIndex, int endIndex, E value) { if(!initialCapacityKnown) ensureCapacity(endIndex); for(int i = startIndex; i < endIndex; i++) { if(startIndex > 0 && startIndex > tree.size(TARGET_INDICES)) { throw new IllegalArgumentException(); } int overallIndex = tree.convertIndexColor(startIndex, TARGET_INDICES, ALL_INDICES); Element<E> standingChangeToIndex = tree.get(overallIndex, ALL_INDICES); // if we're deleting an insert, remove that insert if(standingChangeToIndex.getColor() == INSERT) { if(!allowContradictingEvents) throw new IllegalStateException("Remove " + i + " undoes prior insert at the same index! Consider enabling contradicting events."); tree.remove(overallIndex, ALL_INDICES, 1); continue; } // if we're deleting an update, the original replaced value stands. if(standingChangeToIndex.getColor() == UPDATE) { value = standingChangeToIndex.get(); } tree.set(overallIndex, ALL_INDICES, DELETE, value, 1); } }
/** * Step to the next node. */ public void nextNode( byte colors ) { if(!hasNextNode( colors )) { throw new NoSuchElementException(); } // start at the first node in the tree if(node == null) { node = tree.firstNode(); index = 0; if((node.color & colors) != 0) return; } // scan through the nodes, looking for the first one of the right color while(true) { if(node.color == 1) count1 += node.size - index; if(node.color == 2) count2 += node.size - index; if(node.color == 4) count4 += node.size - index; if(node.color == 8) count8 += node.size - index; node = FourColorTree.next(node); index = 0; // we've found a node that meet our requirements, so return if((node.color & colors) != 0) break; } }
/** * Print this tree as a list of colors, removing all hierarchy. */ public String asSequenceOfColors() { if(root == null) return ""; // print it flattened, like a list of colors StringBuffer result = new StringBuffer(); for(FourColorNode n = firstNode(); n != null; n = next(n)) { Object color = coder.getColors().get(colorAsIndex(n.color)); for( int i = 0; i < n.size; i++ ) { result.append(color); } } return result.toString(); }
this.node = ( FourColorNode < T0> )tree.get(currentIndex , nextIndexColors ); count1 = tree.convertIndexColor(currentIndex, nextIndexColors, (byte)1) + (node.color == 1 ? 0 : 1); count2 = tree.convertIndexColor(currentIndex, nextIndexColors, (byte)2) + (node.color == 2 ? 0 : 1); count4 = tree.convertIndexColor(currentIndex, nextIndexColors, (byte)4) + (node.color == 4 ? 0 : 1); count8 = tree.convertIndexColor(currentIndex, nextIndexColors, (byte)8) + (node.color == 8 ? 0 : 1); if(node.color == 1) this.index = count1 - tree.indexOfNode(this.node, (byte)1); if(node.color == 2) this.index = count2 - tree.indexOfNode(this.node, (byte)2); if(node.color == 4) this.index = count4 - tree.indexOfNode(this.node, (byte)4); if(node.color == 8) this.index = count8 - tree.indexOfNode(this.node, (byte)8);
/** * <p>We should consider removing the loop by only setting on removed elements. * * @param oldValue the previous value being replaced * @param newValue the new value * @param startIndex the first updated element, inclusive * @param endIndex the last index, exclusive */ public void targetUpdate(int startIndex, int endIndex, E oldValue, E newValue) { if(!initialCapacityKnown) ensureCapacity(endIndex); for(int i = startIndex; i < endIndex; i++) { int overallIndex = tree.convertIndexColor(i, TARGET_INDICES, ALL_INDICES); Element<E> standingChangeToIndex = tree.get(overallIndex, ALL_INDICES); if(horribleHackPreferMostRecentValue) { byte newColor = standingChangeToIndex.getColor() == INSERT ? INSERT : UPDATE; tree.set(overallIndex, ALL_INDICES, newColor, oldValue, 1); continue; } // don't bother updating an inserted element if(standingChangeToIndex.getColor() == INSERT) { continue; } // if we're updating an update, the original replaced value stands. if(standingChangeToIndex.getColor() == UPDATE) { oldValue = standingChangeToIndex.get(); } // apply the update to our change description tree.set(overallIndex, ALL_INDICES, UPDATE, oldValue, 1); } }
for( FourColorNode < T0> currentFollower = parent; true; currentFollower = next(currentFollower)) { fixCountsThruRoot(parent, color, size); return parent; FourColorNode < T0> inserted = new FourColorNode < T0> ( color, size, value, parent); parent.left = inserted; fixCountsThruRoot(parent, color, size); fixHeightPostChange(parent, false); return inserted; FourColorNode < T0> inserted = new FourColorNode < T0> ( color, size, value, parent); parent.right = inserted; fixCountsThruRoot(parent, color, size); fixHeightPostChange(parent, false); return inserted;
if(index >= parentLeftSize && index <= parentRightStartIndex) { parent.size += size; fixCountsThruRoot(parent, color, size); return parent; FourColorNode < T0> inserted = new FourColorNode < T0> ( color, size, value, parent); parent.left = inserted; fixCountsThruRoot(parent, color, size); fixHeightPostChange(parent, false); return inserted; int parentRightHalfSize = parentRightStartIndex - index; parent.size -= parentRightHalfSize; fixCountsThruRoot(parent, parent.color, -parentRightHalfSize); Element<T0> inserted = insertIntoSubtree(parent, index, indexColors, parent.color, null, parentRightHalfSize); inserted.set(parent.t0); FourColorNode < T0> inserted = new FourColorNode < T0> ( color, size, value, parent); parent.right = inserted; fixCountsThruRoot(parent, color, size); fixHeightPostChange(parent, false); return inserted;
/** {@inheritDoc} */ @Override public T0 get(int index) { return tree.get(index , colors ).get(); }
fixCountsThruRoot(replacement, replacement.color, -replacement.size ); replaceChild(replacement, replacement.left); replacement.height = toReplace.height; replacement.refreshCounts(); replaceChild(toReplace, replacement); fixCountsThruRoot(replacement.parent, replacement.color, replacement.size );
removeFromSubtree(nodeLeft, index, indexColors, toRemove); size -= toRemove; leftSize -= toRemove; size -= toRemove; rightStartIndex -= toRemove; fixCountsThruRoot(node, node.color, -toRemove); if( node.size == 0 ) { zeroQueue.add(node);
/** {@inheritDoc} */ @Override protected int getSourceIndex(int mutationIndex) { return data.convertIndexColor(mutationIndex, VISIBLE_NODES, REAL_NODES); }
public void reset(int size) { tree.clear(); initialCapacityKnown = true; ensureCapacity(size); } private void ensureCapacity(int size) {
/** * Change the color of the specified element. */ public final void setColor(Element<T0> element, byte color) { FourColorNode node = (FourColorNode)element; byte oldColor = node.getColor(); if(oldColor == color) return; fixCountsThruRoot(node, oldColor, -node.size); node.color = color; fixCountsThruRoot(node, color, node.size); }