// This software is released into the Public Domain. See copying.txt for details. package org.openstreetmap.osmosis.core.sort.common; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.NoSuchElementException; import org.openstreetmap.osmosis.core.lifecycle.ReleasableIterator; /** * This iterator examines a list of sorted input sources and merges them into a * single sorted list. * * @param <DataType> * The object type to be sorted. * @author Brett Henderson */ public class MergingIterator<DataType> implements ReleasableIterator<DataType> { private List<ReleasableIterator<DataType>> sources; private Comparator<DataType> comparator; private List<DataType> sourceData; /** * Creates a new instance. * * @param sources * The list of data sources. * @param comparator * The comparator to be used for sorting. */ public MergingIterator(List<ReleasableIterator<DataType>> sources, Comparator<DataType> comparator) { this.sources = new ArrayList<ReleasableIterator<DataType>>(sources); this.comparator = comparator; } /** * Primes the sorting collections. */ private void initialize() { if (sourceData == null) { // Get the first entity from each source. Delete any empty sources. sourceData = new ArrayList<DataType>(sources.size()); for (int sourceIndex = 0; sourceIndex < sources.size();) { ReleasableIterator<DataType> source; source = sources.get(sourceIndex); if (source.hasNext()) { sourceData.add(source.next()); sourceIndex++; } else { sources.remove(sourceIndex).close(); } } } } /** * {@inheritDoc} */ public boolean hasNext() { initialize(); return sourceData.size() > 0; } /** * {@inheritDoc} */ public DataType next() { DataType dataMinimum; int indexMinimum; ReleasableIterator<DataType> source; initialize(); if (!hasNext()) { throw new NoSuchElementException(); } dataMinimum = sourceData.get(0); indexMinimum = 0; // Find the minimum entity. for (int indexCurrent = 1; indexCurrent < sources.size(); indexCurrent++) { DataType dataCurrent = sourceData.get(indexCurrent); // Check if the current data entity is less than the existing minimum. if (comparator.compare(dataMinimum, dataCurrent) > 0) { dataMinimum = dataCurrent; indexMinimum = indexCurrent; } } // Get the next entity from the source if available. // Otherwise remove the source and its current data. source = sources.get(indexMinimum); if (source.hasNext()) { sourceData.set(indexMinimum, source.next()); } else { sources.remove(indexMinimum).close(); sourceData.remove(indexMinimum); } return dataMinimum; } /** * Not supported. An UnsupportedOperationException is always thrown. */ public void remove() { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ public void close() { for (ReleasableIterator<DataType> source : sources) { source.close(); } } }