Skip to content

Instantly share code, notes, and snippets.

@stepancheg
Last active September 11, 2015 00:28
Show Gist options
  • Save stepancheg/eb3848a65bd74c9ade68 to your computer and use it in GitHub Desktop.
Save stepancheg/eb3848a65bd74c9ade68 to your computer and use it in GitHub Desktop.
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