// This software is released into the Public Domain. See copying.txt for details. package org.openstreetmap.osmosis.core.filter.common; import java.util.BitSet; import java.util.Iterator; import java.util.NoSuchElementException; import org.openstreetmap.osmosis.core.util.LongAsInt; /** * Implements the IdTracker interface using an internal JDK BitSet. The current * implementation only supports 31 bit numbers, but will be enhanced if and when * required. * * @author Brett Henderson */ public class BitSetIdTracker implements IdTracker { /** * The positive ids are stored within a bitset which cannot hold negative * values. It is not private to allow the IdIterator to access it * efficiently. */ /* package */ BitSet positiveSet; /** * The negative ids cannot be stored in the main bitset. They are stored in * a list implementation because the number of negative values is expected * to be small. It is not private to allow the IdIterator to access it * efficiently. */ /* package */ ListIdTracker negativeSet; /** * Creates a new instance. */ public BitSetIdTracker() { positiveSet = new BitSet(); negativeSet = new ListIdTracker(); } /** * {@inheritDoc} */ public void set(long id) { int intId; intId = LongAsInt.longToInt(id); if (intId >= 0) { positiveSet.set(intId); } else { negativeSet.set(intId); } } /** * {@inheritDoc} */ public boolean get(long id) { int intId; boolean result; intId = LongAsInt.longToInt(id); if (intId >= 0) { result = positiveSet.get(intId); } else { result = negativeSet.get(intId); } return result; } /** * {@inheritDoc} */ @Override public Iterator<Long> iterator() { return new IdIterator(); } /** * {@inheritDoc} */ @Override public void setAll(IdTracker idTracker) { for (Long id : idTracker) { set(id); } } /** * The iterator implementation for providing access to the list of ids. * * @author Brett Henderson */ private class IdIterator implements Iterator<Long> { /** * Tracks whether we're currently reading positive or negative bitsets. */ private boolean readingPositive; private long nextId; private boolean nextIdAvailable; private Iterator<Long> negativeIterator; /** * The current bit offset in the positive bitset. */ private int positiveOffset; /** * Creates a new instance. */ public IdIterator() { readingPositive = false; nextIdAvailable = false; positiveOffset = 0; } /** * {@inheritDoc} */ @Override public boolean hasNext() { if (!nextIdAvailable) { if (!readingPositive) { // Create a negative set iterator if one doesn't already exist. if (negativeIterator == null) { negativeIterator = negativeSet.iterator(); } // Get data from the negative iterator if available, if not // available switch to positive reading. if (negativeIterator.hasNext()) { nextId = negativeIterator.next(); nextIdAvailable = true; } else { negativeIterator = null; readingPositive = true; } } if (readingPositive) { int nextBitOffset; nextBitOffset = positiveSet.nextSetBit(positiveOffset); if (nextBitOffset >= 0) { nextId = nextBitOffset; nextIdAvailable = true; positiveOffset = nextBitOffset + 1; } } } return nextIdAvailable; } /** * {@inheritDoc} */ @Override public Long next() { if (!hasNext()) { throw new NoSuchElementException(); } nextIdAvailable = false; return nextId; } /** * {@inheritDoc} */ @Override public void remove() { throw new UnsupportedOperationException(); } } }