/*
* Copyright (C) 2007 - 2010 GeoSolutions S.A.S.
* http://www.geo-solutions.it
*
* GPLv3 + Classpath exception
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package it.geosolutions.geostore.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
*
* @author ETj (etj at geo-solutions.it)
*/
public class CategorizedCircularBuffer<T, K> {
// protected final static Logger LOGGER = Logger.getLogger(CategorizedCircularBuffer.class);
private final int maxSize;
LinkedList<Pair<T, K>> mainList;
private Map<K, LinkedList<T>> typedLists = new HashMap<K, LinkedList<T>>();
public CategorizedCircularBuffer(int maxCount) {
if (maxCount < 1) {
throw new IllegalArgumentException("Bad size");
}
this.maxSize = maxCount;
mainList = new LinkedList<Pair<T, K>>();
}
public void add(K key, T value) {
// add to main list
mainList.addFirst(new Pair<T, K>(key, value));
while (mainList.size() > maxSize) {
removeLastEntry();
}
LinkedList<T> typedList = typedLists.get(key);
if (typedList == null) {
typedList = new LinkedList<T>();
typedLists.put(key, typedList);
}
typedList.addFirst(value);
}
private void removeLastEntry() {
Pair<T, K> lastEntry = mainList.pollLast();
LinkedList<T> typedList = typedLists.get(lastEntry.key);
if (typedList == null) {
throw new IllegalStateException("Internal error - can't find list for " + lastEntry);
}
T remove = typedList.removeLast();
if (!lastEntry.value.equals(remove)) {
throw new IllegalStateException("Internal error - mismatching values "
+ lastEntry.value + " , " + remove);
}
if (typedList.size() == 0) {
typedLists.remove(lastEntry.key);
}
}
public List<T> subList(int fromIndex, int toIndex) {
List<T> ret = new ArrayList<T>(toIndex - fromIndex);
for (Pair<T, K> pair : mainList.subList(fromIndex, toIndex)) {
ret.add(pair.value);
}
return ret;
}
public int size() {
return mainList.size();
}
@SuppressWarnings("unchecked")
public List<T> subListByKey(K key, int fromIndex, int toIndex) {
LinkedList<T> typedList = typedLists.get(key);
if (typedList == null) {
return Collections.EMPTY_LIST;
}
return typedList.subList(fromIndex, toIndex);
}
public int sizeByKey(K key) {
LinkedList<T> typedList = typedLists.get(key);
if (typedList == null) {
return 0;
}
return typedList.size();
}
static class Pair<T, K> {
K key;
T value;
public Pair(K key, T value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return "Pair{" + "key=" + key + " value=" + value + '}';
}
}
}