001/*
002 * BridJ - Dynamic and blazing-fast native interop for Java.
003 * http://bridj.googlecode.com/
004 *
005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031package org.bridj;
032
033import java.lang.reflect.ParameterizedType;
034import java.lang.reflect.Type;
035import java.util.*;
036import java.nio.*;
037import java.util.concurrent.ConcurrentHashMap;
038import org.bridj.util.Utils;
039
040/**
041 * Helper class that knows how to read/write data from/to a {@link Pointer}.<br>
042 * 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}).
043 * @author Olivier
044 */
045public abstract class PointerIO<T> {
046        final Type targetType;
047        final Class<?> typedPointerClass;
048        final int targetSize, targetAlignment = -1;
049        
050        public PointerIO(Type targetType, int targetSize, Class<?> typedPointerClass) {
051                this.targetType = targetType;
052                this.targetSize = targetSize;
053                this.typedPointerClass = typedPointerClass;
054        }
055        abstract T get(Pointer<T> pointer, long index);
056        abstract void set(Pointer<T> pointer, long index, T value);
057        public Object getArray(Pointer<T> pointer, long byteOffset, int length) {
058                return pointer.offset(byteOffset).toArray(length);
059        }
060        public <B extends Buffer> B getBuffer(Pointer<T> pointer, long byteOffset, int length) {
061                throw new UnsupportedOperationException("Cannot create a Buffer instance of elements of type " + getTargetType());
062        }
063        public void setArray(Pointer<T> pointer, long byteOffset, Object array) {
064                Object[] a = (Object[])array;
065                for (int i = 0, n = a.length; i < n; i++)
066                        set(pointer, i, (T)a[i]);
067        }
068        
069        public T castTarget(long peer) {
070                throw new UnsupportedOperationException("Cannot cast pointer to " + targetType);
071        }
072        
073        PointerIO<Pointer<T>> getReferenceIO() {
074                return new CommonPointerIOs.PointerPointerIO<T>(this);
075        }
076        public long getTargetSize() {
077                return targetSize;
078        }
079        public long getTargetAlignment() { 
080                return targetAlignment < 0 ? getTargetSize() : targetAlignment;
081        }
082        public boolean isTypedPointer() {
083                return typedPointerClass != null;
084        }
085        public Class<?> getTypedPointerClass() {
086                return typedPointerClass;
087        }
088        public Type getTargetType() {
089                return targetType;
090        }
091        
092        static Class<?> getClass(Type type) {
093                if (type instanceof Class<?>)
094                        return (Class<?>)type;
095                if (type instanceof ParameterizedType)
096                        return getClass(((ParameterizedType)type).getRawType());
097                return null;
098        }
099        
100        private static final PointerIO<Pointer> PointerIO = getPointerInstance((PointerIO)null);
101
102        public static <T> PointerIO<Pointer<T>> getPointerInstance(Type target) {
103                return getPointerInstance((PointerIO<T>)getInstance(target));
104        }
105        public static <T> PointerIO<Pointer<T>> getPointerInstance(PointerIO<T> targetIO) {
106                return new CommonPointerIOs.PointerPointerIO<T>(targetIO);
107        }
108        public static <T> PointerIO<Pointer<T>> getArrayInstance(PointerIO<T> targetIO, long[] dimensions, int iDimension) {
109                return new CommonPointerIOs.PointerArrayIO<T>(targetIO, dimensions, iDimension);
110        }
111        
112        static <T> PointerIO<T> getArrayIO(Object array) {
113                        if (array instanceof int[])
114                        return (PointerIO)CommonPointerIOs.intIO;
115                                if (array instanceof long[])
116                        return (PointerIO)CommonPointerIOs.longIO;
117                                if (array instanceof short[])
118                        return (PointerIO)CommonPointerIOs.shortIO;
119                                if (array instanceof byte[])
120                        return (PointerIO)CommonPointerIOs.byteIO;
121                                if (array instanceof char[])
122                        return (PointerIO)CommonPointerIOs.charIO;
123                                if (array instanceof float[])
124                        return (PointerIO)CommonPointerIOs.floatIO;
125                                if (array instanceof double[])
126                        return (PointerIO)CommonPointerIOs.doubleIO;
127                                if (array instanceof boolean[])
128                        return (PointerIO)CommonPointerIOs.booleanIO;
129                                return PointerIO.getInstance(array.getClass().getComponentType());
130        }   
131        
132        private static final ConcurrentHashMap<StructIO, PointerIO<?>> structIOs = new ConcurrentHashMap<StructIO, PointerIO<?>>();
133        public static <S extends StructObject> PointerIO<S> getInstance(StructIO s) {
134        PointerIO io = structIOs.get(s);
135        if (io == null) {
136            io = new CommonPointerIOs.StructPointerIO(s);
137            PointerIO previousIO = structIOs.putIfAbsent(s, io);
138            if (previousIO != null)
139                io = previousIO;
140        }
141        return io;
142    }
143  private static final ConcurrentHashMap<Type, PointerIO<?>> ios = new ConcurrentHashMap<Type, PointerIO<?>>();
144  static {
145                ios.put(Pointer.class, PointerIO);
146                ios.put(SizeT.class, CommonPointerIOs.SizeTIO);
147                ios.put(TimeT.class, CommonPointerIOs.TimeTIO);
148                ios.put(CLong.class, CommonPointerIOs.CLongIO);
149
150        {
151        PointerIO io = CommonPointerIOs.intIO;
152        ios.put(Integer.TYPE, io);
153        ios.put(Integer.class, io);
154    }
155        {
156        PointerIO io = CommonPointerIOs.longIO;
157        ios.put(Long.TYPE, io);
158        ios.put(Long.class, io);
159    }
160        {
161        PointerIO io = CommonPointerIOs.shortIO;
162        ios.put(Short.TYPE, io);
163        ios.put(Short.class, io);
164    }
165        {
166        PointerIO io = CommonPointerIOs.byteIO;
167        ios.put(Byte.TYPE, io);
168        ios.put(Byte.class, io);
169    }
170        {
171        PointerIO io = CommonPointerIOs.charIO;
172        ios.put(Character.TYPE, io);
173        ios.put(Character.class, io);
174    }
175        {
176        PointerIO io = CommonPointerIOs.floatIO;
177        ios.put(Float.TYPE, io);
178        ios.put(Float.class, io);
179    }
180        {
181        PointerIO io = CommonPointerIOs.doubleIO;
182        ios.put(Double.TYPE, io);
183        ios.put(Double.class, io);
184    }
185        {
186        PointerIO io = CommonPointerIOs.booleanIO;
187        ios.put(Boolean.TYPE, io);
188        ios.put(Boolean.class, io);
189    }
190      }
191        public static <P> PointerIO<P> getInstance(Type type) {
192                if (type == null)
193                        return null;
194
195                PointerIO io = ios.get(type);
196                if (io == null) {
197                        final Class<?> cl = Utils.getClass(type);
198                        if (cl != null) {
199                                if (cl == Pointer.class)
200                                        io = getPointerInstance(((ParameterizedType)type).getActualTypeArguments()[0]);
201                                else if (StructObject.class.isAssignableFrom(cl))
202                                        io = getInstance(StructIO.getInstance((Class)cl, type));
203                                else if (Callback.class.isAssignableFrom(cl))
204                                        io = new CommonPointerIOs.CallbackPointerIO(cl);
205                                else if (NativeObject.class.isAssignableFrom(cl))
206                                        io = new CommonPointerIOs.NativeObjectPointerIO(type);
207                                else if (IntValuedEnum.class.isAssignableFrom(cl)) {
208                                        if (type instanceof ParameterizedType) {
209                                                Type enumType = ((ParameterizedType)type).getActualTypeArguments()[0];
210                                                if (enumType instanceof Class)
211                                                        io = new CommonPointerIOs.IntValuedEnumPointerIO((Class)enumType);
212                                        }
213                                }
214                                else if (TypedPointer.class.isAssignableFrom(cl))
215                                        io = new CommonPointerIOs.TypedPointerPointerIO((Class<? extends TypedPointer>)cl);
216                        }
217                        if (io != null) {
218                                PointerIO previousIO = ios.putIfAbsent(type, io);
219                                if (previousIO != null)
220          io = previousIO; // created io twice : not important in general (expecially not compared to cost of contention on non-concurrent map)
221        }
222      }
223      return io;
224    }
225
226
227                                public static PointerIO<Integer> getIntInstance() {
228      return (PointerIO)CommonPointerIOs.intIO;
229        }
230                        public static PointerIO<Long> getLongInstance() {
231      return (PointerIO)CommonPointerIOs.longIO;
232        }
233                        public static PointerIO<Short> getShortInstance() {
234      return (PointerIO)CommonPointerIOs.shortIO;
235        }
236                        public static PointerIO<Byte> getByteInstance() {
237      return (PointerIO)CommonPointerIOs.byteIO;
238        }
239                        public static PointerIO<Character> getCharInstance() {
240      return (PointerIO)CommonPointerIOs.charIO;
241        }
242                        public static PointerIO<Float> getFloatInstance() {
243      return (PointerIO)CommonPointerIOs.floatIO;
244        }
245                        public static PointerIO<Double> getDoubleInstance() {
246      return (PointerIO)CommonPointerIOs.doubleIO;
247        }
248                        public static PointerIO<Boolean> getBooleanInstance() {
249      return (PointerIO)CommonPointerIOs.booleanIO;
250        }
251                        public static PointerIO<CLong> getCLongInstance() {
252      return (PointerIO)CommonPointerIOs.CLongIO;
253        }
254                        public static PointerIO<SizeT> getSizeTInstance() {
255      return (PointerIO)CommonPointerIOs.SizeTIO;
256        }
257           
258        public static PointerIO<Pointer> getPointerInstance() {
259      return PointerIO;
260        }
261
262        public static PointerIO<TimeT> getTimeTInstance() {
263      return (PointerIO)CommonPointerIOs.TimeTIO;
264        }
265
266    public static <P> PointerIO<P> getBufferPrimitiveInstance(Buffer buffer) {
267                        if (buffer instanceof IntBuffer)
268            return (PointerIO)CommonPointerIOs.intIO;
269                                if (buffer instanceof LongBuffer)
270            return (PointerIO)CommonPointerIOs.longIO;
271                                if (buffer instanceof ShortBuffer)
272            return (PointerIO)CommonPointerIOs.shortIO;
273                                if (buffer instanceof ByteBuffer)
274            return (PointerIO)CommonPointerIOs.byteIO;
275                                if (buffer instanceof CharBuffer)
276            return (PointerIO)CommonPointerIOs.charIO;
277                                if (buffer instanceof FloatBuffer)
278            return (PointerIO)CommonPointerIOs.floatIO;
279                                if (buffer instanceof DoubleBuffer)
280            return (PointerIO)CommonPointerIOs.doubleIO;
281                        throw new UnsupportedOperationException();
282    }
283
284}