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

com.hazelcast.util.collection.IntHashSet Maven / Gradle / Ivy

There is a newer version: 5.4.0
Show newest version
/*
 * Original work Copyright 2015 Real Logic Ltd.
 * Modified work Copyright (c) 2015, Hazelcast, Inc. All Rights Reserved.
 *
 * 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 com.hazelcast.util.collection;

import com.hazelcast.util.function.Predicate;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;

import static com.hazelcast.util.Preconditions.checkNotNull;
import static com.hazelcast.util.Preconditions.checkTrue;
import static com.hazelcast.util.QuickMath.nextPowerOfTwo;
import static com.hazelcast.util.collection.Hashing.intHash;

/**
 * Simple fixed-size int hashset.
 */
public final class IntHashSet implements Set {
    /** Maximum supported capacity */
    @SuppressWarnings("checkstyle:magicnumber")
    public static final int MAX_CAPACITY = 1 << 29;
    private final int[] values;
    private final IntIterator iterator;
    private final int capacity;
    private final int mask;
    private final int missingValue;

    private int size;

    public IntHashSet(final int capacity, final int missingValue) {
        checkTrue(capacity <= MAX_CAPACITY, "Maximum capacity is 2^29");
        this.capacity = capacity;
        size = 0;
        this.missingValue = missingValue;
        final int arraySize = nextPowerOfTwo(2 * capacity);
        mask = arraySize - 1;
        values = new int[arraySize];
        Arrays.fill(values, missingValue);

        // NB: references values in the constructor, so must be assigned after values
        iterator = new IntIterator(missingValue, values);
    }

    /**
     * {@inheritDoc}
     */
    public boolean add(final Integer value) {
        return add(value.intValue());
    }

    /**
     * Primitive specialised overload of {this#add(Integer)}
     *
     * @param value the value to add
     * @return true if the collection has changed, false otherwise
     */
    public boolean add(final int value) {
        if (size == capacity) {
            throw new IllegalStateException("This IntHashSet of capacity " + capacity + " is full");
        }
        int index = intHash(value, mask);

        while (values[index] != missingValue) {
            if (values[index] == value) {
                return false;
            }

            index = next(index);
        }

        values[index] = value;
        size++;

        return true;
    }

    /**
     * {@inheritDoc}
     */
    public boolean remove(final Object value) {
        return value instanceof Integer && remove(((Integer) value).intValue());
    }

    /**
     * An int specialised version of {this#remove(Object)}.
     *
     * @param value the value to remove
     * @return true if the value was present, false otherwise
     */
    public boolean remove(final int value) {
        int index = intHash(value, mask);

        while (values[index] != missingValue) {
            if (values[index] == value) {
                values[index] = missingValue;
                compactChain(index);
                return true;
            }

            index = next(index);
        }

        return false;
    }

    private int next(int index) {
        index = ++index & mask;
        return index;
    }

    private void compactChain(int deleteIndex) {
        final int[] values = this.values;
        int index = deleteIndex;
        while (true) {
            index = next(index);
            if (values[index] == missingValue) {
                return;
            }
            final int hash = intHash(values[index], mask);
            if ((index < hash && (hash <= deleteIndex || deleteIndex <= index))
                    || (hash <= deleteIndex && deleteIndex <= index)
            ) {
                values[deleteIndex] = values[index];
                values[index] = missingValue;
                deleteIndex = index;
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean contains(final Object value) {
        return value instanceof Integer && contains(((Integer) value).intValue());
    }

    /**
     * {@inheritDoc}
     */
    public boolean contains(final int value) {
        int index = intHash(value, mask);

        while (values[index] != missingValue) {
            if (values[index] == value) {
                return true;
            }

            index = next(index);
        }

        return false;
    }

    /**
     * {@inheritDoc}
     */
    public int size() {
        return size;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isEmpty() {
        return size() == 0;
    }

    /**
     * {@inheritDoc}
     */
    public void clear() {
        final int[] values = this.values;
        final int length = values.length;
        for (int i = 0; i < length; i++) {
            values[i] = missingValue;
        }
        size = 0;
    }

    /**
     * {@inheritDoc}
     */
    public boolean addAll(final Collection coll) {
        return addAllCapture(coll);
    }

    private  boolean addAllCapture(final Collection coll) {
        final Predicate p = new Predicate() {
            @Override
            public boolean test(E x) {
                return add(x);
            }
        };
        return conjunction(coll, p);
    }

    /**
     * {@inheritDoc}
     */
    public boolean containsAll(final Collection coll) {
        return containsAllCapture(coll);
    }

    private  boolean containsAllCapture(Collection coll) {
        return conjunction(coll, new Predicate() {
            @Override public boolean test(E value) {
                return contains(value);
            }
        });
    }

    /**
     * IntHashSet specialised variant of {this#containsAll(Collection)}.
     *
     * @param other the int hashset to compare against.
     * @return true if every element in other is in this.
     */
    public boolean containsAll(final IntHashSet other) {
        final IntIterator iterator = other.iterator();
        while (iterator.hasNext()) {
            if (!contains(iterator.nextValue())) {
                return false;
            }
        }
        return true;
    }

    /**
     * Fast Path set difference for comparison with another IntHashSet.
     * 

* NB: garbage free in the identical case, allocates otherwise. * * @param collection the other set to subtract * @return null if identical, otherwise the set of differences */ public IntHashSet difference(final IntHashSet collection) { checkNotNull(collection, "Collection must not be null"); IntHashSet difference = null; final IntIterator it = iterator(); while (it.hasNext()) { final int value = it.nextValue(); if (!collection.contains(value)) { if (difference == null) { difference = new IntHashSet(size, missingValue); } difference.add(value); } } return difference; } /** * {@inheritDoc} */ public boolean removeAll(final Collection coll) { return removeAllCapture(coll); } private boolean removeAllCapture(final Collection coll) { return conjunction(coll, new Predicate() { @Override public boolean test(E value) { return remove(value); } }); } private static boolean conjunction(final Collection collection, final Predicate predicate) { checkNotNull(collection); boolean acc = false; for (final E e : collection) { // Deliberate strict evaluation acc |= predicate.test(e); } return acc; } /** * {@inheritDoc} */ public IntIterator iterator() { iterator.reset(); return iterator; } /** * {@inheritDoc} */ public void copy(final IntHashSet obj) { // NB: mask also implies the length is the same if (this.mask != obj.mask) { throw new IllegalArgumentException("Cannot copy object: masks not equal"); } if (this.missingValue != obj.missingValue) { throw new IllegalArgumentException("Cannot copy object: missingValues not equal"); } System.arraycopy(obj.values, 0, this.values, 0, this.values.length); this.size = obj.size; } /** * {@inheritDoc} */ public String toString() { final StringBuilder b = new StringBuilder(size() * 3 + 2); b.append('{'); String separator = ""; for (int i : values) { b.append(i).append(separator); separator = ","; } return b.append('}').toString(); } /** * {@inheritDoc} */ public Object[] toArray() { final int[] values = this.values; final Object[] array = new Object[this.size]; int i = 0; for (int value : values) { if (value != missingValue) { array[i++] = value; } } return array; } /** * {@inheritDoc} */ @SuppressWarnings("unchecked") public T[] toArray(T[] into) { checkNotNull(into); final Class aryType = into.getClass().getComponentType(); if (!aryType.isAssignableFrom(Integer.class)) { throw new ArrayStoreException("Cannot store Integers in array of type " + aryType); } final int[] values = this.values; final Object[] ret = into.length >= this.size ? into : (T[]) Array.newInstance(aryType, this.size); int i = 0; for (int value : values) { if (value != missingValue) { ret[i++] = value; } } if (ret.length > this.size) { ret[values.length] = null; } return (T[]) ret; } /** * {@inheritDoc} */ public boolean equals(final Object other) { if (other == this) { return true; } if (other instanceof IntHashSet) { final IntHashSet otherSet = (IntHashSet) other; return otherSet.missingValue == missingValue && otherSet.size() == size() && containsAll(otherSet); } return false; } /** * {@inheritDoc} */ public int hashCode() { final IntIterator iterator = iterator(); int total = 0; while (iterator.hasNext()) { // Cast exists for substitutions total += (int) iterator.nextValue(); } return total; } // --- Unimplemented below here public boolean retainAll(final Collection coll) { throw new UnsupportedOperationException("Not implemented"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy