All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.common.flags.Flags Maven / Gradle / Ivy

There is a newer version: 62
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2018 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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.wildfly.common.flags;

import static java.lang.Integer.bitCount;
import static java.lang.Integer.highestOneBit;
import static java.lang.Integer.lowestOneBit;
import static java.lang.Integer.numberOfTrailingZeros;

import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.function.Consumer;

import org.wildfly.common.Assert;

/**
 * A base class for implementing value-like flags and flag sets, where flags and flag sets may be used without allocation
 * overhead.
 * 

*/ public abstract class Flags, This extends Flags> extends AbstractSet implements SortedSet { final int bits; /** * Construct a new instance. This constructor should only be called during initial array construction. * * @param bits the bits of this set */ protected Flags(final int bits) { this.bits = bits; } /** * Get the set value of the given bit combination. The bit combination may contain extraneous one-bits so * any bits beyond the bit of the last flag should be masked off if an array is used for lookup. * * @param bits the bit combination (possibly with extra bits) * @return the set instance */ protected abstract This value(int bits); /** * Return {@code this}. * * @return {@code this} */ protected abstract This this_(); /** * Get the flag item with the given index. * * @param index the index * @return the flag */ protected abstract E itemOf(int index); /** * Get the item (cast to the correct {@code enum} type), or {@code null} if it is not of the correct type. * * @param obj the object to cast * @return the cast object, or {@code null} */ protected abstract E castItemOrNull(Object obj); /** * Cast the given object to this class, throwing an exception if the cast fails. * * @param obj the object to cast * @return the cast object */ protected abstract This castThis(Object obj); /** * Get the size of the flag set. * * @return the flag set size */ public final int size() { return bitCount(bits); } /** * Get the first flag in the set. * * @return the first flag */ public final E first() { final int bits = this.bits; if (bits == 0) throw new NoSuchElementException(); return itemOf(numberOfTrailingZeros(lowestOneBit(bits))); } /** * Get the last flag in the set. * * @return the last flag */ public final E last() { final int bits = this.bits; if (bits == 0) throw new NoSuchElementException(); return itemOf(numberOfTrailingZeros(highestOneBit(bits))); } /** * Get the {@code null} comparator, indicating that this set is always sorted in natural order. * * @return {@code null} */ public final Comparator comparator() { return null; } /** * Determine if this flag set is empty. * * @return {@code true} if the flag set is empty, {@code false} otherwise */ public boolean isEmpty() { return bits == 0; } /** * Get the subset of flags from this set, up to (but not including) the given element. * * @param toElement the "to" element (must not be {@code null}) * @return the subset */ public final This headSet(final E toElement) { Assert.checkNotNullParam("toElement", toElement); return value(bits & bitOf(toElement) - 1); } /** * Get the subset of flags from this set, starting from the given element. * * @param fromElement the "from" element (must not be {@code null}) * @return the subset */ public final This tailSet(final E fromElement) { Assert.checkNotNullParam("fromElement", fromElement); return value(bits & ~(bitOf(fromElement) - 1)); } /** * Get the subset of flags, starting from {@code fromElement} up to (but not including) {@code toElement}. * * @param fromElement the "from" element (must not be {@code null}) * @param toElement the "to" element (must not be {@code null}) * @return the subset */ public final This subSet(final E fromElement, final E toElement) { Assert.checkNotNullParam("fromElement", fromElement); Assert.checkNotNullParam("toElement", toElement); return value(bits & (bitOf(toElement) - 1) & ~(bitOf(fromElement) - 1)); } /** * Get an {@code Object} array containing all the flag values of this set. * * @return the {@code Object} array */ public final Object[] toArray() { int b = bits; final Object[] array = new Object[bitCount(b)]; int idx = 0; while (bitCount(b) > 0) { final int lob = lowestOneBit(b); array[idx + 1] = itemOf(numberOfTrailingZeros(lob)); b ^= lob; } return array; } /** * Get a typed array containing all the flag values of this set. * * @param array the array to populate or clone * @param the element type * @return the populated array */ @SuppressWarnings("unchecked") public final T[] toArray(T[] array) { int b = bits; final int size = bitCount(b); if (size > array.length) { array = Arrays.copyOf(array, size); } int idx = 0; while (bitCount(b) > 0) { final int lob = lowestOneBit(b); array[idx + 1] = (T) itemOf(numberOfTrailingZeros(lob)); b ^= lob; } return array; } /** * Determine if this flag set contains the given flag. * * @param flag the flag * @return {@code true} if the flag is contained by this set */ public final boolean contains(E flag) { return flag != null && (bits & bitOf(flag)) != 0; } /** * Determine if this flag set contains the given object. * * @param o the object * @return {@code true} if the object is contained by this set */ public final boolean contains(final Object o) { return contains(castItemOrNull(o)); } /** * Determine if this flag set contains all of the objects in the given collection. * * @param c the collection * @return {@code true} if all of the collection's objects are contained by this set */ public final boolean containsAll(final Collection c) { if (c.getClass() == getClass()) { return containsAll(castThis(c)); } else { for (Object o : c) { if (! contains(o)) return false; } return true; } } /** * Determine if this flag set contains all of the flags in the given flag set. * * @param other the flag set * @return {@code true} if all of the given set's flags are contained by this set */ public final boolean containsAll(This other) { final int otherBits = other.bits; return (this.bits & otherBits) == otherBits; } /** * Determine if this flag set contains all of the given flags. * * @param flag1 the first flag * @param flag2 the second flag * @return {@code true} if all of the given flags are contained by this set */ public final boolean containsAll(E flag1, E flag2) { return contains(flag1) && contains(flag2); } /** * Determine if this flag set contains all of the given flags. * * @param flag1 the first flag * @param flag2 the second flag * @param flag3 the third flag * @return {@code true} if all of the given flags are contained by this set */ public final boolean containsAll(E flag1, E flag2, E flag3) { return containsAll(flag1, flag2) && contains(flag3); } /** * Determine if this flag set contains any of the flags in the given flag set. * * @param other the flag set * @return {@code true} if all of the given set's flags are contained by this set */ public final boolean containsAny(This other) { return other != null && (bits & other.bits) != 0; } /** * Determine if this flag set contains any of the given flags. * * @param flag1 the first flag * @param flag2 the second flag * @return {@code true} if any of the given flags are contained by this set */ public final boolean containsAny(E flag1, E flag2) { return contains(flag1) || contains(flag2); } /** * Determine if this flag set contains any of the given flags. * * @param flag1 the first flag * @param flag2 the second flag * @param flag3 the third flag * @return {@code true} if any of the given flags are contained by this set */ public final boolean containsAny(E flag1, E flag2, E flag3) { return containsAny(flag1, flag2) || contains(flag3); } /** * Get the complement of this set. * * @return the complement of this set */ public final This complement() { return value(~bits); } /** * Return a set which includes all of the flags in this set and the given additional flag. * * @param flag the additional flag * @return the combined set */ public final This with(E flag) { return flag == null ? this_() : value(bits | bitOf(flag)); } /** * Return a set which includes all of the flags in this set and the given additional flags. * * @param flag1 the first flag * @param flag2 the second flag * @return the combined set */ public final This with(E flag1, E flag2) { return with(flag1).with(flag2); } /** * Return a set which includes all of the flags in this set and the given additional flags. * * @param flag1 the first flag * @param flag2 the second flag * @param flag3 the third flag * @return the combined set */ public final This with(E flag1, E flag2, E flag3) { return with(flag1, flag2).with(flag3); } /** * Return a set which includes all of the flags in this set and the given additional flags. * * @param flags the additional flags * @return the combined set */ @SafeVarargs public final This with(E... flags) { if (flags == null) return this_(); int b = bits; for (E flag : flags) { if (flag != null) b |= bitOf(flag); } return value(b); } /** * Return a set which includes all of the flags in this set and the given additional flags. * * @param other the additional flags * @return the combined set */ public final This with(This other) { return other == null ? this_() : value(bits | other.bits); } /** * Return a set which includes all of the flags except for the given flag. * * @param flag the flag * @return the reduced set */ public final This without(E flag) { return flag == null ? this_() : value(bits & ~bitOf(flag)); } /** * Return a set which includes all of the flags except for the given flags. * * @param other the flags * @return the reduced set */ public final This without(This other) { return other == null ? this_() : value(bits & ~other.bits); } /** * Determine if this flag set is equal to the given object. * * @param o the other object * @return {@code true} if the object is equal to this set, {@code false} otherwise */ public final boolean equals(final Object o) { return o == this || o instanceof Set && equals((Set) o); } /** * Determine if this flag set is equal to the given set. * * @param o the other set * @return {@code true} if the set is equal to this set, {@code false} otherwise */ public final boolean equals(final Set o) { return o == this || o.containsAll(this) && containsAll(o); } /** * Determine if this flag set is equal to the given flag set. * * @param o the other flag set * @return {@code true} if the flag set is equal to this set, {@code false} otherwise */ public final boolean equals(final This o) { return o == this; } /** * Get the hash code of this flag set. * * @return the flag set hash code */ public final int hashCode() { int hc = 0; int b = this.bits; while (b != 0) { int lob = lowestOneBit(b); hc += itemOf(numberOfTrailingZeros(lob)).hashCode(); b ^= lob; } return hc; } /** * Iterate this set in order from first to last flag. * * @return the iterator */ public final Iterator iterator() { return new Iterator() { int b = bits; public boolean hasNext() { return b != 0; } public E next() { int b = this.b; if (b == 0) throw new NoSuchElementException(); final int lob = lowestOneBit(b); final E item = itemOf(numberOfTrailingZeros(lob)); this.b = b ^ lob; return item; } }; } /** * Iterate this set in order from last to first flag. * * @return the iterator */ public final Iterator descendingIterator() { return new Iterator() { int b = bits; public boolean hasNext() { return b != 0; } public E next() { int b = this.b; if (b == 0) throw new NoSuchElementException(); final int hob = highestOneBit(b); final E item = itemOf(numberOfTrailingZeros(hob)); this.b = b ^ hob; return item; } }; } /** * Apply the given action for every flag in this set. * * @param action the action to apply */ public void forEach(final Consumer action) { Assert.checkNotNullParam("action", action); int b = this.bits; while (b != 0) { int lob = lowestOneBit(b); action.accept(itemOf(numberOfTrailingZeros(lob))); b = b ^ lob; } } /** * Get a string representation of this flag set. * * @return the string representation */ public final String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()).append('['); int lob; int bits = this.bits; if (bits != 0) { lob = lowestOneBit(bits); buf.append(itemOf(numberOfTrailingZeros(lob))); bits ^= lob; while (bits != 0) { buf.append(' '); lob = lowestOneBit(bits); buf.append(itemOf(numberOfTrailingZeros(lob))); bits ^= lob; } } buf.append(']'); return buf.toString(); } private static int bitOf(Enum item) { return 1 << item.ordinal(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy