package org.ovirt.engine.core.bll.network.macpool;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.collections.iterators.UnmodifiableIterator;
/**
* Associative array counting instances of given object.
* @param <T> class of instances being count.
*/
class ObjectCounter<T> implements Iterable<T>{
private Map<T, Counter> map = new HashMap<>();
private final boolean allowDuplicate;
ObjectCounter(boolean allowDuplicate) {
this.allowDuplicate = allowDuplicate;
}
/**
* add instance if possible, incrementing number of its occurrences.
* @param key instance to add.
* @return true if instance was added && count incremented.
*/
public boolean increase(T key) {
return increase(key, allowDuplicate);
}
public boolean increase(T key, boolean allowDuplicate) {
Counter counter = map.get(key);
if (counter == null) {
map.put(key, new Counter());
return true;
} else if (allowDuplicate) {
counter.increase();
return true;
} else {
return false;
}
}
/**
* decrements number of its occurrences, removing instance if possible(count reaches zero).
*
* @param key instance to remove.
*/
public void decrease(T key) {
Counter counter = map.get(key);
if (counter == null) {
return;
}
int count = counter.decrease();
if (count == 0) {
map.remove(key);
} else if (count < 0) {
throw new IllegalStateException("count underflow.");
}
}
/**
* @param key instance to look for
* @return true if there's at least one occurrence of given instance.
*/
public boolean contains(T key) {
return map.containsKey(key);
}
/**
* @param key instance to look for
* @return number of occurrences of given instance. When instance was not added
*/
public int count(T key) {
final Counter counter = map.get(key);
return counter == null ? 0 : counter.toInt();
}
/**
* @return unmodifiable iterator over all 'registered' instances (i.e. all instances having count >= 0).
*/
@Override
@SuppressWarnings("unchecked")
public Iterator<T> iterator() {
return UnmodifiableIterator.decorate(map.keySet().iterator());
}
private static class Counter {
private int count;
private Counter() {
this(1);
}
public Counter(int initialValue) {
setCount(initialValue);
}
public void setCount(int count) {
this.count = count;
}
public void increase() {
count++;
}
public int decrease() {
count--;
return count;
}
public int toInt() {
return count;
}
}
}