/** * Copyright 2013 Oak Ridge National Laboratory * Author: James Horey <horeyjl@ornl.gov> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ package gov.ornl.keva.core; /** * Java libs. **/ import java.util.Iterator; import java.util.Comparator; import java.util.List; import java.util.TreeSet; /** * Merge multiple, sorted iterators into a single iterator. This iterator * returns values in sorted order across iterators assuming that the user * supplies a comparator. This iterator is also special in that users can * define equivalence classes. Values within a single equivalence class can * be "merged" so that only a single value is returned. * * @author James Horey */ public class TreeUnionIterator<E> implements Iterator<E> { private List<Iterator<? extends E>> iters; private TreeSet<UnionValue<E>> index; private Comparator<E> comparator; /** * @param iterators The iterators containing all the values. Assumes that these * values are already sorted within a single iterator. * @param comparator Compare two values * @param equivOp Define an equivalence between values */ public TreeUnionIterator(final List<Iterator<? extends E>> iterators, final Comparator<E> comparator) { this.iters = iterators; this.comparator = comparator; // Populate the index with null values for each slot. index = new TreeSet<UnionValue<E>>(new Comparator<UnionValue<E>>() { public int compare(UnionValue<E> v1, UnionValue<E> v2) { return comparator.compare(v1.e, v2.e); } }); // Now populate the index with initial iterator values. for(Iterator<? extends E> iter : iters) { placeIntoSlot(iter, index); } } /** * Helper method to place the next value from the iterator * into the appropriate slot. **/ private void placeIntoSlot(Iterator<? extends E> iter, TreeSet<UnionValue<E>> index) { while(iter.hasNext()) { E e = iter.next(); // Check if the et contains the next element. If so, then we // can safe skip and proceed to the next element. UnionValue<E> value = new UnionValue<>(e, iter); if(!index.contains(value)) { // Place an item into the tree map. index.add(value); break; } } } /** * Indicate whether we have another element. * * @return True if there is another value. False otherwise. */ @Override public boolean hasNext() { // Does the set still have any items left? return index.size() > 0; } /** * Fetch the next element. * * @return Next value in the iterator. */ @Override public E next() { // Get the least value from the index. UnionValue<E> value = index.pollFirst(); // Fill up the used slot. placeIntoSlot(value.iter, index); // Return the least value. return value.e; } /** * Remove current element (not implemented). */ @Override public void remove() { // Do not implement. } class UnionValue<E> { public E e; public Iterator<? extends E> iter; public UnionValue(E e, Iterator<? extends E> iter) { this.e = e; this.iter = iter; } } }