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

com.hazelcast.util.collection.LongHashSet 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.longHash;

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

    private int size;

    public LongHashSet(final int capacity, final long 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 long[arraySize];
        Arrays.fill(values, missingValue);

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

    public LongHashSet(long[] items, long missingValue) {
        this(items.length, missingValue);
        for (long item : items) {
            add(item);
        }
    }

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

    /**
     * Primitive specialised overload of {this#add(Long)}
     *
     * @param value the value to add
     * @return true if the collection has changed, false otherwise
     */
    public boolean add(final long value) {
        if (size == capacity) {
            throw new IllegalStateException("This LongHashSet of capacity " + capacity + " is full");
        }
        int index = longHash(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 Long && remove(((Long) value).longValue());
    }

    /**
     * An long 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 long value) {
        int index = longHash(value, mask);

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

            index = next(index);
        }

        return false;
    }

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

    private void compactChain(int deleteIndex) {
        final long[] values = this.values;
        int index = deleteIndex;
        while (true) {
            index = next(index);
            if (values[index] == missingValue) {
                return;
            }
            final int hash = longHash(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 Long && contains(((Long) value).longValue());
    }

    /**
     * {@inheritDoc}
     */
    public boolean contains(final long value) {
        int index = longHash(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 long[] 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);
            }
        });
    }

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

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

* 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 LongHashSet difference(final LongHashSet collection) { checkNotNull(collection); LongHashSet difference = null; final LongIterator it = iterator(); while (it.hasNext()) { final long value = it.nextValue(); if (!collection.contains(value)) { if (difference == null) { difference = new LongHashSet(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 T t : collection) { // Deliberate strict evaluation acc |= predicate.test(t); } return acc; } /** * {@inheritDoc} */ public LongIterator iterator() { iterator.reset(); return iterator; } /** * {@inheritDoc} */ public void copy(final LongHashSet 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 (long i : values) { if (i == missingValue) { continue; } b.append(separator).append(i); separator = ","; } return b.append('}').toString(); } /** * {@inheritDoc} */ public Object[] toArray() { final long[] values = this.values; final Object[] array = new Object[this.size]; int i = 0; for (long 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(Long.class)) { throw new ArrayStoreException("Cannot store Longs in array of type " + aryType); } final long[] values = this.values; final Object[] ret = into.length >= this.size ? into : (T[]) Array.newInstance(aryType, this.size); int i = 0; for (long 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 LongHashSet) { final LongHashSet otherSet = (LongHashSet) other; return otherSet.missingValue == missingValue && otherSet.size() == size() && containsAll(otherSet); } return false; } /** * {@inheritDoc} */ public int hashCode() { final LongIterator iterator = iterator(); int total = 0; while (iterator.hasNext()) { // Cast exists for substitutions total += (long) 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