/*-
* Copyright 2017 Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.dawnsci.analysis.dataset;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.IntUnaryOperator;
import java.util.function.LongConsumer;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.StreamSupport;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DoubleDataset;
import org.eclipse.january.dataset.IndexIterator;
import org.eclipse.january.dataset.IntegerDataset;
import org.eclipse.january.dataset.LongDataset;
/**
* Provide static methods to use Datasets in functional ways
*
* This class provides dataset values as streams.
* @see StreamSupport
*/
public class DatasetStreamSupport {
private static final int FLAGS = Spliterator.SIZED | Spliterator.DISTINCT | Spliterator.CONCURRENT
| Spliterator.IMMUTABLE | Spliterator.NONNULL;
private DatasetStreamSupport() {
}
private static class DatasetIndexOperator implements IntUnaryOperator {
private int[] shape;
private int[] strides;
private int offset;
private int rank;
public DatasetIndexOperator(Dataset a) {
shape = a.getShape();
rank = shape.length;
strides = a.getStrides().clone();
offset = a.getOffset();
}
@Override
public int applyAsInt(int value) {
int v = value;
int index = offset;
for (int i = rank-1; v > 0 && i >= 0; i--) {
int s = shape[i];
int p = v % s;
if (p != 0) {
index += p * strides[i];
}
v /= s;
}
return index;
}
}
/**
* Create a function to map an ordinal to the actual index used in a view of
* a dataset
* @param a dataset
* @return function
*/
public static IntUnaryOperator createDatasetIndexFunction(Dataset a) {
if (a.getStrides() == null) {
return i -> i;
}
return new DatasetIndexOperator(a);
}
private static class IndexSpliterator extends Spliterators.AbstractIntSpliterator {
private boolean gotNext;
private final IndexIterator it;
public IndexSpliterator(Dataset a) {
super(a.getSize(), FLAGS);
gotNext = a.getSize() > 0;
it = a.getIterator();
}
@Override
public boolean tryAdvance(IntConsumer action) {
if (action == null) {
throw new NullPointerException();
}
gotNext = it.hasNext();
if (gotNext) {
action.accept(it.index);
}
return gotNext;
}
}
private static class DatasetIntSpliterator extends Spliterators.AbstractIntSpliterator {
private boolean gotNext;
private final IndexIterator it;
private final Dataset data;
public DatasetIntSpliterator(Dataset a) {
super(a.getSize(), FLAGS);
data = a;
gotNext = a.getSize() > 0;
it = a.getIterator();
}
@Override
public boolean tryAdvance(IntConsumer action) {
if (action == null) {
throw new NullPointerException();
}
gotNext = it.hasNext();
if (gotNext) {
action.accept((int) data.getElementLongAbs(it.index));
}
return gotNext;
}
}
private static class DatasetLongSpliterator extends Spliterators.AbstractLongSpliterator {
private boolean gotNext;
private final IndexIterator it;
private final Dataset data;
public DatasetLongSpliterator(Dataset a) {
super(a.getSize(), FLAGS);
data = a;
gotNext = a.getSize() > 0;
it = a.getIterator();
}
@Override
public boolean tryAdvance(LongConsumer action) {
if (action == null) {
throw new NullPointerException();
}
gotNext = it.hasNext();
if (gotNext) {
action.accept(data.getElementLongAbs(it.index));
}
return gotNext;
}
}
private static class DatasetDoubleSpliterator extends Spliterators.AbstractDoubleSpliterator {
private boolean gotNext;
private final IndexIterator it;
private final Dataset data;
public DatasetDoubleSpliterator(Dataset a) {
super(a.getSize(), FLAGS);
data = a;
gotNext = a.getSize() > 0;
it = a.getIterator();
}
@Override
public boolean tryAdvance(DoubleConsumer action) {
if (action == null) {
throw new NullPointerException();
}
gotNext = it.hasNext();
if (gotNext) {
action.accept(data.getElementDoubleAbs(it.index));
}
return gotNext;
}
}
private static class DoubleDatasetSpliterator extends Spliterators.AbstractDoubleSpliterator {
private boolean gotNext;
private final IndexIterator it;
private final DoubleDataset data;
public DoubleDatasetSpliterator(DoubleDataset a) {
super(a.getSize(), FLAGS);
data = a;
gotNext = a.getSize() > 0;
it = a.getIterator();
}
@Override
public boolean tryAdvance(DoubleConsumer action) {
if (action == null) {
throw new NullPointerException();
}
gotNext = it.hasNext();
if (gotNext) {
action.accept(data.getAbs(it.index));
}
return gotNext;
}
}
private static class IntegerDatasetSpliterator extends Spliterators.AbstractIntSpliterator {
private boolean gotNext;
private final IndexIterator it;
private final IntegerDataset data;
public IntegerDatasetSpliterator(IntegerDataset a) {
super(a.getSize(), FLAGS);
data = a;
gotNext = a.getSize() > 0;
it = a.getIterator();
}
@Override
public boolean tryAdvance(IntConsumer action) {
if (action == null) {
throw new NullPointerException();
}
gotNext = it.hasNext();
if (gotNext) {
action.accept(data.getAbs(it.index));
}
return gotNext;
}
}
private static class LongDatasetSpliterator extends Spliterators.AbstractLongSpliterator {
private boolean gotNext;
private final IndexIterator it;
private final LongDataset data;
public LongDatasetSpliterator(LongDataset a) {
super(a.getSize(), FLAGS);
data = a;
gotNext = a.getSize() > 0;
it = a.getIterator();
}
@Override
public boolean tryAdvance(LongConsumer action) {
if (action == null) {
throw new NullPointerException();
}
gotNext = it.hasNext();
if (gotNext) {
action.accept(data.getAbs(it.index));
}
return gotNext;
}
}
/**
* Create a stream of index for iterating through a dataset
* @param a dataset
* @return index stream
*/
public static IntStream createDatasetIndexStream(Dataset a, boolean parallel) {
return StreamSupport.intStream(new IndexSpliterator(a), parallel);
}
/**
* Create a stream of long values from iterating through a dataset
* @param a dataset
* @return long stream
*/
public static IntStream createDatasetStream(IntegerDataset a, boolean parallel) {
if (a.getStrides() == null) {
StreamSupport.intStream(Spliterators.spliterator(a.getData(), FLAGS), parallel);
}
return StreamSupport.intStream(new IntegerDatasetSpliterator(a), parallel);
}
/**
* Create a stream of long values from iterating through a dataset
* @param a dataset
* @return long stream
*/
public static LongStream createDatasetStream(LongDataset a, boolean parallel) {
if (a.getStrides() == null) {
StreamSupport.longStream(Spliterators.spliterator(a.getData(), FLAGS), parallel);
}
return StreamSupport.longStream(new LongDatasetSpliterator(a), parallel);
}
/**
* Create a stream of double values from iterating through a dataset
* @param a dataset
* @return double stream
*/
public static DoubleStream createDatasetStream(DoubleDataset a, boolean parallel) {
if (a.getStrides() == null) {
StreamSupport.doubleStream(Spliterators.spliterator(a.getData(), FLAGS), parallel);
}
return StreamSupport.doubleStream(new DoubleDatasetSpliterator(a), parallel);
}
/**
* Create a stream of int values from iterating through a dataset
* @param a dataset
* @return int stream
*/
public static IntStream createDatasetIntStream(Dataset a, boolean parallel) {
if (a instanceof IntegerDataset) {
return createDatasetStream((IntegerDataset) a, parallel);
}
return StreamSupport.intStream(new DatasetIntSpliterator(a), parallel);
}
/**
* Create a stream of long values from iterating through a dataset
* @param a dataset
* @return long stream
*/
public static LongStream createDatasetLongStream(Dataset a, boolean parallel) {
if (a instanceof LongDataset) {
return createDatasetStream((LongDataset) a, parallel);
}
return StreamSupport.longStream(new DatasetLongSpliterator(a), parallel);
}
/**
* Create a stream of double values from iterating through a dataset
* @param a dataset
* @return double stream
*/
public static DoubleStream createDatasetDoubleStream(Dataset a, boolean parallel) {
if (a instanceof DoubleDataset) {
return createDatasetStream((DoubleDataset) a, parallel);
}
return StreamSupport.doubleStream(new DatasetDoubleSpliterator(a), parallel);
}
}