org.bridj.PointerIO Maven / Gradle / Ivy
package org.bridj;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.nio.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import org.bridj.util.Utils;
/**
* Helper class that knows how to read/write data from/to a {@link Pointer}.
* End users don't need to use this class directly as ({@link Pointer} lets you work with {@link java.lang.reflect.Type} and {@link Class}).
* @author Olivier
*/
public abstract class PointerIO {
final Type targetType;
final Class typedPointerClass;
final int targetSize, targetAlignment = -1;
public PointerIO(Type targetType, int targetSize, Class typedPointerClass) {
this.targetType = targetType;
this.targetSize = targetSize;
this.typedPointerClass = typedPointerClass;
}
abstract T get(Pointer pointer, long index);
abstract void set(Pointer pointer, long index, T value);
public Object getArray(Pointer pointer, long byteOffset, int length) {
return pointer.offset(byteOffset).toArray(length);
}
public B getBuffer(Pointer pointer, long byteOffset, int length) {
throw new UnsupportedOperationException("Cannot create a Buffer instance of elements of type " + getTargetType());
}
public void setArray(Pointer pointer, long byteOffset, Object array) {
Object[] a = (Object[])array;
for (int i = 0, n = a.length; i < n; i++)
set(pointer, i, (T)a[i]);
}
public T castTarget(long peer) {
throw new UnsupportedOperationException("Cannot cast pointer to " + targetType);
}
PointerIO> getReferenceIO() {
return new CommonPointerIOs.PointerPointerIO(this);
}
public long getTargetSize() {
return targetSize;
}
public long getTargetAlignment() {
return targetAlignment < 0 ? getTargetSize() : targetAlignment;
}
public boolean isTypedPointer() {
return typedPointerClass != null;
}
public Class getTypedPointerClass() {
return typedPointerClass;
}
public Type getTargetType() {
return targetType;
}
static Class getClass(Type type) {
if (type instanceof Class)
return (Class)type;
if (type instanceof ParameterizedType)
return getClass(((ParameterizedType)type).getRawType());
return null;
}
public static PointerIO> getPointerInstance(Type target) {
return getPointerInstance((PointerIO)getInstance(target));
}
public static PointerIO> getPointerInstance(PointerIO targetIO) {
return new CommonPointerIOs.PointerPointerIO(targetIO);
}
public static PointerIO> getArrayInstance(PointerIO targetIO, long[] dimensions, int iDimension) {
return new CommonPointerIOs.PointerArrayIO(targetIO, dimensions, iDimension);
}
static PointerIO getArrayIO(Object array) {
if (array instanceof int[])
return (PointerIO)PointerIO.getIntInstance();
if (array instanceof long[])
return (PointerIO)PointerIO.getLongInstance();
if (array instanceof short[])
return (PointerIO)PointerIO.getShortInstance();
if (array instanceof byte[])
return (PointerIO)PointerIO.getByteInstance();
if (array instanceof char[])
return (PointerIO)PointerIO.getCharInstance();
if (array instanceof float[])
return (PointerIO)PointerIO.getFloatInstance();
if (array instanceof double[])
return (PointerIO)PointerIO.getDoubleInstance();
if (array instanceof boolean[])
return (PointerIO)PointerIO.getBooleanInstance();
return PointerIO.getInstance(array.getClass().getComponentType());
}
private static final ConcurrentHashMap> structIOs = new ConcurrentHashMap>();
public static PointerIO getInstance(StructIO s) {
PointerIO io = structIOs.get(s);
if (io == null) {
io = new CommonPointerIOs.StructPointerIO(s);
PointerIO previousIO = structIOs.putIfAbsent(s, io);
if (previousIO != null)
io = previousIO;
}
return io;
}
private static final ConcurrentHashMap> ios = new ConcurrentHashMap>();
public static PointerIO
getInstance(Type type) {
if (type == null)
return null;
PointerIO io = ios.get(type);
if (io == null) {
final Class cl = Utils.getClass(type);
if (type == Integer.TYPE || type == Integer.class)
io = CommonPointerIOs.intIO;
else if (type == Long.TYPE || type == Long.class)
io = CommonPointerIOs.longIO;
else if (type == Short.TYPE || type == Short.class)
io = CommonPointerIOs.shortIO;
else if (type == Byte.TYPE || type == Byte.class)
io = CommonPointerIOs.byteIO;
else if (type == Character.TYPE || type == Character.class)
io = CommonPointerIOs.charIO;
else if (type == Float.TYPE || type == Float.class)
io = CommonPointerIOs.floatIO;
else if (type == Double.TYPE || type == Double.class)
io = CommonPointerIOs.doubleIO;
else if (type == Boolean.TYPE || type == Boolean.class)
io = CommonPointerIOs.booleanIO;
else if (cl != null) {
if (TypedPointer.class.isAssignableFrom(cl))
io = new CommonPointerIOs.TypedPointerPointerIO((Class)cl);
else if (Pointer.class.isAssignableFrom(cl)) {
if (Pointer.class.equals(type) || !(type instanceof ParameterizedType))
io = getPointerInstance((PointerIO)null);
else
io = getPointerInstance(((ParameterizedType)type).getActualTypeArguments()[0]);
}
else if (SizeT.class.isAssignableFrom(cl))
io = CommonPointerIOs.sizeTIO;
else if (TimeT.class.isAssignableFrom(cl))
io = CommonPointerIOs.timeTIO;
else if (CLong.class.isAssignableFrom(cl))
io = CommonPointerIOs.clongIO;
else if (StructObject.class.isAssignableFrom(cl))
io = getInstance(StructIO.getInstance((Class)cl, type));
else if (Callback.class.isAssignableFrom(cl))
io = new CommonPointerIOs.CallbackPointerIO(cl);
else if (NativeObject.class.isAssignableFrom(cl))
io = new CommonPointerIOs.NativeObjectPointerIO(type);
else if (IntValuedEnum.class.isAssignableFrom(cl)) {
if (type instanceof ParameterizedType) {
Type enumType = ((ParameterizedType)type).getActualTypeArguments()[0];
if (enumType instanceof Class)
io = new CommonPointerIOs.IntValuedEnumPointerIO((Class)enumType);
}
}
}
//else
//throw new UnsupportedOperationException("Cannot create pointer io to type " + type + ((type instanceof Class) && ((Class)type).getSuperclass() != null ? " (parent type : " + ((Class)type).getSuperclass().getName() + ")" : ""));
//return null; // TODO throw here ?
//if (io == null)
// throw new RuntimeException("Failed to create pointer io to type " + type);
if (io != null) {
PointerIO previousIO = ios.putIfAbsent(type, io);
if (previousIO != null)
io = previousIO; // created io twice : not important in general (expecially not compared to cost of contention on non-concurrent map)
}
}
return io;
}
private static PointerIO atomicInstance(AtomicReference ref, Type type) {
PointerIO io = (PointerIO)ref.get();
if (io != null)
return io;
if (ref.compareAndSet(null, io = getInstance(type)))
return io;
return (PointerIO)ref.get();
}
private static final AtomicReference> intInstance = new AtomicReference>();
public static PointerIO getIntInstance() {
return atomicInstance(intInstance, Integer.class);
}
/* PointerIO io = intInstance.get();
if (io != null)
return io;
if (intInstance.compareAndSet(null, io = getInstance(Integer.class)))
return io;
return intInstance.get();
}*/
private static final AtomicReference> longInstance = new AtomicReference>();
public static PointerIO getLongInstance() {
return atomicInstance(longInstance, Long.class);
}
/* PointerIO io = longInstance.get();
if (io != null)
return io;
if (longInstance.compareAndSet(null, io = getInstance(Long.class)))
return io;
return longInstance.get();
}*/
private static final AtomicReference> shortInstance = new AtomicReference>();
public static PointerIO getShortInstance() {
return atomicInstance(shortInstance, Short.class);
}
/* PointerIO io = shortInstance.get();
if (io != null)
return io;
if (shortInstance.compareAndSet(null, io = getInstance(Short.class)))
return io;
return shortInstance.get();
}*/
private static final AtomicReference> byteInstance = new AtomicReference>();
public static PointerIO getByteInstance() {
return atomicInstance(byteInstance, Byte.class);
}
/* PointerIO io = byteInstance.get();
if (io != null)
return io;
if (byteInstance.compareAndSet(null, io = getInstance(Byte.class)))
return io;
return byteInstance.get();
}*/
private static final AtomicReference> charInstance = new AtomicReference>();
public static PointerIO getCharInstance() {
return atomicInstance(charInstance, Character.class);
}
/* PointerIO io = charInstance.get();
if (io != null)
return io;
if (charInstance.compareAndSet(null, io = getInstance(Character.class)))
return io;
return charInstance.get();
}*/
private static final AtomicReference> floatInstance = new AtomicReference>();
public static PointerIO getFloatInstance() {
return atomicInstance(floatInstance, Float.class);
}
/* PointerIO io = floatInstance.get();
if (io != null)
return io;
if (floatInstance.compareAndSet(null, io = getInstance(Float.class)))
return io;
return floatInstance.get();
}*/
private static final AtomicReference> doubleInstance = new AtomicReference>();
public static PointerIO getDoubleInstance() {
return atomicInstance(doubleInstance, Double.class);
}
/* PointerIO io = doubleInstance.get();
if (io != null)
return io;
if (doubleInstance.compareAndSet(null, io = getInstance(Double.class)))
return io;
return doubleInstance.get();
}*/
private static final AtomicReference> booleanInstance = new AtomicReference>();
public static PointerIO getBooleanInstance() {
return atomicInstance(booleanInstance, Boolean.class);
}
/* PointerIO io = booleanInstance.get();
if (io != null)
return io;
if (booleanInstance.compareAndSet(null, io = getInstance(Boolean.class)))
return io;
return booleanInstance.get();
}*/
private static final AtomicReference> CLongInstance = new AtomicReference>();
public static PointerIO getCLongInstance() {
return atomicInstance(CLongInstance, CLong.class);
}
/* PointerIO io = CLongInstance.get();
if (io != null)
return io;
if (CLongInstance.compareAndSet(null, io = getInstance(CLong.class)))
return io;
return CLongInstance.get();
}*/
private static final AtomicReference> SizeTInstance = new AtomicReference>();
public static PointerIO getSizeTInstance() {
return atomicInstance(SizeTInstance, SizeT.class);
}
/* PointerIO io = SizeTInstance.get();
if (io != null)
return io;
if (SizeTInstance.compareAndSet(null, io = getInstance(SizeT.class)))
return io;
return SizeTInstance.get();
}*/
private static final AtomicReference> PointerInstance = new AtomicReference>();
public static PointerIO getPointerInstance() {
return atomicInstance(PointerInstance, Pointer.class);
}
/* PointerIO io = PointerInstance.get();
if (io != null)
return io;
if (PointerInstance.compareAndSet(null, io = getInstance(Pointer.class)))
return io;
return PointerInstance.get();
}*/
public static PointerIO
getBufferPrimitiveInstance(Buffer buffer) {
if (buffer instanceof IntBuffer)
return (PointerIO
)getIntInstance();
if (buffer instanceof LongBuffer)
return (PointerIO
)getLongInstance();
if (buffer instanceof ShortBuffer)
return (PointerIO
)getShortInstance();
if (buffer instanceof ByteBuffer)
return (PointerIO
)getByteInstance();
if (buffer instanceof CharBuffer)
return (PointerIO
)getCharInstance();
if (buffer instanceof FloatBuffer)
return (PointerIO
)getFloatInstance();
if (buffer instanceof DoubleBuffer)
return (PointerIO
)getDoubleInstance();
throw new UnsupportedOperationException();
}
private static final AtomicReference stringInstance = new AtomicReference();
public static PointerIO getStringInstance() {
return atomicInstance(stringInstance, String.class);/*
PointerIO io = stringInstance.get();
if (io != null)
return io;
if (stringInstance.compareAndSet(null, io = getInstance(String.class)))
return io;
return stringInstance.get();*/
}
}