package com.ripple.core.types.shamap;
import com.ripple.core.coretypes.hash.Hash256;
import java.util.ArrayDeque;
import java.util.Iterator;
public class PathToIndex {
public Hash256 index;
public ShaMapLeaf leaf;
private ArrayDeque<ShaMapInner> inners;
private ShaMapInner[] dirtied;
private boolean matched = false;
public boolean hasLeaf() {
return leaf != null;
}
public boolean leafMatchedIndex() {
return matched;
}
public boolean copyLeafOnUpdate() {
return leaf.version != dirtied[0].version;
}
int size() {
return inners.size();
}
public ShaMapInner top() {
return dirtied[dirtied.length - 1];
}
// returns the
public ShaMapInner dirtyOrCopyInners() {
if (maybeCopyOnWrite()) {
int ix = 0;
// We want to make a uniformly accessed array of the inners
dirtied = new ShaMapInner[inners.size()];
// from depth 0 to 1, to 2, to 3, don't be fooled by the api
Iterator<ShaMapInner> it = inners.descendingIterator();
// This is actually the root which COULD be the top of the stack
// Think about it ;)
ShaMapInner top = it.next();
dirtied[ix++] = top;
top.invalidate();
while (it.hasNext()) {
ShaMapInner next = it.next();
boolean doCopies = next.version != top.version;
if (doCopies) {
ShaMapInner copy = next.copy(top.version);
copy.invalidate();
top.setBranch(index, copy);
next = copy;
} else {
next.invalidate();
}
top = next;
dirtied[ix++] = top;
}
return top;
} else {
copyInnersToDirtiedArray();
return inners.peekFirst();
}
}
public boolean hasMatchedLeaf() {
return hasLeaf() && leafMatchedIndex();
}
public void collapseOnlyLeafChildInners() {
assert dirtied != null;
ShaMapInner next;
ShaMapLeaf onlyChild = null;
for (int i = dirtied.length - 1; i >= 0; i--) {
next = dirtied[i];
if (onlyChild != null) {
next.setLeaf(onlyChild);
}
onlyChild = next.onlyChildLeaf();
if (onlyChild == null) {
break;
}
}
}
private void copyInnersToDirtiedArray() {
int ix = 0;
dirtied = new ShaMapInner[inners.size()];
Iterator<ShaMapInner> descending = inners.descendingIterator();
while (descending.hasNext()) {
ShaMapInner next = descending.next();
dirtied[ix++] = next;
next.invalidate();
}
}
private boolean maybeCopyOnWrite() {
return inners.peekLast().doCoW;
}
public PathToIndex(ShaMapInner root, Hash256 index) {
this.index = index;
makeStack(root, index);
}
private void makeStack(ShaMapInner root, Hash256 index) {
inners = new ArrayDeque<ShaMapInner>();
ShaMapInner top = root;
while (true) {
inners.push(top);
ShaMapNode existing = top.getBranch(index);
if (existing == null) {
break;
} else if (existing.isLeaf()) {
leaf = existing.asLeaf();
matched = leaf.index.equals(index);
break;
}
else if (existing.isInner()) {
top = existing.asInner();
}
}
}
public ShaMapLeaf invalidatedPossiblyCopiedLeafForUpdating() {
assert matched;
if (dirtied == null) {
dirtyOrCopyInners();
}
ShaMapLeaf theLeaf = leaf;
if (copyLeafOnUpdate()) {
theLeaf = leaf.copy();
top().setLeaf(theLeaf);
}
theLeaf.invalidate();
return theLeaf;
}
}