| // ASM: a very small and fast Java bytecode manipulation framework |
| // Copyright (c) 2000-2011 INRIA, France Telecom |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions |
| // are met: |
| // 1. Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // 2. Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // 3. Neither the name of the copyright holders nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| // THE POSSIBILITY OF SUCH DAMAGE. |
| package org.apache.tapestry5.internal.plastic.asm.tree.analysis; |
| |
| import java.util.AbstractSet; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.NoSuchElementException; |
| import java.util.Set; |
| |
| /** |
| * An immutable set of at most two elements, optimized for speed compared to a generic set |
| * implementation. |
| * |
| * @author Eric Bruneton |
| */ |
| final class SmallSet<T> extends AbstractSet<T> { |
| |
| /** The first element of this set, maybe {@literal null}. */ |
| private final T element1; |
| |
| /** |
| * The second element of this set, maybe {@literal null}. If {@link #element1} is {@literal null} |
| * then this field must be {@literal null}, otherwise it must be different from {@link #element1}. |
| */ |
| private final T element2; |
| |
| // ----------------------------------------------------------------------------------------------- |
| // Constructors |
| // ----------------------------------------------------------------------------------------------- |
| |
| /** Constructs an empty set. */ |
| SmallSet() { |
| this.element1 = null; |
| this.element2 = null; |
| } |
| |
| /** |
| * Constructs a set with exactly one element. |
| * |
| * @param element the unique set element. |
| */ |
| SmallSet(final T element) { |
| this.element1 = element; |
| this.element2 = null; |
| } |
| |
| /** |
| * Constructs a new {@link SmallSet}. |
| * |
| * @param element1 see {@link #element1}. |
| * @param element2 see {@link #element2}. |
| */ |
| private SmallSet(final T element1, final T element2) { |
| this.element1 = element1; |
| this.element2 = element2; |
| } |
| |
| // ----------------------------------------------------------------------------------------------- |
| // Implementation of the inherited abstract methods |
| // ----------------------------------------------------------------------------------------------- |
| |
| @Override |
| public Iterator<T> iterator() { |
| return new IteratorImpl<>(element1, element2); |
| } |
| |
| @Override |
| public int size() { |
| if (element1 == null) { |
| return 0; |
| } else if (element2 == null) { |
| return 1; |
| } else { |
| return 2; |
| } |
| } |
| |
| // ----------------------------------------------------------------------------------------------- |
| // Utility methods |
| // ----------------------------------------------------------------------------------------------- |
| |
| /** |
| * Returns the union of this set and of the given set. |
| * |
| * @param otherSet another small set. |
| * @return the union of this set and of otherSet. |
| */ |
| Set<T> union(final SmallSet<T> otherSet) { |
| // If the two sets are equal, return this set. |
| if ((otherSet.element1 == element1 && otherSet.element2 == element2) |
| || (otherSet.element1 == element2 && otherSet.element2 == element1)) { |
| return this; |
| } |
| // If one set is empty, return the other. |
| if (otherSet.element1 == null) { |
| return this; |
| } |
| if (element1 == null) { |
| return otherSet; |
| } |
| |
| // At this point we know that the two sets are non empty and are different. |
| // If otherSet contains exactly one element: |
| if (otherSet.element2 == null) { |
| // If this set also contains exactly one element, we have two distinct elements. |
| if (element2 == null) { |
| return new SmallSet<>(element1, otherSet.element1); |
| } |
| // If otherSet is included in this set, return this set. |
| if (otherSet.element1 == element1 || otherSet.element1 == element2) { |
| return this; |
| } |
| } |
| // If this set contains exactly one element, then otherSet contains two elements (because of the |
| // above tests). Thus, if otherSet contains this set, return otherSet: |
| if (element2 == null && (element1 == otherSet.element1 || element1 == otherSet.element2)) { |
| return otherSet; |
| } |
| |
| // At this point we know that there are at least 3 distinct elements, so we need a generic set |
| // to store the result. |
| HashSet<T> result = new HashSet<>(4); |
| result.add(element1); |
| if (element2 != null) { |
| result.add(element2); |
| } |
| result.add(otherSet.element1); |
| if (otherSet.element2 != null) { |
| result.add(otherSet.element2); |
| } |
| return result; |
| } |
| |
| static class IteratorImpl<T> implements Iterator<T> { |
| |
| /** The next element to return in {@link #next}. Maybe {@literal null}. */ |
| private T firstElement; |
| |
| /** |
| * The element to return in {@link #next}, after {@link #firstElement} is returned. If {@link |
| * #firstElement} is {@literal null} then this field must be {@literal null}, otherwise it must |
| * be different from {@link #firstElement}. |
| */ |
| private T secondElement; |
| |
| IteratorImpl(final T firstElement, final T secondElement) { |
| this.firstElement = firstElement; |
| this.secondElement = secondElement; |
| } |
| |
| @Override |
| public boolean hasNext() { |
| return firstElement != null; |
| } |
| |
| @Override |
| public T next() { |
| if (firstElement == null) { |
| throw new NoSuchElementException(); |
| } |
| T element = firstElement; |
| firstElement = secondElement; |
| secondElement = null; |
| return element; |
| } |
| |
| @Override |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| } |
| } |