/*
* Copyright (c) 2008, Jan Stender, Bjoern Kolbeck, Mikael Hoegqvist,
* Felix Hupfeld, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package de.mxro.thrd.babudb05.index;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Map.Entry;
import de.mxro.thrd.babudb05.api.database.ResultSet;
/**
* An iterator that merges a list of overlay trees. If a key occurs in multiple
* trees, the value associated with the key in the first tree has the highest
* priority, the one in the second tree the second highest priority, and so on.
* The iterator will never return more than one value for each key.
*
* @author stender
*
* @param <K>
* the key type
* @param <V>
* the value type
*/
public class OverlayMergeIterator<K, V> implements ResultSet<K, V> {
/**
* the next element to return
*/
private Entry<K, V> nextElement;
/**
* a list of potentially next elements
*/
private Entry<K, V>[] nextElements;
/**
* a list of all iterators to merge
*/
private List<Iterator<Entry<K, V>>> itList;
private Comparator<K> comp;
private V nullValue;
private boolean ascending;
public OverlayMergeIterator(List<Iterator<Entry<K, V>>> itList, Comparator<K> comp, V nullValue,
boolean ascending) {
this.itList = itList;
this.comp = comp;
this.nullValue = nullValue;
this.ascending = ascending;
nextElements = new Entry[itList.size()];
for (int i = 0; i < nextElements.length; i++)
nextElements[i] = itList.get(i).hasNext() ? itList.get(i).next() : null;
nextElement = getNextElement();
}
@Override
public boolean hasNext() {
return nextElement != null;
}
@Override
public Entry<K, V> next() {
if (nextElement == null)
throw new NoSuchElementException();
Entry<K, V> element = nextElement;
nextElement = getNextElement();
return element;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void free() {
// make sure that all resources attached to result sets in the list are
// freed
for (Iterator<Entry<K, V>> it : itList)
if (it instanceof ResultSet)
((ResultSet) it).free();
}
private Entry<K, V> getNextElement() {
// find the smallest element in the 'rightmost' tree
for (;;) {
int smallest = 0;
for (int i = 1; i < nextElements.length; i++) {
if (nextElements[i] == null)
continue;
// if a smaller element was found, next element is the
// smallest
if (nextElements[smallest] == null
|| (ascending && comp.compare(nextElements[i].getKey(), nextElements[smallest].getKey()) < 0)
|| (!ascending && comp.compare(nextElements[i].getKey(), nextElements[smallest].getKey()) > 0))
smallest = i;
// if the smallest element is equal to the current one, remove
// the current one
else if (comp.compare(nextElements[i].getKey(), nextElements[smallest].getKey()) == 0) {
Iterator<Entry<K, V>> it = itList.get(i);
nextElements[i] = it.hasNext() ? it.next() : null;
}
}
Entry<K, V> entry = nextElements[smallest];
Iterator<Entry<K, V>> it = itList.get(smallest);
nextElements[smallest] = it.hasNext() ? it.next() : null;
if (entry == null)
return null;
if (nullValue == null || entry.getValue() != nullValue)
return entry;
}
}
}