package bjc.utils.data; import java.util.Deque; import java.util.Iterator; import java.util.LinkedList; import java.util.NoSuchElementException; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; public class TopDownTransformIterator implements Iterator> { private Function picker; private BiFunction, Consumer>>, ITree> transform; private ITree preParent; private ITree postParent; private Deque> preChildren; private Deque> postChildren; private TopDownTransformIterator curChild; private boolean done; private boolean initial; private Deque>> toYield; private Iterator> curYield; public TopDownTransformIterator(Function pickr, BiFunction, Consumer>>, ITree> transfrm, ITree tree) { preParent = tree; preChildren = new LinkedList<>(); postChildren = new LinkedList<>(); toYield = new LinkedList<>(); picker = pickr; transform = transfrm; done = false; initial = true; } public void addYield(Iterator> src) { if(curYield != null) { toYield.push(curYield); } curYield = src; } public boolean hasNext() { return !done; } public ITree next() { if(done) throw new NoSuchElementException(); if(initial) { TopDownTransformResult res = picker.apply(preParent.getHead()); switch(res) { case PASSTHROUGH: postParent = new Tree<>(preParent.getHead()); if(preParent.getChildrenCount() != 0) { for(int i = 0; i < preParent.getChildrenCount(); i++) { preChildren.add(preParent.getChild(i)); } // Return whatever the first child is break; } else { done = true; return postParent; } case SKIP: done = true; return preParent; case TRANSFORM: done = true; return transform.apply(preParent, this::addYield); case PUSHDOWN: if(preParent.getChildrenCount() != 0) { for(int i = 0; i < preParent.getChildrenCount(); i++) { preChildren.add(preParent.getChild(i)); } // Return whatever the first child is break; } else { done = true; return transform.apply(new Tree<>(preParent.getHead()), this::addYield); } case PULLUP: ITree intRes = transform.apply(preParent, this::addYield); postParent = new Tree<>(intRes.getHead()); if(intRes.getChildrenCount() != 0) { for(int i = 0; i < intRes.getChildrenCount(); i++) { preChildren.add(intRes.getChild(i)); } // Return whatever the first child is break; } else { done = true; return postParent; } default: throw new IllegalArgumentException("Unknown result type " + res); } initial = false; } if(curYield != null) { if(curYield.hasNext()) { return curYield.next(); } else { while(toYield.size() != 0 && !curYield.hasNext()) { curYield = toYield.pop(); } if(toYield.size() == 0 && !curYield.hasNext()) { curYield = null; } } } if(curChild == null || !curChild.hasNext()) { if(preChildren.size() != 0) { curChild = new TopDownTransformIterator<>(picker, transform, preChildren.pop()); ITree res = curChild.next(); postChildren.add(res); return res; } else { ITree res = null; if(postParent == null) { res = new Tree<>(preParent.getHead()); for(ITree child : postChildren) { res.addChild(child); } res = transform.apply(res, this::addYield); } else { res = postParent; for(ITree child : postChildren) { res.addChild(child); } } done = true; return res; } } else { ITree res = curChild.next(); postChildren.add(res); return res; } } }