/* * Copyright 2003-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 org.jetbrains.mps.util; import org.jetbrains.annotations.NotNull; import org.jetbrains.mps.openapi.language.SAbstractConcept; import org.jetbrains.mps.openapi.language.SConcept; import org.jetbrains.mps.openapi.language.SInterfaceConcept; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; /** * Iterates hierarchy of concepts, breadth-first. Iterator doesn't support removals. * Return values are not unique, e.g. if an interface is implemented by few concepts, it is reported several times. * Wrap with {@link org.jetbrains.mps.util.UniqueIterator} if necessary. * * Given * ConceptA implements I1, I2 and * ConceptB extends ConceptA implements I3, I4; * Interface I3 extends I5; * Interface I5 extends I1; * * and ConceptB as starting point, yields: * { ConceptB, I3, I4 } - level 0 for ConceptB, { ConceptA, I1, I2 } - level 1 from ConceptA , { I5 } level 1 from I3, {I1} - level 2 from I5. * * Note, this class is similar to {@link org.jetbrains.mps.openapi.language.SConceptUtil}, except for explicit walk algorithm and OOP-friendly style. * * @author Artem Tikhomirov */ public class BreadthConceptHierarchyIterator implements Iterable<SAbstractConcept>, Iterator<SAbstractConcept>{ private final Deque<SAbstractConcept> myQueue = new ArrayDeque<SAbstractConcept>(); private final SAbstractConcept myStart; public BreadthConceptHierarchyIterator(@NotNull SAbstractConcept start) { myStart = start; } @Override public Iterator<SAbstractConcept> iterator() { myQueue.clear(); myQueue.add(myStart); return this; } @Override public boolean hasNext() { return !myQueue.isEmpty(); } @Override public SAbstractConcept next() { SAbstractConcept rv = myQueue.removeFirst(); final Iterable<SInterfaceConcept> superInterfaces; final SConcept parentConcept; if (rv instanceof SInterfaceConcept) { superInterfaces = ((SInterfaceConcept) rv).getSuperInterfaces(); parentConcept = null; } else { assert rv instanceof SConcept; parentConcept = ((SConcept) rv).getSuperConcept(); superInterfaces = ((SConcept) rv).getSuperInterfaces(); } // for a concept, implemented interfaces are deemed as 'this' level, while extended concept constitutes jump to a next depth for (SAbstractConcept i : superInterfaces) { myQueue.addLast(i); } if (parentConcept != null) { myQueue.addLast(parentConcept); } return rv; } @Override public void remove() { throw new UnsupportedOperationException(); } }