// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.dataset.v0_6.impl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.openstreetmap.osmosis.core.lifecycle.Closeable;
import org.openstreetmap.osmosis.core.store.IndexStoreReader;
import org.openstreetmap.osmosis.core.store.IntegerLongIndexElement;
/**
* Provides read-only access to a way tile area index store. Each thread
* accessing the store must create its own reader. The reader maintains all
* references to heavyweight resources such as file handles used to access the
* store eliminating the need for objects such as object iterators to be cleaned
* up explicitly.
*
* @author Brett Henderson
*/
public class WayTileAreaIndexReader implements Closeable {
private int[] masks = {0xFFFFFFFF, 0xFFFFFFF0, 0xFFFFFF00, 0xFFFF0000, 0xFF000000, 0x00000000};
private List<IndexStoreReader<Integer, IntegerLongIndexElement>> indexReaders;
/**
* Creates a new instance.
*
* @param masks
* The index masks.
* @param indexReaders
* The index readers.
*/
public WayTileAreaIndexReader(int[] masks, List<IndexStoreReader<Integer, IntegerLongIndexElement>> indexReaders) {
this.masks = masks;
this.indexReaders = indexReaders;
}
/**
* Returns all elements in the range specified by the minimum and maximum
* tiles. All ways with tiles matching and lying between the two values will
* be returned.
*
* @param minimumTile
* The minimum tile in the range.
* @param maximumTile
* The maximum tile in the range.
* @return An iterator pointing to the requested range.
*/
public Iterator<Long> getRange(Integer minimumTile, Integer maximumTile) {
List<Iterator<IntegerLongIndexElement>> ranges;
// Loop through the masks reading way id ranges from the corresponding
// indexes.
ranges = new ArrayList<Iterator<IntegerLongIndexElement>>(masks.length);
for (int i = 0; i < masks.length; i++) {
int mask;
int beginKey;
int endKey;
IndexStoreReader<Integer, IntegerLongIndexElement> indexReader;
mask = masks[i];
beginKey = mask & minimumTile;
endKey = mask & maximumTile;
indexReader = indexReaders.get(i);
ranges.add(indexReader.getRange(beginKey, endKey));
}
return new ResultIterator(ranges.iterator());
}
/**
* {@inheritDoc}
*/
@Override
public void close() {
for (IndexStoreReader<Integer, IntegerLongIndexElement> indexReader : indexReaders) {
indexReader.close();
}
}
/**
* Returns a complete result set of matching index values based on iterators
* from each of the internal indexes.
*
* @author Brett Henderson
*/
private static class ResultIterator implements Iterator<Long> {
private Iterator<Iterator<IntegerLongIndexElement>> sources;
private Iterator<IntegerLongIndexElement> currentSource;
private boolean currentSourceAvailable;
/**
* Creates a new instance.
*
* @param sources
* The input sources.
*/
public ResultIterator(Iterator<Iterator<IntegerLongIndexElement>> sources) {
this.sources = sources;
currentSourceAvailable = false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
while (true) {
// Get the next available input source if required.
if (!currentSourceAvailable) {
if (sources.hasNext()) {
currentSource = sources.next();
currentSourceAvailable = true;
} else {
return false;
}
}
if (currentSource.hasNext()) {
return true;
} else {
currentSourceAvailable = false;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Long next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return currentSource.next().getValue();
}
/**
* {@inheritDoc}
*/
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}