/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.containers;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
import java.util.List;
import static com.intellij.openapi.util.Conditions.not;
public abstract class FilteredTraverserBase<T, Self extends FilteredTraverserBase<T, Self>> implements Iterable<T> {
protected final Meta<T> meta;
protected final Function<T, ? extends Iterable<? extends T>> tree;
protected FilteredTraverserBase(@Nullable Meta<T> meta, Function<T, ? extends Iterable<? extends T>> tree) {
this.tree = tree;
this.meta = meta == null ? Meta.<T>empty() : meta;
}
@NotNull
public T getRoot() {
return meta.roots.iterator().next();
}
@NotNull
public Iterable<? extends T> getRoots() {
return meta.roots;
}
@Override
public Iterator<T> iterator() {
return traverse().iterator();
}
@NotNull
protected abstract Self newInstance(Meta<T> meta);
@NotNull
public JBIterable<T> traverse(TreeTraversal traversal) {
Function<T, Iterable<? extends T>> adjusted = new Function<T, Iterable<? extends T>>() {
@Override
public Iterable<? extends T> fun(T t) {
return children(t);
}
};
return traversal.traversal(getRoots(), adjusted).filter(meta.filter.AND());
}
@NotNull
public JBIterable<T> traverse() {
return traverse(meta.traversal);
}
@NotNull
public final JBIterable<T> preOrderDfsTraversal() {
return traverse(TreeTraversal.PRE_ORDER_DFS);
}
@NotNull
public final JBIterable<T> postOrderDfsTraversal() {
return traverse(TreeTraversal.POST_ORDER_DFS);
}
@NotNull
public final JBIterable<T> bfsTraversal() {
return traverse(TreeTraversal.PLAIN_BFS);
}
@NotNull
public final JBIterable<T> tracingBfsTraversal() {
return traverse(TreeTraversal.TRACING_BFS);
}
@NotNull
public Self reset() {
return newInstance(meta.reset());
}
@NotNull
public Self withRoot(@Nullable T root) {
return newInstance(meta.withRoots(ContainerUtil.createMaybeSingletonList(root)));
}
@NotNull
public Self withRoots(@NotNull Iterable<? extends T> roots) {
return newInstance(meta.withRoots(roots));
}
@NotNull
public Self withTraversal(TreeTraversal type) {
return newInstance(meta.withTraversal(type));
}
@NotNull
public Self expand(@NotNull Condition<? super T> c) {
return newInstance(meta.expand(c));
}
@NotNull
public Self regard(@NotNull Condition<? super T> c) {
return newInstance(meta.regard(c));
}
@NotNull
public Self expandAndFilter(Condition<? super T> c) {
return newInstance(meta.expand(c).filter(c));
}
@NotNull
public Self expandAndSkip(Condition<? super T> c) {
return newInstance(meta.expand(c).filter(not(c)));
}
@NotNull
public Self filter(@NotNull Condition<? super T> c) {
return newInstance(meta.filter(c));
}
@NotNull
public <C> JBIterable<C> filter(@NotNull Class<C> type) {
return traverse().filter(type);
}
@NotNull
public Self forceIgnore(@NotNull Condition<? super T> c) {
return newInstance(meta.forceIgnore(c));
}
@NotNull
public Self forceDisregard(@NotNull Condition<? super T> c) {
return newInstance(meta.forceDisregard(c));
}
@NotNull
public JBIterable<T> children(@NotNull T node) {
if (isAlwaysLeaf(node)) {
return JBIterable.empty();
}
else if (meta.regard.next == null && meta.forceDisregard.next == null) {
return JBIterable.from(tree.fun(node)).filter(not(meta.forceIgnore.OR()));
}
else {
// traverse subtree to select accepted children
return TreeTraversal.GUIDED_TRAVERSAL.traversal(node, tree).intercept(meta.createChildrenGuide(node));
}
}
protected boolean isAlwaysLeaf(@NotNull T node) {
return !meta.expand.valueAnd(node);
}
@NotNull
public List<T> toList() {
return traverse().toList();
}
@Override
public String toString() {
return traverse().toString();
}
public abstract static class EdgeFilter<T> extends JBIterable.StatefulFilter<T> {
protected T curParent;
}
@SuppressWarnings("unchecked")
protected static class Meta<T> {
final Iterable<? extends T> roots;
final TreeTraversal traversal;
final Cond<T> expand;
final Cond<T> regard;
final Cond<T> filter;
final Cond<T> forceIgnore;
final Cond<T> forceDisregard;
public Meta(@NotNull Iterable<? extends T> roots,
@NotNull TreeTraversal traversal,
@NotNull Cond<T> expand,
@NotNull Cond<T> regard,
@NotNull Cond<T> filter,
@NotNull Cond<T> forceIgnore,
@NotNull Cond<T> forceDisregard) {
this.roots = roots;
this.traversal = traversal;
this.expand = expand;
this.regard = regard;
this.filter = filter;
this.forceIgnore = forceIgnore;
this.forceDisregard = forceDisregard;
}
public Meta<T> reset() {
return new Meta<T>(roots, TreeTraversal.PRE_ORDER_DFS, Cond.TRUE, Cond.TRUE, Cond.TRUE, forceIgnore, forceDisregard);
}
public Meta<T> withRoots(@NotNull Iterable<? extends T> roots) {
return new Meta<T>(roots, traversal, expand, regard, filter, forceIgnore, forceDisregard);
}
public Meta<T> withTraversal(TreeTraversal traversal) {
return new Meta<T>(roots, traversal, expand, regard, filter, forceIgnore, forceDisregard);
}
public Meta<T> expand(@NotNull Condition<? super T> c) {
return new Meta<T>(roots, traversal, expand.append(c), regard, this.filter, forceIgnore, forceDisregard);
}
public Meta<T> regard(@NotNull Condition<? super T> c) {
return new Meta<T>(roots, traversal, expand, regard.append(c), this.filter, forceIgnore, forceDisregard);
}
public Meta<T> filter(@NotNull Condition<? super T> c) {
return new Meta<T>(roots, traversal, expand, regard, this.filter.append(c), forceIgnore, forceDisregard);
}
public Meta<T> forceIgnore(Condition<? super T> c) {
return new Meta<T>(roots, traversal, expand, regard, this.filter, forceIgnore.append(c), forceDisregard);
}
public Meta<T> forceDisregard(Condition<? super T> c) {
return new Meta<T>(roots, traversal, expand, regard, this.filter, forceIgnore, forceDisregard.append(c));
}
Function.Mono<TreeTraversal.GuidedIt<T>> createChildrenGuide(final T parent) {
final Condition<? super T> expand = buildExpandConditionForChildren(parent);
class G implements Consumer<TreeTraversal.GuidedIt<T>>, Function.Mono<TreeTraversal.GuidedIt<T>> {
@Override
public TreeTraversal.GuidedIt<T> fun(TreeTraversal.GuidedIt<T> it) {
return it.setGuide(this);
}
@Override
public void consume(TreeTraversal.GuidedIt<T> it) {
doPerformChildrenGuidance(it, expand);
}
}
return new G();
}
private void doPerformChildrenGuidance(TreeTraversal.GuidedIt<T> it, Condition<? super T> expand) {
if (it.curChild == null) return;
if (forceIgnore.valueOr(it.curChild)) return;
if (it.curParent == null || expand.value(it.curChild)) {
it.queueNext(it.curChild);
}
else {
it.result(it.curChild);
}
}
private Condition<? super T> buildExpandConditionForChildren(T parent) {
// implements: or2(forceExpandAndSkip, not(childFilter));
// and handles JBIterable.StatefulTransform and EdgeFilter conditions
Cond copy = null;
boolean invert = true;
Cond c = regard;
while (c != null) {
Condition impl = JBIterable.Stateful.copy(c.impl);
if (impl != (invert ? Condition.TRUE : Condition.FALSE)) {
copy = new Cond<Object>(invert ? not(impl) : impl, copy);
if (impl instanceof EdgeFilter) {
((EdgeFilter)impl).curParent = parent;
}
}
if (c.next == null) {
c = invert ? forceDisregard : null;
invert = false;
}
else {
c = c.next;
}
}
return copy == null ? Condition.FALSE : copy.OR();
}
private static final Meta<?> EMPTY = new Meta<Object>(
JBIterable.empty(), TreeTraversal.PRE_ORDER_DFS,
Cond.TRUE, Cond.TRUE, Cond.TRUE,
Cond.FALSE, Cond.FALSE);
public static <T> Meta<T> empty() {
return (Meta<T>)EMPTY;
}
}
private static class Cond<T> {
final static Cond TRUE = new Cond<Object>(Conditions.TRUE, null);
final static Cond FALSE = new Cond<Object>(Conditions.FALSE, null);
final Condition<? super T> impl;
final Cond<T> next;
Cond(Condition<? super T> impl, Cond<T> next) {
this.impl = impl;
this.next = next;
}
Cond<T> append(Condition<? super T> impl) {
return new Cond<T>(impl, this);
}
private boolean valueAnd(T t) {
for (Cond<T> c = this; c != null; c = c.next) {
if (!c.impl.value(t)) return false;
}
return true;
}
private boolean valueOr(T t) {
for (Cond<T> c = this; c != null; c = c.next) {
if (c.impl.value(t)) return true;
}
return false;
}
Condition<? super T> OR() {
return new Condition<T>() {
@Override
public boolean value(T t) {
return valueOr(t);
}
};
}
Condition<? super T> AND() {
return new Condition<T>() {
@Override
public boolean value(T t) {
return valueAnd(t);
}
};
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Cond{");
for (Cond<T> c = this; c != null; c = c.next) {
sb.append(JBIterator.toShortString(c.impl));
if (c.next != null) sb.append(", ");
}
return sb.append("}").toString();
}
}
}