001    /*
002     * To change this template, choose Tools | Templates
003     * and open the template in the editor.
004     */
005    
006    package org.bridj.cpp;
007    
008    import java.util.Stack;
009    import java.util.Arrays;
010    import java.util.List;
011    import java.util.ArrayList;
012    import java.lang.reflect.Type;
013    import java.lang.reflect.ParameterizedType;
014    
015    import org.bridj.NativeObject;
016    import org.bridj.Pointer;
017    import org.bridj.StructObject;
018    import org.bridj.ann.Runtime;
019    import org.bridj.ann.Template;
020    import org.bridj.cpp.mfc.MFCRuntime;
021    import org.bridj.BridJ;
022    
023    
024    /**
025     * Representation of a C++ type (including template parameters, which can be types or constants).
026     * @author Olivier
027     */
028    public class CPPType implements ParameterizedType {
029            private final Type[] actualTypeArguments;
030        private final Type ownerType;
031        private final Type rawType;
032        private final Object[] templateParameters;
033            
034        public CPPType(Type ownerType, Type rawType, Object... templateParameters) {
035                    this.ownerType = ownerType;
036                    this.actualTypeArguments = getTypes(templateParameters);
037                    this.rawType = rawType;
038                    this.templateParameters = templateParameters;
039        }
040        public CPPType(Type rawType, Object... templateParameters) {
041            this(null, rawType, templateParameters);
042        }
043        
044            private static Type[] getTypes(Object[] objects) {
045                    List<Type> ret = new ArrayList<Type>(objects.length);
046                    for (int i = 0, n = objects.length; i < n; i++) {
047                            Object o = objects[i];
048                            if (o instanceof Type)
049                                    ret.add((Type)o);
050                    }
051                    return ret.toArray(new Type[ret.size()]);
052            }
053        
054            static Object[] cons(Class firstClass, Object... flattenedClassesAndParams) {
055                    Object[] a = new Object[flattenedClassesAndParams.length + 1];
056                    a[0] = firstClass;
057                    System.arraycopy(flattenedClassesAndParams, 0, a, 1, flattenedClassesAndParams.length);
058                    return a;
059            }
060        public static Type getCPPType(Object... flattenedClassesAndParams) {
061                    int[] position = new int[] { 0 };
062                    Type t = parseCPPType(flattenedClassesAndParams, position);
063                    if (position[0] < flattenedClassesAndParams.length)
064                            parseError("Unexpected trailing parameters", flattenedClassesAndParams, position);
065                    
066                    return t;
067        }
068        static void parseError(String message, Object[] flattenedClassesAndParams, int[] position) {
069                    throw new IllegalArgumentException("Error while parsing C++ type in " + Arrays.asList(flattenedClassesAndParams) + " at offset " + position[0] + " : " + message);
070        }
071        static void notEOF(String message, Object[] flattenedClassesAndParams, int[] position) {
072                    if (position[0] >= flattenedClassesAndParams.length)
073                            throw new IllegalArgumentException("EOF while parsing C++ type in " + Arrays.asList(flattenedClassesAndParams) + " at offset " + position[0] + " : " + message);
074        }
075        
076        static Type parseCPPType(Object[] flattenedClassesAndParams, int[] position) {
077                    notEOF("expecting class", flattenedClassesAndParams, position);
078                    Object oc = flattenedClassesAndParams[position[0]];
079                    if (!(oc instanceof Class))
080                            parseError("expected class", flattenedClassesAndParams, position);
081                    Class<?> c = (Class)oc;
082                    position[0]++;
083                    Template t = c.getAnnotation(Template.class);
084                    
085                    Class<?>[] paramTypes = t == null ? null : t.value();
086                    int nParams = paramTypes == null ? 0 : paramTypes.length;
087                    Object[] params = new Object[nParams];
088                    for (int iParam = 0; iParam < nParams; iParam++) {
089                            notEOF("expecting param " + iParam + " for template " + c.getName(), flattenedClassesAndParams, position);
090                            Object param = flattenedClassesAndParams[position[0]];
091                            Type paramType = paramTypes[iParam];
092                            if (paramType.equals(Class.class) && param.getClass().equals(Class.class))
093                                    param = parseCPPType(flattenedClassesAndParams, position);
094                            else {
095                                    if (!((Class)paramType).isInstance(param))
096                                            parseError("bad type for template param " + iParam + " : expected a " + paramType + ", got " + param, flattenedClassesAndParams, position);
097                                    position[0]++;
098                            }
099                            params[iParam] = param;
100                    }
101                    return nParams == 0 ? c : new CPPType(c, params);
102        }
103        
104        //@Override
105        public Type[] getActualTypeArguments() {
106            return actualTypeArguments.clone();
107        }
108    
109        //@Override
110        public java.lang.reflect.Type getOwnerType() {
111            return ownerType;
112        }
113    
114        //@Override
115        public java.lang.reflect.Type getRawType() {
116            return rawType;
117        }
118        
119            public Object[] getTemplateParameters() {
120                    return templateParameters.clone();
121            }
122            
123            @Override
124            public int hashCode() {
125                    int h = getRawType().hashCode();
126                    if (getOwnerType() != null)
127                            h ^= getOwnerType().hashCode();
128                    for (int i = 0, n = templateParameters.length; i < n; i++)
129                            h ^= templateParameters[i].hashCode();
130                    return h;
131            }
132            
133            static boolean eq(Object a, Object b) {
134                    if ((a == null) != (b == null))
135                            return false;
136                    if (a != null && !a.equals(b))
137                            return false;
138                    return true;
139            }
140            @Override
141            public boolean equals(Object o) {
142                    if (o == null || !(o instanceof CPPType))
143                            return false;
144                    
145                    CPPType t = (CPPType)o;
146                    if (!eq(getRawType(), t.getRawType()))
147                            return false;
148                    if (!eq(getOwnerType(), t.getOwnerType()))
149                            return false;
150                    
151                    Object[] tp = t.templateParameters;
152                    if (templateParameters.length != tp.length)
153                            return false;
154                    
155                    for (int i = 0, n = templateParameters.length; i < n; i++)
156                            if (!eq(templateParameters[i], tp[i]))
157                                    return false;
158                            
159                    return true;
160            }
161            
162            @Override
163            public String toString() {
164                    StringBuilder b = new StringBuilder();
165                    if (getOwnerType() != null)
166                            b.append(getOwnerType()).append('.');
167                    
168                    b.append(getRawType());
169                    int n = templateParameters.length;
170                    if (n != 0) {
171                            b.append('<');
172                            for (int i = 0; i < n; i++) {
173                                    if (i > 0)
174                                            b.append(", ");
175                                    b.append(templateParameters[i]);
176                            }
177                            b.append('>');
178                    }
179                    return b.toString();
180            }
181    }