001    package org.bridj;
002    
003    import java.lang.reflect.ParameterizedType;
004    import java.lang.reflect.Type;
005    import java.util.*;
006    import java.nio.*;
007    import java.util.concurrent.ConcurrentHashMap;
008    import java.util.concurrent.atomic.AtomicReference;
009    import org.bridj.util.Utils;
010    
011    /**
012     * Helper class that knows how to read/write data from/to a {@link Pointer}.<br>
013     * 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}).
014     * @author Olivier
015     */
016    public abstract class PointerIO<T> {
017            final Type targetType;
018            final Class<?> typedPointerClass;
019            final int targetSize, targetAlignment = -1;
020            
021            public PointerIO(Type targetType, int targetSize, Class<?> typedPointerClass) {
022                    this.targetType = targetType;
023                    this.targetSize = targetSize;
024                    this.typedPointerClass = typedPointerClass;
025            }
026            abstract T get(Pointer<T> pointer, long index);
027            abstract void set(Pointer<T> pointer, long index, T value);
028            public Object getArray(Pointer<T> pointer, long byteOffset, int length) {
029                    return pointer.offset(byteOffset).toArray(length);
030            }
031            public <B extends Buffer> B getBuffer(Pointer<T> pointer, long byteOffset, int length) {
032                    throw new UnsupportedOperationException("Cannot create a Buffer instance of elements of type " + getTargetType());
033            }
034            public void setArray(Pointer<T> pointer, long byteOffset, Object array) {
035                    Object[] a = (Object[])array;
036                    for (int i = 0, n = a.length; i < n; i++)
037                            set(pointer, i, (T)a[i]);
038            }
039            
040            public T castTarget(long peer) {
041                    throw new UnsupportedOperationException("Cannot cast pointer to " + targetType);
042            }
043            
044            PointerIO<Pointer<T>> getReferenceIO() {
045                    return new CommonPointerIOs.PointerPointerIO<T>(this);
046            }
047            public long getTargetSize() {
048                    return targetSize;
049            }
050            public long getTargetAlignment() { 
051                    return targetAlignment < 0 ? getTargetSize() : targetAlignment;
052            }
053            public boolean isTypedPointer() {
054                    return typedPointerClass != null;
055            }
056            public Class<?> getTypedPointerClass() {
057                    return typedPointerClass;
058            }
059            public Type getTargetType() {
060                    return targetType;
061            }
062            
063            static Class<?> getClass(Type type) {
064                    if (type instanceof Class<?>)
065                            return (Class<?>)type;
066                    if (type instanceof ParameterizedType)
067                            return getClass(((ParameterizedType)type).getRawType());
068                    return null;
069            }
070            
071            public static <T> PointerIO<Pointer<T>> getPointerInstance(Type target) {
072                    return getPointerInstance((PointerIO<T>)getInstance(target));
073            }
074            public static <T> PointerIO<Pointer<T>> getPointerInstance(PointerIO<T> targetIO) {
075                    return new CommonPointerIOs.PointerPointerIO<T>(targetIO);
076            }
077            public static <T> PointerIO<Pointer<T>> getArrayInstance(PointerIO<T> targetIO, long[] dimensions, int iDimension) {
078                    return new CommonPointerIOs.PointerArrayIO<T>(targetIO, dimensions, iDimension);
079            }
080            
081            static <T> PointerIO<T> getArrayIO(Object array) {
082                            if (array instanceof int[])
083                            return (PointerIO)PointerIO.getIntInstance();
084                                    if (array instanceof long[])
085                            return (PointerIO)PointerIO.getLongInstance();
086                                    if (array instanceof short[])
087                            return (PointerIO)PointerIO.getShortInstance();
088                                    if (array instanceof byte[])
089                            return (PointerIO)PointerIO.getByteInstance();
090                                    if (array instanceof char[])
091                            return (PointerIO)PointerIO.getCharInstance();
092                                    if (array instanceof float[])
093                            return (PointerIO)PointerIO.getFloatInstance();
094                                    if (array instanceof double[])
095                            return (PointerIO)PointerIO.getDoubleInstance();
096                                    if (array instanceof boolean[])
097                            return (PointerIO)PointerIO.getBooleanInstance();
098                                    return PointerIO.getInstance(array.getClass().getComponentType());
099            }   
100            
101            private static final ConcurrentHashMap<StructIO, PointerIO<?>> structIOs = new ConcurrentHashMap<StructIO, PointerIO<?>>();
102            public static <S extends StructObject> PointerIO<S> getInstance(StructIO s) {
103            PointerIO io = structIOs.get(s);
104            if (io == null) {
105                io = new CommonPointerIOs.StructPointerIO(s);
106                PointerIO previousIO = structIOs.putIfAbsent(s, io);
107                if (previousIO != null)
108                    io = previousIO;
109            }
110            return io;
111        }
112        private static final ConcurrentHashMap<Type, PointerIO<?>> ios = new ConcurrentHashMap<Type, PointerIO<?>>();
113            public static <P> PointerIO<P> getInstance(Type type) {
114            if (type == null)
115                return null;
116            
117                    PointerIO io = ios.get(type);
118            if (io == null) {
119                final Class<?> cl = Utils.getClass(type);
120            
121                                        if (type == Integer.TYPE || type == Integer.class)
122                    io = CommonPointerIOs.intIO;
123                             else             if (type == Long.TYPE || type == Long.class)
124                    io = CommonPointerIOs.longIO;
125                             else             if (type == Short.TYPE || type == Short.class)
126                    io = CommonPointerIOs.shortIO;
127                             else             if (type == Byte.TYPE || type == Byte.class)
128                    io = CommonPointerIOs.byteIO;
129                             else             if (type == Character.TYPE || type == Character.class)
130                    io = CommonPointerIOs.charIO;
131                             else             if (type == Float.TYPE || type == Float.class)
132                    io = CommonPointerIOs.floatIO;
133                             else             if (type == Double.TYPE || type == Double.class)
134                    io = CommonPointerIOs.doubleIO;
135                             else             if (type == Boolean.TYPE || type == Boolean.class)
136                    io = CommonPointerIOs.booleanIO;
137                            else if (cl != null) {
138                        if (TypedPointer.class.isAssignableFrom(cl))
139                                            io = new CommonPointerIOs.TypedPointerPointerIO((Class<? extends TypedPointer>)cl);
140                                    else if (Pointer.class.isAssignableFrom(cl)) {
141                                            if (Pointer.class.equals(type) || !(type instanceof ParameterizedType))
142                                                    io = getPointerInstance((PointerIO<?>)null);
143                                            else
144                                                    io = getPointerInstance(((ParameterizedType)type).getActualTypeArguments()[0]);
145                                    }
146                                    else if (SizeT.class.isAssignableFrom(cl))
147                                            io = CommonPointerIOs.sizeTIO;
148                                    else if (TimeT.class.isAssignableFrom(cl))
149                                            io = CommonPointerIOs.timeTIO;
150                                    else if (CLong.class.isAssignableFrom(cl))
151                                            io = CommonPointerIOs.clongIO;
152                                    else if (StructObject.class.isAssignableFrom(cl))
153                                            io = getInstance(StructIO.getInstance((Class)cl, type));
154                                    else if (Callback.class.isAssignableFrom(cl))
155                                            io = new CommonPointerIOs.CallbackPointerIO(cl);
156                                    else if (NativeObject.class.isAssignableFrom(cl))
157                                            io = new CommonPointerIOs.NativeObjectPointerIO(type);
158                                    else if (IntValuedEnum.class.isAssignableFrom(cl)) {
159                                            if (type instanceof ParameterizedType) {
160                                                    Type enumType = ((ParameterizedType)type).getActualTypeArguments()[0];
161                                                    if (enumType instanceof Class)
162                                                            io = new CommonPointerIOs.IntValuedEnumPointerIO((Class)enumType);
163                                            }
164                                    }
165                            }
166                //else
167                //throw new UnsupportedOperationException("Cannot create pointer io to type " + type + ((type instanceof Class) && ((Class)type).getSuperclass() != null ? " (parent type : " + ((Class)type).getSuperclass().getName() + ")" : ""));
168                    //return null; // TODO throw here ?
169    
170                //if (io == null)
171                //  throw new RuntimeException("Failed to create pointer io to type " + type);
172                if (io != null) {
173                    PointerIO previousIO = ios.putIfAbsent(type, io);
174                    if (previousIO != null)
175                        io = previousIO; // created io twice : not important in general (expecially not compared to cost of contention on non-concurrent map)
176                }
177            }
178            return io;
179        }
180    
181        private static PointerIO atomicInstance(AtomicReference ref, Type type) {
182            PointerIO io = (PointerIO)ref.get();
183            if (io != null)
184                return io;
185    
186            if (ref.compareAndSet(null, io = getInstance(type)))
187                return io;
188                   
189            return (PointerIO)ref.get();
190        }
191    
192        private static final AtomicReference<PointerIO<Integer>> intInstance = new AtomicReference<PointerIO<Integer>>();
193            public static PointerIO<Integer> getIntInstance() {
194            return atomicInstance(intInstance, Integer.class);
195        }
196        /*    PointerIO<Integer> io = intInstance.get();
197            if (io != null)
198                return io;
199    
200            if (intInstance.compareAndSet(null, io = getInstance(Integer.class)))
201                return io;
202                   
203            return intInstance.get();
204            }*/
205        private static final AtomicReference<PointerIO<Long>> longInstance = new AtomicReference<PointerIO<Long>>();
206            public static PointerIO<Long> getLongInstance() {
207            return atomicInstance(longInstance, Long.class);
208        }
209        /*    PointerIO<Long> io = longInstance.get();
210            if (io != null)
211                return io;
212    
213            if (longInstance.compareAndSet(null, io = getInstance(Long.class)))
214                return io;
215                   
216            return longInstance.get();
217            }*/
218        private static final AtomicReference<PointerIO<Short>> shortInstance = new AtomicReference<PointerIO<Short>>();
219            public static PointerIO<Short> getShortInstance() {
220            return atomicInstance(shortInstance, Short.class);
221        }
222        /*    PointerIO<Short> io = shortInstance.get();
223            if (io != null)
224                return io;
225    
226            if (shortInstance.compareAndSet(null, io = getInstance(Short.class)))
227                return io;
228                   
229            return shortInstance.get();
230            }*/
231        private static final AtomicReference<PointerIO<Byte>> byteInstance = new AtomicReference<PointerIO<Byte>>();
232            public static PointerIO<Byte> getByteInstance() {
233            return atomicInstance(byteInstance, Byte.class);
234        }
235        /*    PointerIO<Byte> io = byteInstance.get();
236            if (io != null)
237                return io;
238    
239            if (byteInstance.compareAndSet(null, io = getInstance(Byte.class)))
240                return io;
241                   
242            return byteInstance.get();
243            }*/
244        private static final AtomicReference<PointerIO<Character>> charInstance = new AtomicReference<PointerIO<Character>>();
245            public static PointerIO<Character> getCharInstance() {
246            return atomicInstance(charInstance, Character.class);
247        }
248        /*    PointerIO<Character> io = charInstance.get();
249            if (io != null)
250                return io;
251    
252            if (charInstance.compareAndSet(null, io = getInstance(Character.class)))
253                return io;
254                   
255            return charInstance.get();
256            }*/
257        private static final AtomicReference<PointerIO<Float>> floatInstance = new AtomicReference<PointerIO<Float>>();
258            public static PointerIO<Float> getFloatInstance() {
259            return atomicInstance(floatInstance, Float.class);
260        }
261        /*    PointerIO<Float> io = floatInstance.get();
262            if (io != null)
263                return io;
264    
265            if (floatInstance.compareAndSet(null, io = getInstance(Float.class)))
266                return io;
267                   
268            return floatInstance.get();
269            }*/
270        private static final AtomicReference<PointerIO<Double>> doubleInstance = new AtomicReference<PointerIO<Double>>();
271            public static PointerIO<Double> getDoubleInstance() {
272            return atomicInstance(doubleInstance, Double.class);
273        }
274        /*    PointerIO<Double> io = doubleInstance.get();
275            if (io != null)
276                return io;
277    
278            if (doubleInstance.compareAndSet(null, io = getInstance(Double.class)))
279                return io;
280                   
281            return doubleInstance.get();
282            }*/
283        private static final AtomicReference<PointerIO<Boolean>> booleanInstance = new AtomicReference<PointerIO<Boolean>>();
284            public static PointerIO<Boolean> getBooleanInstance() {
285            return atomicInstance(booleanInstance, Boolean.class);
286        }
287        /*    PointerIO<Boolean> io = booleanInstance.get();
288            if (io != null)
289                return io;
290    
291            if (booleanInstance.compareAndSet(null, io = getInstance(Boolean.class)))
292                return io;
293                   
294            return booleanInstance.get();
295            }*/
296        private static final AtomicReference<PointerIO<CLong>> CLongInstance = new AtomicReference<PointerIO<CLong>>();
297            public static PointerIO<CLong> getCLongInstance() {
298            return atomicInstance(CLongInstance, CLong.class);
299        }
300        /*    PointerIO<CLong> io = CLongInstance.get();
301            if (io != null)
302                return io;
303    
304            if (CLongInstance.compareAndSet(null, io = getInstance(CLong.class)))
305                return io;
306                   
307            return CLongInstance.get();
308            }*/
309        private static final AtomicReference<PointerIO<SizeT>> SizeTInstance = new AtomicReference<PointerIO<SizeT>>();
310            public static PointerIO<SizeT> getSizeTInstance() {
311            return atomicInstance(SizeTInstance, SizeT.class);
312        }
313        /*    PointerIO<SizeT> io = SizeTInstance.get();
314            if (io != null)
315                return io;
316    
317            if (SizeTInstance.compareAndSet(null, io = getInstance(SizeT.class)))
318                return io;
319                   
320            return SizeTInstance.get();
321            }*/
322        private static final AtomicReference<PointerIO<Pointer>> PointerInstance = new AtomicReference<PointerIO<Pointer>>();
323            public static PointerIO<Pointer> getPointerInstance() {
324            return atomicInstance(PointerInstance, Pointer.class);
325        }
326        /*    PointerIO<Pointer> io = PointerInstance.get();
327            if (io != null)
328                return io;
329    
330            if (PointerInstance.compareAndSet(null, io = getInstance(Pointer.class)))
331                return io;
332                   
333            return PointerInstance.get();
334            }*/
335            
336        public static <P> PointerIO<P> getBufferPrimitiveInstance(Buffer buffer) {
337                            if (buffer instanceof IntBuffer)
338                return (PointerIO<P>)getIntInstance();
339                                    if (buffer instanceof LongBuffer)
340                return (PointerIO<P>)getLongInstance();
341                                    if (buffer instanceof ShortBuffer)
342                return (PointerIO<P>)getShortInstance();
343                                    if (buffer instanceof ByteBuffer)
344                return (PointerIO<P>)getByteInstance();
345                                    if (buffer instanceof CharBuffer)
346                return (PointerIO<P>)getCharInstance();
347                                    if (buffer instanceof FloatBuffer)
348                return (PointerIO<P>)getFloatInstance();
349                                    if (buffer instanceof DoubleBuffer)
350                return (PointerIO<P>)getDoubleInstance();
351                            throw new UnsupportedOperationException();
352        }
353    
354        private static final AtomicReference<PointerIO> stringInstance = new AtomicReference<PointerIO>();
355        public static PointerIO<String> getStringInstance() {
356            return atomicInstance(stringInstance, String.class);/*
357            PointerIO io = stringInstance.get();
358            if (io != null)
359                return io;
360    
361            if (stringInstance.compareAndSet(null, io = getInstance(String.class)))
362                return io;
363                   
364            return stringInstance.get();*/
365        }
366    
367    }