Last active
September 11, 2015 00:28
-
-
Save stepancheg/eb3848a65bd74c9ade68 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ru.yandex.salmon.kikimr.v4.unpackedArrayList; | |
import java.lang.invoke.MethodHandle; | |
import java.lang.invoke.MethodHandles; | |
import java.lang.reflect.Field; | |
import java.util.stream.IntStream; | |
import java.util.stream.Stream; | |
import ru.yandex.bolts.collection.Cf; | |
import ru.yandex.bolts.collection.impl.AbstractListF; | |
import ru.yandex.bolts.function.Function0; | |
import ru.yandex.bolts.type.array.ArrayType; | |
import ru.yandex.misc.algo.arrayList.ArrayListImpl; | |
import ru.yandex.misc.jvm.UnsafeUtils; | |
import ru.yandex.misc.reflection.ClassX; | |
import ru.yandex.misc.reflection.FieldX; | |
import ru.yandex.misc.reflection.objenesis.ObjenesisUtils; | |
/** | |
* @author Stepan Koltsov | |
*/ | |
public class UnpackedArrayList<A> extends AbstractListF<A> { | |
private final Factory<A> factory; | |
private int capacity; | |
private int size; | |
private Object[] arrays; | |
private UnpackedArrayList(Factory<A> factory) { | |
this(factory, 0); | |
} | |
private UnpackedArrayList(Factory<A> factory, int capacity) { | |
this.factory = factory; | |
this.arrays = Stream.of(factory.fields).map(f -> f.arrayType.newArray(capacity)).toArray(); | |
this.size = 0; | |
this.capacity = capacity; | |
} | |
private class Accessor implements ArrayListImpl.Accessor { | |
@Override | |
public int capacity() { | |
return capacity; | |
} | |
@Override | |
public int size() { | |
return size; | |
} | |
@Override | |
public void reserveExact(int newCapacity) { | |
for (int i = 0; i < factory.fields.length; ++i) { | |
arrays[i] = factory.fields[i].arrayType.copyOf(arrays[i], newCapacity); | |
} | |
capacity = newCapacity; | |
} | |
} | |
@Override | |
public int size() { | |
return size; | |
} | |
@Override | |
public A get(int index) { | |
if (index >= size) { | |
throw new IllegalArgumentException(); | |
} | |
A r = factory.elementInstantiator.apply(); | |
for (int i = 0; i < factory.fields.length; ++i) { | |
factory.fields[i].handleGet(arrays[i], r, index); | |
} | |
return r; | |
} | |
@Override | |
public A set(int index, A value) { | |
if (value == null) { | |
throw new NullPointerException(); | |
} | |
for (int i = 0; i < factory.fields.length; ++i) { | |
factory.fields[i].handleSet(arrays[i], value, index); | |
} | |
return null; | |
} | |
@Override | |
public boolean add(A value) { | |
ArrayListImpl.prepareAdd(new Accessor()); | |
set(size, value); | |
++size; | |
return true; | |
} | |
@Override | |
public Stream<A> stream() { | |
return IntStream.range(0, size).mapToObj(this::get); | |
} | |
public static class Factory<A> { | |
private abstract static class FieldAccessor<A, B> { | |
private final ArrayType<Object, Object> arrayType; | |
protected final Field field; | |
private final int fieldIndex; | |
protected final long offset; | |
public FieldAccessor(FieldX field, int fieldIndex) { | |
this.fieldIndex = fieldIndex; | |
Class<Object> fieldType = field.getType().getClazz(); | |
if (fieldType.isPrimitive()) { | |
arrayType = (ArrayType<Object, Object>) ArrayType.forElementType(fieldType); | |
} else { | |
arrayType = (ArrayType<Object, Object>) (ArrayType<?, ?>) Cf.ObjectArray; | |
} | |
this.field = field.getField(); | |
this.offset = UnsafeUtils.UNSAFE.objectFieldOffset(field.getField()); | |
} | |
public abstract void handleSet(B array, A value, int index); | |
public abstract void handleGet(B array, A r, int index); | |
} | |
private static class FieldAccessorInt<A> extends FieldAccessor<A, int[]> { | |
public FieldAccessorInt(FieldX field, int fieldIndex) { | |
super(field, fieldIndex); | |
} | |
@Override | |
public void handleGet(int[] array, A r, int index) { | |
UnsafeUtils.UNSAFE.putInt(r, offset, array[index]); | |
} | |
@Override | |
public void handleSet(int[] array, A value, int index) { | |
array[index] = UnsafeUtils.UNSAFE.getInt(value, offset); | |
} | |
} | |
private static class FieldAccessorLong<A> extends FieldAccessor<A, long[]> { | |
public FieldAccessorLong(FieldX field, int fieldIndex) { | |
super(field, fieldIndex); | |
} | |
@Override | |
public void handleGet(long[] array, A r, int index) { | |
UnsafeUtils.UNSAFE.putLong(r, offset, array[index]); | |
} | |
@Override | |
public void handleSet(long[] array, A value, int index) { | |
array[index] = UnsafeUtils.UNSAFE.getLong(value, offset); | |
} | |
} | |
private static class FieldAccessorShort<A> extends FieldAccessor<A, short[]> { | |
public FieldAccessorShort(FieldX field, int fieldIndex) { | |
super(field, fieldIndex); | |
} | |
@Override | |
public void handleGet(short[] array, A r, int index) { | |
UnsafeUtils.UNSAFE.putShort(r, offset, ((short[]) array)[index]); | |
} | |
@Override | |
public void handleSet(short[] array, A value, int index) { | |
array[index] = UnsafeUtils.UNSAFE.getShort(value, offset); | |
} | |
} | |
private static class FieldAccessorByte<A> extends FieldAccessor<A, byte[]> { | |
public FieldAccessorByte(FieldX field, int fieldIndex) { | |
super(field, fieldIndex); | |
} | |
@Override | |
public void handleGet(byte[] array, A r, int index) { | |
UnsafeUtils.UNSAFE.putByte(r, offset, array[index]); | |
} | |
@Override | |
public void handleSet(byte[] array, A value, int index) { | |
array[index] = UnsafeUtils.UNSAFE.getByte(value, offset); | |
} | |
} | |
private static class FieldAccessorBoolean<A> extends FieldAccessor<A, boolean[]> { | |
public FieldAccessorBoolean(FieldX field, int fieldIndex) { | |
super(field, fieldIndex); | |
} | |
@Override | |
public void handleGet(boolean[] array, A r, int index) { | |
UnsafeUtils.UNSAFE.putBoolean(r, offset, array[index]); | |
} | |
@Override | |
public void handleSet(boolean[] array, A value, int index) { | |
array[index] = UnsafeUtils.UNSAFE.getBoolean(value, offset); | |
} | |
} | |
private static class FieldAccessorFloat<A> extends FieldAccessor<A, float[]> { | |
public FieldAccessorFloat(FieldX field, int fieldIndex) { | |
super(field, fieldIndex); | |
} | |
@Override | |
public void handleGet(float[] array, A r, int index) { | |
UnsafeUtils.UNSAFE.putFloat(r, offset, array[index]); | |
} | |
@Override | |
public void handleSet(float[] array, A value, int index) { | |
array[index] = UnsafeUtils.UNSAFE.getFloat(value, offset); | |
} | |
} | |
private static class FieldAccessorDouble<A> extends FieldAccessor<A, double[]> { | |
public FieldAccessorDouble(FieldX field, int fieldIndex) { | |
super(field, fieldIndex); | |
} | |
@Override | |
public void handleGet(double[] array, A r, int index) { | |
UnsafeUtils.UNSAFE.putDouble(r, offset, array[index]); | |
} | |
@Override | |
public void handleSet(double[] array, A value, int index) { | |
array[index] = UnsafeUtils.UNSAFE.getDouble(value, offset); | |
} | |
} | |
private static class FieldAccessorChar<A> extends FieldAccessor<A, char[]> { | |
public FieldAccessorChar(FieldX field, int fieldIndex) { | |
super(field, fieldIndex); | |
} | |
@Override | |
public void handleGet(char[] array, A r, int index) { | |
UnsafeUtils.UNSAFE.putChar(r, offset, array[index]); | |
} | |
@Override | |
public void handleSet(char[] array, A value, int index) { | |
array[index] = UnsafeUtils.UNSAFE.getChar(value, offset); | |
} | |
} | |
private static class FieldAccessorObject<A> extends FieldAccessor<A, Object[]> { | |
public FieldAccessorObject(FieldX field, int fieldIndex) { | |
super(field, fieldIndex); | |
} | |
@Override | |
public void handleGet(Object[] array, A r, int index) { | |
UnsafeUtils.UNSAFE.putObject(r, offset, array[index]); | |
} | |
@Override | |
public void handleSet(Object[] array, A value, int index) { | |
array[index] = UnsafeUtils.UNSAFE.getObject(value, offset); | |
} | |
} | |
private final Function0<A> elementInstantiator; | |
private final FieldAccessor[] fields; | |
public Factory(Class<A> elementType) { | |
this.fields = ClassX.wrap(elementType) | |
.getAllDeclaredInstanceFieldsAccessible() | |
.zipWithIndex() | |
.map((field, fieldIndex) -> { | |
if (field.getField().getType().isPrimitive()) { | |
if (field.getField().getType() == int.class) { | |
return new FieldAccessorInt<>(field, fieldIndex); | |
} else if (field.getField().getType() == long.class) { | |
return new FieldAccessorLong<>(field, fieldIndex); | |
} else if (field.getField().getType() == short.class) { | |
return new FieldAccessorShort<>(field, fieldIndex); | |
} else if (field.getField().getType() == byte.class) { | |
return new FieldAccessorByte<>(field, fieldIndex); | |
} else if (field.getField().getType() == boolean.class) { | |
return new FieldAccessorBoolean<>(field, fieldIndex); | |
} else if (field.getField().getType() == float.class) { | |
return new FieldAccessorFloat<>(field, fieldIndex); | |
} else if (field.getField().getType() == double.class) { | |
return new FieldAccessorDouble<>(field, fieldIndex); | |
} else if (field.getField().getType() == char.class) { | |
return new FieldAccessorChar<>(field, fieldIndex); | |
} else { | |
throw new IllegalArgumentException("unknown type"); | |
} | |
} else { | |
return new FieldAccessorObject<>(field, fieldIndex); | |
} | |
}) | |
.toArray(new FieldAccessor[0]); | |
elementInstantiator = ObjenesisUtils.newInstanceNoCacheF(elementType); | |
} | |
public UnpackedArrayList<A> newInstance() { | |
return new UnpackedArrayList<>(this); | |
} | |
public UnpackedArrayList<A> newWithCapacity(int capacity) { | |
return new UnpackedArrayList<>(this, capacity); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment