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.cpp; 032 033import java.util.Stack; 034import java.util.Arrays; 035import java.util.List; 036import java.util.ArrayList; 037import java.lang.reflect.Type; 038import java.lang.reflect.ParameterizedType; 039 040import org.bridj.NativeObject; 041import org.bridj.Pointer; 042import org.bridj.StructObject; 043import org.bridj.ann.Runtime; 044import org.bridj.ann.Template; 045import org.bridj.cpp.mfc.MFCRuntime; 046import org.bridj.BridJ; 047 048/** 049 * Representation of a C++ type (including template parameters, which can be 050 * types or constants). 051 * 052 * @author Olivier 053 */ 054public class CPPType implements ParameterizedType { 055 056 private final Type[] actualTypeArguments; 057 private final Type ownerType; 058 private final Type rawType; 059 private final Object[] templateParameters; 060 061 public CPPType(Type ownerType, Type rawType, Object... templateParameters) { 062 this.ownerType = ownerType; 063 this.templateParameters = templateParameters == null ? new Object[0] : templateParameters; 064 this.actualTypeArguments = getTypes(this.templateParameters); 065 this.rawType = rawType; 066 } 067 068 public CPPType(Type rawType, Object... templateParameters) { 069 this(null, rawType, templateParameters); 070 } 071 072 private static Type[] getTypes(Object[] objects) { 073// assert objects != null; 074 int n = objects == null ? 0 : objects.length; 075 List<Type> ret = new ArrayList<Type>(n); 076 for (int i = 0; i < n; i++) { 077 Object o = objects[i]; 078 if (o instanceof Type) { 079 ret.add((Type) o); 080 } 081 } 082 return ret.toArray(new Type[ret.size()]); 083 } 084 085 static Object[] cons(Class firstClass, Object... flattenedClassesAndParams) { 086 Object[] a = new Object[flattenedClassesAndParams.length + 1]; 087 a[0] = firstClass; 088 System.arraycopy(flattenedClassesAndParams, 0, a, 1, flattenedClassesAndParams.length); 089 return a; 090 } 091 092 public static Type getCPPType(Object... flattenedClassesAndParams) { 093 int[] position = new int[]{0}; 094 Type t = parseCPPType(flattenedClassesAndParams, position); 095 if (position[0] < flattenedClassesAndParams.length) { 096 parseError("Unexpected trailing parameters", flattenedClassesAndParams, position); 097 } 098 099 return t; 100 } 101 102 static void parseError(String message, Object[] flattenedClassesAndParams, int[] position) { 103 throw new IllegalArgumentException("Error while parsing C++ type in " + Arrays.asList(flattenedClassesAndParams) + " at offset " + position[0] + " : " + message); 104 } 105 106 static void notEOF(String message, Object[] flattenedClassesAndParams, int[] position) { 107 if (position[0] >= flattenedClassesAndParams.length) { 108 throw new IllegalArgumentException("EOF while parsing C++ type in " + Arrays.asList(flattenedClassesAndParams) + " at offset " + position[0] + " : " + message); 109 } 110 } 111 112 static Type parseCPPType(Object[] flattenedClassesAndParams, int[] position) { 113 notEOF("expecting class", flattenedClassesAndParams, position); 114 Object oc = flattenedClassesAndParams[position[0]]; 115 if (!(oc instanceof Class)) { 116 parseError("expected class", flattenedClassesAndParams, position); 117 } 118 Class<?> c = (Class) oc; 119 position[0]++; 120 Template t = c.getAnnotation(Template.class); 121 122 Class<?>[] paramTypes = t == null ? null : t.value(); 123 int nParams = paramTypes == null ? 0 : paramTypes.length; 124 Object[] params = new Object[nParams]; 125 for (int iParam = 0; iParam < nParams; iParam++) { 126 notEOF("expecting param " + iParam + " for template " + c.getName(), flattenedClassesAndParams, position); 127 Object param = flattenedClassesAndParams[position[0]]; 128 Type paramType = paramTypes[iParam]; 129 if (paramType.equals(Class.class) && param.getClass().equals(Class.class)) { 130 param = parseCPPType(flattenedClassesAndParams, position); 131 } else { 132 if (!((Class) paramType).isInstance(param)) { 133 parseError("bad type for template param " + iParam + " : expected a " + paramType + ", got " + param, flattenedClassesAndParams, position); 134 } 135 position[0]++; 136 } 137 params[iParam] = param; 138 } 139 return nParams == 0 ? c : new CPPType(c, params); 140 } 141 142 //@Override 143 public Type[] getActualTypeArguments() { 144 return actualTypeArguments.clone(); 145 } 146 147 //@Override 148 public java.lang.reflect.Type getOwnerType() { 149 return ownerType; 150 } 151 152 //@Override 153 public java.lang.reflect.Type getRawType() { 154 return rawType; 155 } 156 157 public Object[] getTemplateParameters() { 158 return templateParameters.clone(); 159 } 160 161 @Override 162 public int hashCode() { 163 int h = getRawType().hashCode(); 164 if (getOwnerType() != null) { 165 h ^= getOwnerType().hashCode(); 166 } 167 for (int i = 0, n = templateParameters.length; i < n; i++) { 168 h ^= templateParameters[i].hashCode(); 169 } 170 return h; 171 } 172 173 static boolean eq(Object a, Object b) { 174 if ((a == null) != (b == null)) { 175 return false; 176 } 177 if (a != null && !a.equals(b)) { 178 return false; 179 } 180 return true; 181 } 182 183 @Override 184 public boolean equals(Object o) { 185 if (o == null || !(o instanceof CPPType)) { 186 return false; 187 } 188 189 CPPType t = (CPPType) o; 190 if (!eq(getRawType(), t.getRawType())) { 191 return false; 192 } 193 if (!eq(getOwnerType(), t.getOwnerType())) { 194 return false; 195 } 196 197 Object[] tp = t.templateParameters; 198 if (templateParameters.length != tp.length) { 199 return false; 200 } 201 202 for (int i = 0, n = templateParameters.length; i < n; i++) { 203 if (!eq(templateParameters[i], tp[i])) { 204 return false; 205 } 206 } 207 208 return true; 209 } 210 211 @Override 212 public String toString() { 213 StringBuilder b = new StringBuilder(); 214 if (getOwnerType() != null) { 215 b.append(getOwnerType()).append('.'); 216 } 217 218 b.append(getRawType()); 219 int n = templateParameters.length; 220 if (n != 0) { 221 b.append('<'); 222 for (int i = 0; i < n; i++) { 223 if (i > 0) { 224 b.append(", "); 225 } 226 b.append(templateParameters[i]); 227 } 228 b.append('>'); 229 } 230 return b.toString(); 231 } 232}