/* * Copyright 2000-2014 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 org.jetbrains.annotations.NotNull; import java.util.Iterator; import java.util.NoSuchElementException; /** * {@link #remove} throws {@link IllegalStateException} if called after {@link #hasNext} * @author dsl * @author dyoma */ public class FilteringIterator implements Iterator { private final Iterator myBaseIterator; private final Condition myFilter; private boolean myNextObtained = false; private boolean myCurrentIsValid = false; private Dom myCurrent; private Boolean myCurrentPassedFilter = null; public static final Condition NOT_NULL = new Condition() { @Override public boolean value(Object t) { return t != null; } }; public FilteringIterator(@NotNull Iterator baseIterator, @NotNull Condition filter) { myBaseIterator = baseIterator; myFilter = filter; } private void obtainNext() { if (myNextObtained) return; boolean hasNext = myBaseIterator.hasNext(); setCurrent(hasNext ? myBaseIterator.next() : null); myCurrentIsValid = hasNext; myNextObtained = true; } @Override public boolean hasNext() { obtainNext(); if (!myCurrentIsValid) return false; boolean value = isCurrentPassesFilter(); while (!value && myBaseIterator.hasNext()) { Dom next = myBaseIterator.next(); setCurrent(next); value = isCurrentPassesFilter(); } return value; } private void setCurrent(Dom next) { myCurrent = next; myCurrentPassedFilter = null; } private boolean isCurrentPassesFilter() { if (myCurrentPassedFilter != null) return myCurrentPassedFilter.booleanValue(); boolean passed = myFilter.value(myCurrent); myCurrentPassedFilter = Boolean.valueOf(passed); return passed; } @Override public E next() { if (!hasNext()) throw new NoSuchElementException(); E result = (E)myCurrent; myNextObtained = false; return result; } /** * Works after call {@link #next} until call {@link #hasNext} * @throws IllegalStateException if {@link #hasNext} called */ @Override public void remove() { if (myNextObtained) throw new IllegalStateException(); myBaseIterator.remove(); } public static Iterator skipNulls(Iterator iterator) { return create(iterator, NOT_NULL); } public static Iterator create(Iterator iterator, Condition condition) { return new FilteringIterator(iterator, condition); } public static Condition alwaysTrueCondition(Class aClass) { return Conditions.alwaysTrue(); } public static InstanceOf instanceOf(final Class aClass) { return new InstanceOf(aClass); } public static Iterator createInstanceOf(Iterator iterator, Class aClass) { return create((Iterator)iterator, instanceOf(aClass)); } public static class InstanceOf implements Condition { private final Class myInstancesClass; public InstanceOf(Class instancesClass) { myInstancesClass = instancesClass; } @Override public boolean value(Object object) { return myInstancesClass.isInstance(object); } } }