Skip to content

Instantly share code, notes, and snippets.

@hageldave
Last active January 21, 2017 14:42
Show Gist options
  • Save hageldave/1d9bff1f0598b9da3443876f0113a501 to your computer and use it in GitHub Desktop.
Save hageldave/1d9bff1f0598b9da3443876f0113a501 to your computer and use it in GitHub Desktop.
wrapper for arrays
package misc;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class Slice<T> implements Iterable<Slice.ArrayAccessor<T>>{
final ArrayAccessor<T> aa;
final int size;
private Slice(ArrayAccessor<T> accessor, int size) {
this.aa = accessor;
this.size = size;
}
@Override
public Iterator<ArrayAccessor<T>> iterator() {
return new AccessorIterator<T>(0, size, aa);
}
@Override
public Spliterator<ArrayAccessor<T>> spliterator() {
return new AccessorSpliterator<T>(0, size-1, 1024, aa);
}
public Stream<ArrayAccessor<T>> stream(boolean parallel) {
return StreamSupport.stream(spliterator(), parallel);
}
public Stream<ArrayAccessor<T>> stream() {
return stream(false);
}
public Stream<ArrayAccessor<T>> parallelStream() {
return stream(true);
}
@Override
public void forEach(Consumer<? super ArrayAccessor<T>> action) {
Iterable.super.forEach(action);
}
public void forEachParallel(Consumer<? super ArrayAccessor<T>> action) {
parallelStream().forEach(action);
}
public Slice<T> copy() {
return new Slice<T>(aa.copy(),size);
}
public T getAt(int i){
return aa.get(i);
}
public void setAt(int i, T e){
aa.set(i, e);
}
public int length() {
return size;
}
public int size() {
return size;
}
///////////////////////////////
// Constructors
///////////////////////////////
static <T> Slice<T> get(T[] array){
return new Slice<T>(new GenericAccessor<T>(array),array.length);
}
static Slice<Integer> get(int[] array){
return new Slice<Integer>(new IntAccessor(array),array.length);
}
static Slice<Long> get(long[] array){
return new Slice<Long>(new LongAccessor(array),array.length);
}
static Slice<Float> get(float[] array){
return new Slice<Float>(new FloatAccessor(array),array.length);
}
static Slice<Double> get(double[] array){
return new Slice<Double>(new DoubleAccessor(array),array.length);
}
static Slice<Short> get(short[] array){
return new Slice<Short>(new ShortAccessor(array),array.length);
}
static Slice<Character> get(char[] array){
return new Slice<Character>(new CharAccessor(array),array.length);
}
static Slice<Byte> get(byte[] array){
return new Slice<Byte>(new ByteAccessor(array),array.length);
}
///////////////////////////////
// Static Streaming
///////////////////////////////
public static <T> Stream<ArrayAccessor<T>> stream(T[] array, boolean parallel, int minSplitSize){
return StreamSupport.stream(new AccessorSpliterator<T>(0, array.length-1, minSplitSize, new GenericAccessor<T>(array)), parallel);
}
public static <T> Stream<ArrayAccessor<T>> stream(T[] array, boolean parallel){
return stream(array, parallel, 1024);
}
public static Stream<ArrayAccessor<Integer>> stream(int[] array, boolean parallel, int minSplitSize){
return StreamSupport.stream(new AccessorSpliterator<Integer>(0, array.length-1, minSplitSize, new IntAccessor(array)), parallel);
}
public static Stream<ArrayAccessor<Integer>> stream(int[] array, boolean parallel){
return stream(array, parallel, 1024);
}
public static Stream<ArrayAccessor<Long>> stream(long[] array, boolean parallel, int minSplitSize){
return StreamSupport.stream(new AccessorSpliterator<Long>(0, array.length-1, minSplitSize, new LongAccessor(array)), parallel);
}
public static Stream<ArrayAccessor<Long>> stream(long[] array, boolean parallel){
return stream(array, parallel, 1024);
}
public static Stream<ArrayAccessor<Float>> stream(float[] array, boolean parallel, int minSplitSize){
return StreamSupport.stream(new AccessorSpliterator<Float>(0, array.length-1, minSplitSize, new FloatAccessor(array)), parallel);
}
public static Stream<ArrayAccessor<Float>> stream(float[] array, boolean parallel){
return stream(array, parallel, 1024);
}
public static Stream<ArrayAccessor<Double>> stream(double[] array, boolean parallel, int minSplitSize){
return StreamSupport.stream(new AccessorSpliterator<Double>(0, array.length-1, minSplitSize, new DoubleAccessor(array)), parallel);
}
public static Stream<ArrayAccessor<Double>> stream(double[] array, boolean parallel){
return stream(array, parallel, 1024);
}
public static Stream<ArrayAccessor<Short>> stream(short[] array, boolean parallel, int minSplitSize){
return StreamSupport.stream(new AccessorSpliterator<Short>(0, array.length-1, minSplitSize, new ShortAccessor(array)), parallel);
}
public static Stream<ArrayAccessor<Short>> stream(short[] array, boolean parallel){
return stream(array, parallel, 1024);
}
public static Stream<ArrayAccessor<Character>> stream(char[] array, boolean parallel, int minSplitSize){
return StreamSupport.stream(new AccessorSpliterator<Character>(0, array.length-1, minSplitSize, new CharAccessor(array)), parallel);
}
public static Stream<ArrayAccessor<Character>> stream(char[] array, boolean parallel){
return stream(array, parallel, 1024);
}
public static Stream<ArrayAccessor<Byte>> stream(byte[] array, boolean parallel, int minSplitSize){
return StreamSupport.stream(new AccessorSpliterator<Byte>(0, array.length-1, minSplitSize, new ByteAccessor(array)), parallel);
}
public static Stream<ArrayAccessor<Byte>> stream(byte[] array, boolean parallel){
return stream(array, parallel, 1024);
}
///////////////////////////////
// Accessors
///////////////////////////////
public static abstract class ArrayAccessor<T> implements Cloneable {
protected int index;
public abstract T get();
public abstract void set(T e);
protected abstract T get(int i);
protected abstract void set(int i, T e);
public final int getIndex(){ return index; }
public final void setIndex(int i){index = i; }
/** only copies reference */
protected abstract ArrayAccessor<T> clone();
/** allocates new array */
protected abstract ArrayAccessor<T> copy();
@Override
public String toString() {
return String.format("[%s] at index %d", getClass().getSimpleName(), index);
}
}
static class GenericAccessor<T> extends ArrayAccessor<T> {
T[] array;
public GenericAccessor(T[] array) {
this.array=array;
}
@Override
public T get() {return array[index];}
@Override
public void set(T e) {array[index] = e;}
@Override
protected T get(int i) {return array[i];}
@Override
protected void set(int i, T e) {array[i] = e;}
@Override
protected GenericAccessor<T> clone() {
GenericAccessor<T> clon = new GenericAccessor<>(array);
clon.setIndex(index);
return clon;
}
@Override
protected GenericAccessor<T> copy() {
GenericAccessor<T> cpy = new GenericAccessor<T>(Arrays.copyOf(array, array.length));
cpy.setIndex(index);
return cpy;
}
}
static class IntAccessor extends ArrayAccessor<Integer> {
int[] array;
public IntAccessor(int[] array) {
this.array=array;
}
@Override
public Integer get() {return array[index];}
@Override
public void set(Integer e) {array[index] = e;}
@Override
protected Integer get(int i) {return array[i];}
@Override
protected void set(int i, Integer e) {array[i] = e;}
@Override
protected IntAccessor clone() {
IntAccessor clon = new IntAccessor(array);
clon.setIndex(index);
return clon;
}
@Override
protected IntAccessor copy() {
IntAccessor cpy = new IntAccessor(Arrays.copyOf(array, array.length));
cpy.setIndex(index);
return cpy;
}
}
static class LongAccessor extends ArrayAccessor<Long> {
long[] array;
public LongAccessor(long[] array) {
this.array=array;
}
@Override
public Long get() {return array[index];}
@Override
public void set(Long e) {array[index] = e;}
@Override
protected Long get(int i) {return array[i];}
@Override
protected void set(int i, Long e) {array[i] = e;}
@Override
protected LongAccessor clone() {
LongAccessor clon = new LongAccessor(array);
clon.setIndex(index);
return clon;
}
@Override
protected LongAccessor copy() {
LongAccessor cpy = new LongAccessor(Arrays.copyOf(array, array.length));
cpy.setIndex(index);
return cpy;
}
}
static class FloatAccessor extends ArrayAccessor<Float> {
float[] array;
public FloatAccessor(float[] array) {
this.array=array;
}
@Override
public Float get() {return array[index];}
@Override
public void set(Float e) {array[index] = e;}
@Override
protected Float get(int i) {return array[i];}
@Override
protected void set(int i, Float e) {array[i] = e;}
@Override
protected FloatAccessor clone() {
FloatAccessor clon = new FloatAccessor(array);
clon.setIndex(index);
return clon;
}
@Override
protected FloatAccessor copy() {
FloatAccessor cpy = new FloatAccessor(Arrays.copyOf(array, array.length));
cpy.setIndex(index);
return cpy;
}
}
static class DoubleAccessor extends ArrayAccessor<Double> {
double[] array;
public DoubleAccessor(double[] array) {
this.array=array;
}
@Override
public Double get() {return array[index];}
@Override
public void set(Double e) {array[index] = e;}
@Override
protected Double get(int i) {return array[i];}
@Override
protected void set(int i, Double e) {array[i] = e;}
@Override
protected DoubleAccessor clone() {
DoubleAccessor clon = new DoubleAccessor(array);
clon.setIndex(index);
return clon;
}
@Override
protected DoubleAccessor copy() {
DoubleAccessor cpy = new DoubleAccessor(Arrays.copyOf(array, array.length));
cpy.setIndex(index);
return cpy;
}
}
static class ShortAccessor extends ArrayAccessor<Short> {
short[] array;
public ShortAccessor(short[] array) {
this.array=array;
}
@Override
public Short get() {return array[index];}
@Override
public void set(Short e) {array[index] = e;}
@Override
protected Short get(int i) {return array[i];}
@Override
protected void set(int i, Short e) {array[i] = e;}
@Override
protected ShortAccessor clone() {
ShortAccessor clon = new ShortAccessor(array);
clon.setIndex(index);
return clon;
}
@Override
protected ShortAccessor copy() {
ShortAccessor cpy = new ShortAccessor(Arrays.copyOf(array, array.length));
cpy.setIndex(index);
return cpy;
}
}
static class CharAccessor extends ArrayAccessor<Character> {
char[] array;
public CharAccessor(char[] array) {
this.array=array;
}
@Override
public Character get() {return array[index];}
@Override
public void set(Character e) {array[index] = e;}
@Override
protected Character get(int i) {return array[i];}
@Override
protected void set(int i, Character e) {array[i] = e;}
@Override
protected CharAccessor clone() {
CharAccessor clon = new CharAccessor(array);
clon.setIndex(index);
return clon;
}
@Override
protected CharAccessor copy() {
CharAccessor cpy = new CharAccessor(Arrays.copyOf(array, array.length));
cpy.setIndex(index);
return cpy;
}
}
static class ByteAccessor extends ArrayAccessor<Byte> {
byte[] array;
public ByteAccessor(byte[] array) {
this.array=array;
}
@Override
public Byte get() {return array[index];}
@Override
public void set(Byte e) {array[index] = e;}
@Override
protected Byte get(int i) {return array[i];}
@Override
protected void set(int i, Byte e) {array[i] = e;}
@Override
protected ByteAccessor clone() {
ByteAccessor clon = new ByteAccessor(array);
clon.setIndex(index);
return clon;
}
@Override
protected ByteAccessor copy() {
ByteAccessor cpy = new ByteAccessor(Arrays.copyOf(array, array.length));
cpy.setIndex(index);
return cpy;
}
}
///////////////////////////////
// Iterator & Spliterator
///////////////////////////////
static class AccessorIterator<T> implements Iterator<ArrayAccessor<T>> {
int i;
final int endIndexExcl;
final ArrayAccessor<T> acc;
public AccessorIterator(int startIndex, int endIndexExcl, ArrayAccessor<T> acc) {
this.acc = acc.clone();
this.i = startIndex-1;
this.endIndexExcl = endIndexExcl;
}
@Override
public boolean hasNext() {
return i+1 < endIndexExcl;
}
@Override
public ArrayAccessor<T> next() {
i++;
acc.setIndex(i);
return acc;
}
@Override
public void forEachRemaining(Consumer<? super ArrayAccessor<T>> action) {
i++;
for(; i < endIndexExcl; i++){
acc.setIndex(i);
}
}
}
static class AccessorSpliterator<T> implements Spliterator<ArrayAccessor<T>> {
final ArrayAccessor<T> acc;
int endIndex;
final int minimumSplitSize;
/**
* Constructs a new ImgSpliterator for the specified index range
* @param startIndex first index of the range (inclusive)
* @param endIndex last index of the range (inclusive)
* @param minSplitSize minimum split size for this spliterator (minimum number of elements in a split)
*/
AccessorSpliterator(int startIndex, int endIndex, int minSplitSize, ArrayAccessor<T> acc) {
this.acc = acc.clone();
this.acc.setIndex(startIndex);
this.endIndex = endIndex;
this.minimumSplitSize = minSplitSize;
}
private void setEndIndex(int endIndex) {
this.endIndex = endIndex;
}
@Override
public boolean tryAdvance(final Consumer<? super ArrayAccessor<T>> action) {
if(acc.getIndex() <= endIndex){
int index = acc.getIndex();
action.accept(acc);
acc.setIndex(index+1);
return true;
} else {
return false;
}
}
@Override
public void forEachRemaining(final Consumer<? super ArrayAccessor<T>> action) {
int idx = acc.getIndex();
for(;idx <= endIndex; acc.setIndex(++idx)){
action.accept(acc);
}
}
@Override
public Spliterator<ArrayAccessor<T>> trySplit() {
int currentIdx = Math.min(acc.getIndex(), endIndex);
int midIdx = currentIdx + (endIndex-currentIdx)/2;
if(midIdx > currentIdx+minimumSplitSize){
AccessorSpliterator<T> split = new AccessorSpliterator<T>(midIdx, endIndex, minimumSplitSize, acc);
setEndIndex(midIdx-1);
return split;
} else {
return null;
}
}
@Override
public long estimateSize() {
int currentIndex = acc.getIndex();
int lastIndexPlusOne = endIndex+1;
return lastIndexPlusOne-currentIndex;
}
@Override
public int characteristics() {
return NONNULL | SIZED | CONCURRENT | SUBSIZED | IMMUTABLE;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment