OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 17 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
 * 
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each file.
 */
 
 package org.openconcerto.utils.cc;

import java.util.AbstractSet;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Iterator;

/**
 * This class implements the <tt>Set</tt> interface with a hash table, using reference-equality in
 * place of object-equality when comparing items. In other words, in an <tt>IdentityHashSet</tt>,
 * two keys <tt>k1</tt> and <tt>k2</tt> are considered equal if and only if <tt>(k1==k2)</tt>. (In
 * normal <tt>Set</tt> implementations (like <tt>HashSet</tt>) two keys <tt>k1</tt> and <tt>k2</tt>
 * are considered equal if and only if <tt>(k1==null ? k2==null : k1.equals(k2))</tt>.)
 * 
 * @param <E> the type of elements maintained by this set
 */
public final class IdentityHashSet<E> extends AbstractSet<E> implements IdentitySet<E>, Cloneable {

    static private final Object VALUE = new Object();

    private final IdentityHashMap<E, Object> map;

    public IdentityHashSet() {
        this.map = new IdentityHashMap<E, Object>();
    }

    public IdentityHashSet(int expectedMaxSize) {
        this.map = new IdentityHashMap<E, Object>(expectedMaxSize);
    }

    public IdentityHashSet(Collection<? extends E> c) {
        this.map = new IdentityHashMap<E, Object>(Math.max((int) (c.size() / .75f) + 1, 16));
        this.addAll(c);
    }

    @Override
    public boolean add(E e) {
        return this.map.put(e, VALUE) != VALUE;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        // let the super which calls add() since we don't want to build a map to use Map.addAll()
        return super.addAll(c);
    }

    @Override
    public void clear() {
        this.map.clear();
    }

    @Override
    public int size() {
        return this.map.size();
    }

    @Override
    public boolean isEmpty() {
        return this.map.isEmpty();
    }

    @Override
    public Iterator<E> iterator() {
        return this.map.keySet().iterator();
    }

    @Override
    public boolean contains(Object o) {
        return this.map.containsKey(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return this.map.keySet().containsAll(c);
    }

    @Override
    public boolean remove(Object o) {
        return this.map.remove(o) == VALUE;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return this.map.keySet().removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return this.map.keySet().retainAll(c);
    }

    @Override
    public Object[] toArray() {
        return this.map.keySet().toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return this.map.keySet().toArray(a);
    }

    // use System.identityHashCode()
    @Override
    public int hashCode() {
        return this.map.keySet().hashCode();
    }

    // equals() uses containsAll which is correct

    /**
     * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements themselves are not
     * cloned.
     * 
     * @return a shallow copy of this set
     */
    public Object clone() {
        return new IdentityHashSet<E>(this);
    }

}