sclass OccTree2 { OccTree2 parent; E e; new L next; int count; // This isn't accurate after replaceWith and stuff *() {} *(E *e) {} void addScript(L script) { OccTree2 node = this; ++count; for (E c : script) (node = node.getOrMakeFollowUp(c)).count++; } OccTree2 getOrMakeFollowUp(E e) { OccTree2 node = followUp(e); if (node == null) next.add(node = newChild(e)); ret node; } OccTree2 followUp(E e) { for (OccTree2 t : next) if (eq(t.e, e)) ret t; null; } L followUpKeys() { ret collect(next, "e"); } OccTree2 newChild(E e) { OccTree2 child = new OccTree2(e); child.parent = this; ret child; } // size including all nodes int size() { int n = 1; for (OccTree2 t : next) n += t.size(); ret n; } L allLeaves() { new L l; collectLeaves(l); ret l; } // does not include root node as it has no input line associated L allNodes() { new L l; collectNodes(l); ret l; } void collectLeaves(L l) { if (isLeaf()) l.add(this); else for (OccTree2 t : next) t.collectLeaves(l); } void collectNodes(L l) { if (!isRoot()) l.add(this); for (OccTree2 t : next) t.collectNodes(l); } bool isRoot() { ret e == null; } bool isLeaf() { ret !isRoot() && isEmpty(next); } int level() { int n = 0; OccTree2 node = this; while (node.parent != null) { ++n; node = node.parent; } ret n; } void replaceWith(OccTree2 n) { int i = parent.next.indexOf(this); parent.next.set(i, n); n.parent = parent; parent = null; } }