blob: b2c4fab200282222ec005b472944031bb1aaca9d [file] [log] [blame]
/*
* 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.pivot.collections;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.pivot.annotations.UnsupportedOperation;
import org.apache.pivot.util.ListenerList;
/**
* Implementation of the {@link Set} interface that is backed by an array of
* enum values.
*
* @param <E> The enum type contained in this set.
*/
public class EnumSet<E extends Enum<E>> implements Set<E>, Serializable {
private static final long serialVersionUID = 3544488357505145448L;
private class ElementIterator implements Iterator<E> {
private int i = 0;
private E next = null;
@Override
public boolean hasNext() {
if (next == null) {
while (i < elements.length && !members[i]) {
i++;
}
if (i < elements.length) {
next = elements[i];
} else {
next = null;
}
}
return (next != null);
}
@Override
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
E nextLocal = this.next;
this.next = null;
i++;
return nextLocal;
}
@Override
@UnsupportedOperation
public void remove() {
throw new UnsupportedOperationException();
}
}
private Class<E> enumClass;
private E[] elements;
private boolean[] members;
private int count = 0;
private transient SetListener.Listeners<E> setListeners = new SetListener.Listeners<>();
public EnumSet(final Class<E> enumClass) {
this.enumClass = enumClass;
elements = enumClass.getEnumConstants();
members = new boolean[elements.length];
}
public Class<E> getEnumClass() {
return enumClass;
}
@Override
public boolean add(final E element) {
boolean added = false;
int ordinal = element.ordinal();
if (!members[ordinal]) {
members[ordinal] = true;
added = true;
count++;
setListeners.elementAdded(this, element);
}
return added;
}
@Override
public boolean remove(final E element) {
boolean removed = false;
int ordinal = element.ordinal();
if (members[ordinal]) {
members[ordinal] = false;
removed = true;
count--;
setListeners.elementRemoved(this, element);
}
return removed;
}
@Override
public void clear() {
if (count > 0) {
members = new boolean[members.length];
count = 0;
setListeners.setCleared(this);
}
}
@Override
public boolean contains(final E element) {
return members[element.ordinal()];
}
@Override
public boolean isEmpty() {
return count == 0;
}
@Override
public int getCount() {
return count;
}
@Override
public Comparator<E> getComparator() {
return null;
}
@Override
@UnsupportedOperation
public void setComparator(final Comparator<E> comparator) {
throw new UnsupportedOperationException(
"Cannot set a comparator because an Enum Set is always ordered by its underlying enum.");
}
@Override
public Iterator<E> iterator() {
return new ElementIterator();
}
@Override
public ListenerList<SetListener<E>> getSetListeners() {
return setListeners;
}
/**
* Creates an empty enum set.
*
* @param <E> The enum type of the set.
* @param elementClass The class of the individual elements to be used
* in this set.
* @return The new empty set.
*/
public static <E extends Enum<E>> EnumSet<E> noneOf(final Class<E> elementClass) {
return new EnumSet<E>(elementClass);
}
/**
* Creates an enum set initially containing all the elements of the backing enum.
*
* @param <E> The enum type of the set.
* @param elementClass The class of the individual elements to be used
* in this set.
* @return The new complete set.
*/
public static <E extends Enum<E>> EnumSet<E> allOf(final Class<E> elementClass) {
EnumSet<E> set = new EnumSet<E>(elementClass);
for (E e : elementClass.getEnumConstants()) {
set.add(e);
}
return set;
}
/**
* Creates an enum set containing the given element.
*
* @param <E> The enum type of the set.
* @param e The only element to assign to the new set.
* @return The new set containing the single element.
*/
public static <E extends Enum<E>> EnumSet<E> of(final E e) {
EnumSet<E> set = new EnumSet<>(e.getDeclaringClass());
set.add(e);
return set;
}
/**
* Creates an enum set containing the given elements.
*
* @param <E> The enum type of the set.
* @param e1 The first element to add to the new set.
* @param e2 The second element to add.
* @return The new set containing only these two elements.
*/
public static <E extends Enum<E>> EnumSet<E> of(final E e1, final E e2) {
EnumSet<E> set = new EnumSet<>(e1.getDeclaringClass());
set.add(e1);
set.add(e2);
return set;
}
/**
* Creates an enum set containing the given elements.
*
* @param <E> The enum type of the set.
* @param e1 The first element to add to the new set.
* @param e2 The second element to add.
* @param e3 The third element to add.
* @return The new set containing only these three elements.
*/
public static <E extends Enum<E>> EnumSet<E> of(final E e1, final E e2, final E e3) {
EnumSet<E> set = new EnumSet<>(e1.getDeclaringClass());
set.add(e1);
set.add(e2);
set.add(e3);
return set;
}
/**
* Creates an enum set containing the given elements.
*
* @param <E> The enum type of the set.
* @param e1 The first element to add to the new set.
* @param e2 The second element to add.
* @param e3 The third element to add.
* @param e4 The fourth element to add.
* @return The new set containing only these four elements.
*/
public static <E extends Enum<E>> EnumSet<E> of(final E e1, final E e2, final E e3, final E e4) {
EnumSet<E> set = new EnumSet<>(e1.getDeclaringClass());
set.add(e1);
set.add(e2);
set.add(e3);
set.add(e4);
return set;
}
/**
* Adds all the elements of the given collection of this enum
* to this set.
*
* @param c The other collection to add to this set.
* @return Whether or not the enum set changed as a result.
*/
public boolean addAll(final Collection<E> c) {
boolean changed = false;
for (E elem : c) {
if (add(elem)) {
changed = true;
}
}
return changed;
}
}