| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.flex.compiler.common; |
| |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.NoSuchElementException; |
| |
| |
| /** |
| * Stores the set of dependency types for an edge in the dependency graph. |
| * <p> |
| * The APIs of this class are similar to that of <code>EnumSet<DependencyType></code>. |
| * Instead of using an <code>EnumSet</code>, we use this smaller |
| * class which stores the dependencies as bitflags in a <code>int</code> field. |
| * <p> |
| * This class was originally designed to handle the fact that we shouldn't need |
| * to keep track of each type of dependency on each edge: if an edge has a more |
| * important dependency type we should be able to ignore the fact that it also has |
| * a less important dependency type. The idea was that this would reduce the size |
| * of the SWC catalog. |
| * <p> |
| * The <code>add()</code> was originally a bottleneck which added a dependency type |
| * to the set, and then cleaned up the set by removing lesser dependency types that |
| * are trumped by greater ones. (<code>SIGNATURE</code> trumped <code>EXPRESSION</code>; |
| * <code>INHERITANCE</code> trumped all others.) But this meant that APIs like |
| * <code>allOf()</code> didn't actually create a set that contained all the types, |
| * Although everything seemed to work, it seemed too dangerous given the way that |
| * sets are used for filtering of edges. |
| * <p>Therefore that "trumping" logic has moved to the SWC catalog writer and this |
| * class is merely a optimization. |
| */ |
| public final class DependencyTypeSet implements Iterable<DependencyType> |
| { |
| private static DependencyType[] DEPENDENCY_TYPES = DependencyType.values(); |
| |
| /** |
| * Constructs a new empty set. |
| * |
| * @return The new {@link DependencyTypeSet}. |
| */ |
| public static DependencyTypeSet noneOf() |
| { |
| return new DependencyTypeSet(); |
| } |
| |
| /** |
| * Constructs a new set with each type of dependency. |
| * |
| * @return The new {@link DependencyTypeSet}. |
| */ |
| public static DependencyTypeSet allOf() |
| { |
| DependencyTypeSet typeSet = new DependencyTypeSet(); |
| for (DependencyType type : DEPENDENCY_TYPES) |
| { |
| typeSet.add(type); |
| } |
| return typeSet; |
| } |
| |
| /** |
| * Constructs a new set with the specified dependency types in it. |
| * |
| * @param types Zero or more parameters, each of which is a {@link DependencyType}. |
| * @return The new {@link DependencyTypeSet}. |
| */ |
| public static DependencyTypeSet of(DependencyType ... types) |
| { |
| DependencyTypeSet typeSet = new DependencyTypeSet(); |
| for (DependencyType type : types) |
| { |
| typeSet.add(type); |
| } |
| return typeSet; |
| } |
| |
| /** |
| * Constructs a new set with the specified collection of dependency |
| * types in it. |
| * |
| * @param dependencyTypeCollection A collection of {@link DependencyType}s. |
| * @return The new {@link DependencyTypeSet}. |
| */ |
| public static DependencyTypeSet copyOf(Collection<DependencyType> dependencyTypeCollection) |
| { |
| DependencyTypeSet typeSet = new DependencyTypeSet(); |
| for (DependencyType type : dependencyTypeCollection) |
| { |
| typeSet.add(type); |
| } |
| return typeSet; |
| } |
| |
| /** |
| * Constructs a copy of another {@link DependencyTypeSet}. |
| * |
| * @param otherTypeSet The {@link DependencyTypeSet} to copy. |
| * @return The new {@link DependencyTypeSet}. |
| */ |
| public static DependencyTypeSet copyOf(DependencyTypeSet otherTypeSet) |
| { |
| DependencyTypeSet typeSet = new DependencyTypeSet(); |
| typeSet.flags = otherTypeSet.flags; |
| return typeSet; |
| } |
| |
| /** |
| * Private constructor. |
| * <p> |
| * Use one of the static method to construct an instance. |
| */ |
| private DependencyTypeSet() |
| { |
| } |
| |
| // The lowest four bits of this field are flags for INHERITANCE (0), |
| // SIGNATURE (1), NAMESPACE (2), and EXPRESSION (4). |
| // The bit position is the ordinal of the enum. |
| private int flags; |
| |
| @Override |
| public Iterator<DependencyType> iterator() |
| { |
| return new Iterator<DependencyType>() |
| { |
| // Bit position of the DependencyType flag that next() |
| // last returned. |
| private int i = -1; |
| |
| @Override |
| public boolean hasNext() |
| { |
| // Increment i until it points at a bit which is set |
| // or until we're past all the flag bits. |
| int bit = getNextBit(i + 1); |
| return bit < DEPENDENCY_TYPES.length; |
| } |
| |
| @Override |
| public DependencyType next() |
| { |
| i = getNextBit(i + 1); |
| if (i < DEPENDENCY_TYPES.length) |
| return DEPENDENCY_TYPES[i]; |
| |
| throw new NoSuchElementException(); |
| } |
| |
| private int getNextBit(int startingBit) |
| { |
| int nextBit = startingBit; |
| while (nextBit < DEPENDENCY_TYPES.length) |
| { |
| int mask = 1 << nextBit; |
| if ((flags & mask) != 0) |
| break; |
| nextBit++; |
| } |
| |
| return nextBit; |
| } |
| |
| @Override |
| public void remove() |
| { |
| assert false: "This should never get called"; |
| } |
| }; |
| } |
| |
| /** |
| * Determines if the set is empty. |
| * |
| * @return <code>true</code> if the set is empty. |
| */ |
| public boolean isEmpty() |
| { |
| return flags == 0; |
| } |
| |
| /** |
| * Adds a dependency type to the set. |
| |
| * @param dependencyType The {@link DependencyType} to be |
| * added to the set. |
| */ |
| public void add(DependencyType dependencyType) |
| { |
| int mask = 1 << dependencyType.ordinal(); |
| flags |= mask; |
| } |
| |
| /** |
| * Adds the dependencies in another set to this set. |
| * |
| * @param otherSet The other {@link DependencyTypeSet}. |
| */ |
| public void addAll(DependencyTypeSet otherSet) |
| { |
| for (DependencyType type : otherSet) |
| { |
| add(type); |
| } |
| } |
| |
| /** |
| * Determines whether this set contains the specified |
| * dependency type. |
| |
| * @param dependencyType A {@link DependencyType}. |
| * @return <code>true</code> if this set contains |
| * that dependency type. |
| */ |
| public boolean contains(DependencyType dependencyType) |
| { |
| int mask = 1 << dependencyType.ordinal(); |
| return (flags & mask) != 0; |
| } |
| |
| /** |
| * For debugging only. |
| * <p> |
| * @return A String like <code>"[ NAMESPACE EXPRESSION ]"</code> |
| * representing the dependency types in this set. |
| */ |
| @Override |
| public String toString() |
| { |
| StringBuilder sb = new StringBuilder(); |
| sb.append('['); |
| sb.append(' '); |
| for (DependencyType type : DependencyType.values()) |
| { |
| if (contains(type)) |
| { |
| sb.append(type.name()); |
| sb.append(' '); |
| } |
| } |
| sb.append(']'); |
| return sb.toString(); |
| } |
| } |