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 }