1 /*
2  * Copyright (c) 2002-2008 LWJGL Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.lwjgl.util.generator;
33 
34 /**
35  *
36  * This class represent a parameter configuration. There are multiple TypeInfos
37  * in case of multityped parameters.
38  *
39  * @author elias_naur <elias_naur@users.sourceforge.net>
40  * @version $Revision$ $Id$
41  */
42 import org.lwjgl.PointerBuffer;
43 import org.lwjgl.util.generator.opengl.GLvoid;
44 
45 import java.lang.annotation.Annotation;
46 import java.nio.*;
47 import java.util.*;
48 import javax.lang.model.element.AnnotationMirror;
49 import javax.lang.model.element.ExecutableElement;
50 import javax.lang.model.element.VariableElement;
51 import javax.lang.model.type.TypeKind;
52 import javax.lang.model.type.TypeMirror;
53 
54 public class TypeInfo {
55 
56 	public static final String UNSIGNED_PARAMETER_NAME = "unsigned";
57 
58 	private final Signedness signedness;
59 	private final Class      type;
60 	private final String     auto_type;
61 
TypeInfo(Class type, Signedness signedness, String auto_type)62 	private TypeInfo(Class type, Signedness signedness, String auto_type) {
63 		this.type = type;
64 		this.signedness = signedness;
65 		this.auto_type = auto_type;
66 	}
67 
getType()68 	public Class getType() {
69 		return type;
70 	}
71 
getSignedness()72 	public Signedness getSignedness() {
73 		return signedness;
74 	}
75 
getAutoType()76 	public String getAutoType() {
77 		if ( auto_type == null ) {
78 			throw new RuntimeException("No auto type assigned");
79 		}
80 		return auto_type;
81 	}
82 
getTypeFromPrimitiveKind(TypeKind kind)83 	private static Class getTypeFromPrimitiveKind(TypeKind kind) {
84 		Class type;
85 		switch ( kind ) {
86 			case LONG:
87 				type = long.class;
88 				break;
89 			case INT:
90 				type = int.class;
91 				break;
92 			case FLOAT:
93 				type = float.class;
94 				break;
95 			case DOUBLE:
96 				type = double.class;
97 				break;
98 			case SHORT:
99 				type = short.class;
100 				break;
101 			case BYTE:
102 				type = byte.class;
103 				break;
104 			case BOOLEAN:
105 				type = boolean.class;
106 				break;
107 			default:
108 				throw new RuntimeException(kind + " is not allowed");
109 		}
110 		return type;
111 	}
112 
getBufferTypeFromPrimitiveKind(TypeKind kind, AnnotationMirror annotation)113 	private static Class getBufferTypeFromPrimitiveKind(TypeKind kind, AnnotationMirror annotation) {
114 		Class type;
115 		switch ( kind ) {
116 			case INT:
117 				type = IntBuffer.class;
118 				break;
119 			case FLOAT:
120 				type = FloatBuffer.class;
121 				break;
122 			case DOUBLE:
123 				type = DoubleBuffer.class;
124 				break;
125 			case SHORT:
126 				type = ShortBuffer.class;
127 				break;
128 			case LONG:
129 				if ( annotation.getAnnotationType().asElement().getAnnotation(PointerType.class) != null ) {
130 					type = PointerBuffer.class;
131 				} else {
132 					type = LongBuffer.class;
133 				}
134 				break;
135 			case BYTE: /* fall through */
136 
137 			case BOOLEAN:
138 				type = ByteBuffer.class;
139 				break;
140 			default:
141 				throw new RuntimeException(kind + " is not allowed");
142 		}
143 		return type;
144 	}
145 
getDefaultTypeInfo(TypeMirror t)146 	private static TypeInfo getDefaultTypeInfo(TypeMirror t) {
147 		Class java_type = Utils.getJavaType(t);
148 		return new TypeInfo(java_type, Signedness.NONE, null);
149 	}
150 
getDefaultTypeInfoMap(ExecutableElement method)151 	public static Map<VariableElement, TypeInfo> getDefaultTypeInfoMap(ExecutableElement method) {
152 		Map<VariableElement, TypeInfo> map = new HashMap<VariableElement, TypeInfo>();
153 		for ( VariableElement param : method.getParameters() ) {
154 			TypeInfo type_info = getDefaultTypeInfo(param.asType());
155 			map.put(param, type_info);
156 		}
157 		return map;
158 	}
159 
getTypeInfos(TypeMap type_map, VariableElement param)160 	private static Collection<TypeInfo> getTypeInfos(TypeMap type_map, VariableElement param) {
161 		List<? extends AnnotationMirror> annotations = Utils.getSortedAnnotations(param.getAnnotationMirrors());
162 		GLvoid void_annotation = param.getAnnotation(GLvoid.class);
163 
164 		Map<Class, TypeInfo> types = new HashMap<Class, TypeInfo>();
165 		Collection<TypeInfo> multityped_result = new ArrayList<TypeInfo>();
166 		boolean add_default_type = true;
167 		for ( AnnotationMirror annotation : annotations ) {
168 			NativeType native_type_annotation = NativeTypeTranslator.getAnnotation(annotation, NativeType.class);
169 			if ( native_type_annotation != null ) {
170 				Class<? extends Annotation> annotation_type = NativeTypeTranslator.getClassFromType(annotation.getAnnotationType());
171 				Signedness signedness = type_map.getSignednessFromType(annotation_type);
172 				Class inverse_type = type_map.getInverseType(annotation_type);
173 				String auto_type = type_map.getAutoTypeFromAnnotation(annotation);
174 				if ( inverse_type != null ) {
175 					if ( types.containsKey(inverse_type) ) {
176 						TypeInfo inverse_type_info = types.get(inverse_type);
177 						String inverse_auto_type = inverse_type_info.getAutoType();
178 						auto_type = signedness == Signedness.UNSIGNED ? auto_type + " : " + inverse_auto_type : inverse_auto_type + " : " + auto_type;
179 						auto_type = UNSIGNED_PARAMETER_NAME + " ? " + auto_type;
180 						signedness = Signedness.BOTH;
181 						types.remove(inverse_type);
182 						multityped_result.remove(inverse_type_info);
183 					}
184 				}
185 				Class type;
186 				TypeKind kind;
187 				kind = void_annotation == null ? type_map.getPrimitiveTypeFromNativeType(annotation_type) : void_annotation.value();
188 				if ( Utils.getNIOBufferType(param.asType()) != null ) {
189 					type = getBufferTypeFromPrimitiveKind(kind, annotation);
190 				} else {
191 					type = getTypeFromPrimitiveKind(kind);
192 				}
193 				TypeInfo type_info = new TypeInfo(type, signedness, auto_type);
194 				types.put(annotation_type, type_info);
195 				multityped_result.add(type_info);
196 				add_default_type = false;
197 			}
198 		}
199 		if ( add_default_type ) {
200 			TypeInfo default_type_info = getDefaultTypeInfo(param.asType());
201 			Collection<TypeInfo> result = new ArrayList<TypeInfo>();
202 			result.add(default_type_info);
203 			return result;
204 		} else {
205 			return multityped_result;
206 		}
207 	}
208 
getTypeInfoMap(TypeMap type_map, ExecutableElement method)209 	private static Map<VariableElement, Collection<TypeInfo>> getTypeInfoMap(TypeMap type_map, ExecutableElement method) {
210 		Map<VariableElement, Collection<TypeInfo>> map = new HashMap<VariableElement, Collection<TypeInfo>>();
211 		for ( VariableElement param : method.getParameters() ) {
212 			Collection<TypeInfo> types = getTypeInfos(type_map, param);
213 			map.put(param, types);
214 		}
215 		return map;
216 	}
217 
getTypeInfoCrossProduct(TypeMap type_map, ExecutableElement method)218 	public static Collection<Map<VariableElement, TypeInfo>> getTypeInfoCrossProduct(TypeMap type_map, ExecutableElement method) {
219 		List<? extends VariableElement> parameter_collection = method.getParameters();
220 		Collection<Map<VariableElement, TypeInfo>> cross_product = new ArrayList<Map<VariableElement, TypeInfo>>();
221 		getCrossProductRecursive(0, parameter_collection, getTypeInfoMap(type_map, method),
222 			new HashMap<VariableElement, TypeInfo>(), cross_product);
223 		return cross_product;
224 	}
225 
getCrossProductRecursive(int index, List<? extends VariableElement> parameters, Map<VariableElement, Collection<TypeInfo>> typeinfos_map, Map<VariableElement, TypeInfo> current_instance, Collection<Map<VariableElement, TypeInfo>> cross_product)226 	private static void getCrossProductRecursive(int index, List<? extends VariableElement> parameters, Map<VariableElement, Collection<TypeInfo>> typeinfos_map, Map<VariableElement, TypeInfo> current_instance, Collection<Map<VariableElement, TypeInfo>> cross_product) {
227 		if ( index == parameters.size() ) {
228 			/**
229 			 * the last parameter is treated as multi-type only
230 			 */
231 			cross_product.add(current_instance);
232 			return;
233 		}
234 		VariableElement param = parameters.get(index);
235 		Collection<TypeInfo> typeinfos = typeinfos_map.get(param);
236 		if ( typeinfos != null ) {
237 			for ( TypeInfo typeinfo : typeinfos ) {
238 				Map<VariableElement, TypeInfo> instance = new HashMap<VariableElement, TypeInfo>(current_instance);
239 				instance.put(param, typeinfo);
240 				getCrossProductRecursive(index + 1, parameters, typeinfos_map, instance, cross_product);
241 			}
242 		}
243 	}
244 }
245