/*
* Copyright (c) Fabien Hermenier
*
* This file is part of Entropy.
*
* Entropy is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Entropy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Entropy. If not, see <http://www.gnu.org/licenses/>.
*/
package entropy.configuration;
import gnu.trove.map.hash.TIntObjectHashMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Basic implementation of a ManagedElementSet.
* {@code add()},{@code addAll()}, {@code contains()}, , {@code get()}, , {@code set()} operations
* are performed in an almost constant time.
* {@code remove()}, {@code removeAll()} operations are in a constant time if the element is not in the set.
* O(n) otherwise
*
* @author Fabien Hermenier
*/
public class SimpleManagedElementSet<E extends ManagedElement> extends ArrayList<E> implements ManagedElementSet<E>, Cloneable {
private TIntObjectHashMap<E> map;
/**
* Make a singleton.
*
* @param e the element in the singleton.
*/
public SimpleManagedElementSet(E e) {
this();
this.add(e);
}
/**
* Make an empty set.
*/
public SimpleManagedElementSet() {
map = new TIntObjectHashMap<E>();
}
@Override
public E get(String name) {
return map.get(name.hashCode());
}
@Override
public boolean contains(E o) {
return map.containsKey(o.hashCode());
}
@Override
public boolean remove(E o) {
if (map.remove(o.hashCode()) != null) {
return super.remove(o);
}
return false;
}
@Override
public final boolean add(E e) {
int k = e.hashCode();
if (!map.containsKey(k)) {
map.put(k, e);
return super.add(e);
}
return false;
}
@Override
public void add(int i, E e) {
int k = e.hashCode();
if (!map.containsKey(k)) {
map.put(k, e);
super.add(i, e);
}
}
@Override
public boolean addAll(ManagedElementSet<E> elems) {
boolean ret = false;
for (E e : elems) {
ret |= this.add(e);
}
return ret;
}
@Override
public boolean removeAll(ManagedElementSet<E> elems) {
boolean ret = false;
for (E e : elems) {
ret |= this.remove(e);
}
return ret;
}
@Override
public boolean removeAll(Collection<?> objects) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
map.clear();
super.clear();
}
@Override
public E set(int i, E e) {
E old = super.set(i, e);
//e already in, so it is just a position change, no need to update the map
if (this.contains(e)) {
map.remove(old.hashCode());
} else {
map.put(e.hashCode(), e);
}
return old;
}
@Override
public boolean contains(Object o) {
return map.containsKey(o.hashCode());
}
@Override
public boolean containsAll(ManagedElementSet<E> elems) {
for (E e : elems) {
if (!this.contains(e)) {
return false;
}
}
return true;
}
@Override
public boolean retainAll(ManagedElementSet<E> elems) {
int i = 0;
boolean ret = false;
while (i < size()) {
E o = get(i);
if (!elems.contains(o)) {
remove(o);
ret = true;
} else {
i++;
}
}
return ret;
}
@Override
public ManagedElementSet<E> clone() {
ManagedElementSet<E> copy = new SimpleManagedElementSet<E>();
for (E e : this) {
copy.add(e);
}
return copy;
}
@Override
public String toString() {
StringBuilder b = new StringBuilder("{");
for (Iterator<E> ite = this.iterator(); ite.hasNext(); ) {
E e = ite.next();
b.append(e.getName());
if (ite.hasNext()) {
b.append(", ");
}
}
return b.append("}").toString();
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
} else if (o == this) {
return true;
} else if (o instanceof ManagedElementSet) {
//Cannot use super.equals() has we do not consider ordering
ManagedElementSet<E> ref = (ManagedElementSet<E>) o;
if (ref.size() != this.size()) {
return false;
}
for (E e : ref) {
if (!contains(e)) {
return false;
}
}
return true;
}
return false;
}
}