/*
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Aug 7, 2008
*/
package com.bigdata.striterator;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import cutthecrap.utils.striterators.ICloseableIterator;
/**
* Pattern for resolving elements of an iterator.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
* @param <I>
* The generic type of the source iterator.
* @param <E>
* The generic type of the elements visited by the source iterator.
* @param <F>
* The generic type of the elements visited by the filtered iterator.
*/
abstract public class Resolver<I extends Iterator<E>, E, F> implements
IFilter<I, E, F> {
/** The chunk size if the source is not chunked. */
private final int chunkSize;
/** The order for the resolved elements (optional). */
private final IKeyOrder<F> keyOrder;
public Resolver() {
this(IChunkedIterator.DEFAULT_CHUNK_SIZE, null);
}
/**
* @param chunkSize
* The chunk size to use if the source is not chunked.
* @param keyOrder
* The order for the resolved elements (optional).
*/
public Resolver(int chunkSize, IKeyOrder<F> keyOrder) {
this.chunkSize = chunkSize;
this.keyOrder = keyOrder;
}
@Override
public IChunkedIterator<F> filter(final I src) {
return new ChunkedResolvingIterator<I, E, F>(src, this);
}
/**
* Resolve an element visited by the source iterator into an element of the
* type visitable by this iterator.
*
* @param e
* An element visited by the source iterator.
*
* @return The element to be visited by this iterator.
*/
abstract protected F resolve(E e);
/**
* Converts the type of the source iterator using
* {@link Resolver#resolve(Object)}.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*
* @param <I>
* The generic type of the source iterator.
* @param <E>
* The generic type of the elements visited by the source
* iterator.
* @param <F>
* The generic type of the elements visited by the filtered
* iterator.
*/
static private class ChunkedResolvingIterator<I extends Iterator<E>, E, F>
implements IChunkedOrderedIterator<F> {
/** The source iterator. */
private final I src;
/** The resolver. */
private final Resolver<I,E,F> filter;
/**
* Ctor variant when (a) you KNOW the sort order for the source iterator and
* (b) the source elements and the resolved elements have the same natural
* sort order (so the sort order is naturally preserved when the elements
* are resolved).
*
* @param src
* The source iterator.
* @param keyOrder
* The sort order for the resolved elements.
*/
public ChunkedResolvingIterator(I src, Resolver<I,E,F> filter) {
if (src == null)
throw new IllegalArgumentException();
this.src = src;
this.filter = filter;
}
@Override
public IKeyOrder<F> getKeyOrder() {
return filter.keyOrder;
}
@Override
public boolean hasNext() {
return src.hasNext();
}
@Override
public F next() {
return filter.resolve( src.next() );
}
@Override
@SuppressWarnings("unchecked")
public F[] nextChunk() {
if (!src.hasNext())
throw new NoSuchElementException();
if(src instanceof IChunkedIterator) {
final E[] a = ((IChunkedIterator<E>) src).nextChunk();
return resolveChunk(a, a.length);
} else {
E[] a = null;
int n = 0;
for (int i = 0; i < filter.chunkSize && src.hasNext(); i++) {
final E e = src.next();
if (a == null) {
/*
* Dynamically instantiation an array of the same
* component type as the objects that we are visiting.
*/
a = (E[]) java.lang.reflect.Array.newInstance(e
.getClass(), filter.chunkSize);
}
a[i] = e;
n++;
}
return resolveChunk(a, n);
}
}
/**
* Resolve a chunk of elements.
*
* @param a
* The chunk of elements.
* @param n
* The #of elements in that chunk.
*
* @return The chunk of resolved elements.
*/
@SuppressWarnings("unchecked")
protected F[] resolveChunk(E[] a, int n) {
F[] b = null;
for (int i = 0; i <n; i++) {
// resolve
final F e = filter.resolve(a[i]);
if (b == null) {
/*
* Dynamically instantiation an array of the same
* component type as the objects that we are visiting.
*/
b = (F[]) java.lang.reflect.Array.newInstance(e.getClass(),
n);
}
// save reference
b[i] = e;
}
// done.
return b;
}
@Override
public F[] nextChunk(final IKeyOrder<F> keyOrder) {
if (keyOrder == null)
throw new IllegalArgumentException();
final F[] chunk = nextChunk();
if (!keyOrder.equals(getKeyOrder())) {
// sort into the required order.
Arrays.sort(chunk, 0, chunk.length, keyOrder.getComparator());
}
return chunk;
}
@Override
public void remove() {
src.remove();
}
@Override
public void close() {
if (src instanceof ICloseableIterator) {
((ICloseableIterator<E>) src).close();
}
}
}
// abstract static public class ChunkedResolvingIterator2<I extends Iterator<E>, E, F>
// extends ChunkedResolvingIterator<I, E, F> {
//
// /**
// * @param src
// * @param filter
// */
// public ChunkedResolvingIterator2(I src) {
//
// super(src, new Resolver<I,E,F>() {
//
// @Override
// protected F resolve(E e) {
// return ChunkedResolvingIterator2.this.resolve( e );
// }
//
// });
//
// }
//
// /**
// * Resolve an element visited by the source iterator into an element of
// * the type visitable by this iterator.
// *
// * @param e
// * An element visited by the source iterator.
// *
// * @return The element to be visited by this iterator.
// */
// abstract protected F resolve(E e);
//
// }
}