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

com.flowpowered.commons.set.ConcurrentRegularEnumSet Maven / Gradle / Ivy

Go to download

A library for Java that provides re-usable components commonly used by Flow libraries.

The newest version!
/*
 * This file is part of Flow Commons, licensed under the MIT License (MIT).
 *
 * Copyright (c) 2013 Flow Powered 
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.flowpowered.commons.set;

import java.lang.reflect.Array;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicLong;

/**
 * A concurrent enum set for enums of with no greater than 64 values.
 */
public class ConcurrentRegularEnumSet> extends AbstractSet {
    private final Class enumClass;
    private final E[] enumConstants;
    private final AtomicLong set = new AtomicLong(0);

    /**
     * Constructs a new concurrent enum set from the class' enum.
     *
     * @param enumClass The class' enum
     */
    public ConcurrentRegularEnumSet(Class enumClass) {
        this.enumClass = enumClass;
        enumConstants = enumClass.getEnumConstants();
        if (enumConstants.length > 64) {
            throw new IllegalArgumentException("Max enum size is 64");
        }
    }

    @Override
    public int size() {
        return Long.bitCount(set.get());
    }

    @Override
    public boolean isEmpty() {
        return set.get() == 0;
    }

    @Override
    public boolean contains(Object o) {
        return isClass(o, enumClass) && (set.get() & getMask(o)) != 0;
    }

    @Override
    public Iterator iterator() {
        return new AtomicEnumSetIterator<>();
    }

    @Override
    @SuppressWarnings("unchecked")
    public E[] toArray() {
        final E[] array = (E[]) Array.newInstance(enumClass, enumConstants.length);
        int i = 0;
        for (int l = 0; l < enumConstants.length; l++) {
            final long mask = 1l << l;
            if ((set.get() & mask) != 0) {
                array[i++] = enumConstants[Long.numberOfTrailingZeros(mask)];
            }
        }
        final E[] finalArray = (E[]) Array.newInstance(enumClass, i);
        System.arraycopy(array, 0, finalArray, 0, i);
        return finalArray;
    }

    @Override
    public  T[] toArray(T[] a) {
        return (T[]) toArray();
    }

    @Override
    public boolean add(E e) {
        checkClass(e, enumClass);
        final long mask = getMask(e);
        boolean done = false;
        long oldSet = 0, newSet = 0;
        while (!done) {
            oldSet = set.get();
            newSet = oldSet | mask;
            done = set.compareAndSet(oldSet, newSet);
        }
        return oldSet != newSet;
    }

    @Override
    public boolean remove(Object o) {
        if (!isClass(o, enumClass)) {
            return false;
        }
        final long mask = ~getMask(o);
        boolean done = false;
        long oldSet = 0, newSet = 0;
        while (!done) {
            oldSet = set.get();
            newSet = oldSet & mask;
            done = set.compareAndSet(oldSet, newSet);
        }
        return oldSet != newSet;
    }

    @Override
    public boolean containsAll(Collection c) {
        if (!(c instanceof ConcurrentRegularEnumSet)) {
            return super.containsAll(c);
        }
        final ConcurrentRegularEnumSet other = (ConcurrentRegularEnumSet) c;
        return enumClass == other.enumClass && (other.set.get() & ~set.get()) == 0;
    }

    @Override
    public boolean addAll(Collection c) {
        if (!(c instanceof ConcurrentRegularEnumSet)) {
            return super.addAll(c);
        }
        final ConcurrentRegularEnumSet other = ((ConcurrentRegularEnumSet) c);
        if (enumClass != other.enumClass) {
            throw new ClassCastException();
        }
        boolean done = false;
        long oldSet = 0, newSet = 0;
        while (!done) {
            oldSet = set.get();
            newSet = oldSet | other.set.get();
            done = set.compareAndSet(oldSet, newSet);
        }
        return oldSet != newSet;
    }

    @Override
    public boolean retainAll(Collection c) {
        if (!(c instanceof ConcurrentRegularEnumSet)) {
            return super.retainAll(c);
        }
        final ConcurrentRegularEnumSet other = ((ConcurrentRegularEnumSet) c);
        if (enumClass != other.enumClass) {
            return false;
        }
        boolean done = false;
        long oldSet = 0, newSet = 0;
        while (!done) {
            oldSet = set.get();
            newSet = oldSet & other.set.get();
            done = set.compareAndSet(oldSet, newSet);
        }
        return oldSet != newSet;
    }

    @Override
    public boolean removeAll(Collection c) {
        if (!(c instanceof ConcurrentRegularEnumSet)) {
            return super.removeAll(c);
        }
        final ConcurrentRegularEnumSet other = ((ConcurrentRegularEnumSet) c);
        if (enumClass != other.enumClass) {
            return false;
        }
        boolean done = false;
        long oldSet = 0, newSet = 0;
        while (!done) {
            oldSet = set.get();
            newSet = oldSet & ~other.set.get();
            done = set.compareAndSet(oldSet, newSet);
        }
        return oldSet != newSet;
    }

    @Override
    public void clear() {
        set.set(0);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof ConcurrentRegularEnumSet)) {
            return false;
        }
        if (!super.equals(o)) {
            return false;
        }
        final ConcurrentRegularEnumSet that = (ConcurrentRegularEnumSet) o;
        return enumClass == that.enumClass && set.get() == that.set.get();
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + enumClass.hashCode();
        final long l = set.get();
        result = 31 * result + ((int) l ^ (int) (l >>> 32));
        return result;
    }

    private static boolean isClass(Object o, Class c) {
        return o != null && c.isAssignableFrom(o.getClass());
    }

    private static void checkClass(Object o, Class c) {
        if (!isClass(o, c)) {
            throw new ClassCastException();
        }
    }

    private static long getMask(Object o) {
        return 1l << ((Enum) o).ordinal();
    }

    private class AtomicEnumSetIterator> implements Iterator {
        private int position = 0;

        @Override
        public boolean hasNext() {
            return (set.get() & ~((1l << position) - 1)) != 0;
        }

        @Override
        @SuppressWarnings("unchecked")
        public E next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            while ((set.get() & (1l << position++)) == 0) {
            }
            return (E) enumConstants[Long.numberOfTrailingZeros(1l << position - 1)];
        }

        @Override
        public void remove() {
            if ((set.get() & ~((1l << position - 1) - 1)) == 0) {
                throw new NoSuchElementException();
            }
            boolean done = false;
            long oldSet, newSet;
            while (!done) {
                oldSet = set.get();
                newSet = oldSet & ~(1l << position - 1);
                done = set.compareAndSet(oldSet, newSet);
            }
            position--;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy