/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection.sets;

import java.util.Collection;
import java.util.Iterator;
import net.ranides.assira.collection.arrays.ArrayAllocator;
import net.ranides.assira.collection.utils.HashCollection;
import net.ranides.assira.generic.CompareUtils;

/**
 * A generic set map implementation.
 */
public final class HashSet<K> extends AHashSet<K> {

    private static final long serialVersionUID = 3L;
    
    /**
     * Creates a new hash set.
     *
     * <p>The actual table size will be the least power of two greater than
     * <code>expected</code>/
     * <code>f</code>.
     *
     * @param expected the expected number of elements in the hash set.
     * @param f the load factor.
     */
    @SuppressWarnings("unchecked")
    public HashSet(int expected, float factor) {
        super(expected, factor);
    }

    /**
     * Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load
     * factor.
     *
     * @param expected the expected number of elements in the hash set.
     */
    public HashSet(int expected) {
        this(expected, HashCollection.LOAD_FACTOR);
    }

    /**
     * Creates a new hash set with initial expected
     * {@link Hash#DEFAULT_INITIAL_SIZE} elements and
     * {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
     */
    public HashSet() {
        this(HashCollection.INITIAL_SIZE, HashCollection.LOAD_FACTOR);
    }

    /**
     * Creates a new hash set copying a given collection.
     *
     * @param values a {@link Collection} to be copied into the new hash set.
     * @param factor the load factor.
     */
    public HashSet(Collection<? extends K> values, float factor) {
        this(values.size(), factor);
        addAll(values);
    }

    /**
     * Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load
     * factor copying a given collection.
     *
     * @param values a {@link Collection} to be copied into the new hash set.
     */
    public HashSet(Collection<? extends K> values) {
        this(values, HashCollection.LOAD_FACTOR);
    }

    /**
     * Creates a new hash set using elements provided by a type-specific
     * iterator.
     *
     * @param iterator a type-specific iterator whose elements will fill the set.
     * @param factor the load factor.
     */
    public HashSet(Iterator<K> iterator, float factor) {
        this(HashCollection.INITIAL_SIZE, factor);
        while (iterator.hasNext()) {
            add(iterator.next());
        }
    }

    /**
     * Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load
     * factor using elements provided by a type-specific iterator.
     *
     * @param iterator a type-specific iterator whose elements will fill the set.
     */
    public HashSet(Iterator<K> iterator) {
        this(iterator, HashCollection.LOAD_FACTOR);
    }

    /**
     * Creates a new hash set and fills it with the elements of a given array.
     *
     * @param keys an array whose elements will be used to fill the set.
     * @param offset the first element to use.
     * @param length the number of elements to use.
     * @param factor the load factor.
     */
    public HashSet(K[] keys, int offset, int length, float factor) {
        this(length < 0 ? 0 : length, factor);
        ArrayAllocator.ensureOffsetLength(keys, offset, length);
        for (int i = 0; i < length; i++) {
            add(keys[ offset + i]);
        }
    }

    /**
     * Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load
     * factor and fills it with the elements of a given array.
     *
     * @param keys an array whose elements will be used to fill the set.
     * @param offset the first element to use.
     * @param length the number of elements to use.
     */
    public HashSet(K[] keys, int offset, int length) {
        this(keys, offset, length, HashCollection.LOAD_FACTOR);
    }

    /**
     * Creates a new hash set copying the elements of an array.
     *
     * @param keys an array to be copied into the new hash set.
     * @param factor the load factor.
     */
    public HashSet(K[] keys, float factor) {
        this(keys, 0, keys.length, factor);
    }

    /**
     * Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load
     * factor copying the elements of an array.
     *
     * @param keys an array to be copied into the new hash set.
     */
    public HashSet(K[] keys) {
        this(keys, HashCollection.LOAD_FACTOR);
    }

    @Override
    protected int hash(K key) {
        return key.hashCode();
    }

    @Override
    protected boolean compare(K key1, K key2) {
        return CompareUtils.equals(key1, key2);
    }

}
