diff options
45 files changed, 2489 insertions, 835 deletions
diff --git a/make/build-test.xml b/make/build-test.xml index f9092d0..26cbd3d 100644 --- a/make/build-test.xml +++ b/make/build-test.xml @@ -542,7 +542,7 @@ chmod 644 ${results}/* \${line.separator} includeRefid="stub.includes.fileset.test" emitter="com.jogamp.gluegen.JavaEmitter" dumpCPP="false" - debug="false"> + debug="true"> <classpath refid="gluegen.classpath" /> </gluegen> diff --git a/make/scripts/runtest.sh b/make/scripts/runtest.sh index 125c163..aa7d539 100755 --- a/make/scripts/runtest.sh +++ b/make/scripts/runtest.sh @@ -81,7 +81,7 @@ function onetest() { echo } # -onetest com.jogamp.common.GlueGenVersion 2>&1 | tee -a $LOG +#onetest com.jogamp.common.GlueGenVersion 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestSystemPropsAndEnvs 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestVersionInfo 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestVersionNumber 2>&1 | tee -a $LOG @@ -127,6 +127,7 @@ onetest com.jogamp.common.GlueGenVersion 2>&1 | tee -a $LOG #onetest com.jogamp.common.nio.TestByteBufferOutputStream 2>&1 | tee -a $LOG #onetest com.jogamp.common.nio.TestByteBufferCopyStream 2>&1 | tee -a $LOG #onetest com.jogamp.common.os.TestElfReader01 $* 2>&1 | tee -a $LOG +onetest com.jogamp.gluegen.test.junit.internals.TestType 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.PCPPTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter 2>&1 | tee -a $LOG diff --git a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g index 01f10c3..3088610 100644 --- a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g +++ b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g @@ -45,6 +45,7 @@ header { import java.util.*; import antlr.CommonAST; + import com.jogamp.gluegen.JavaConfiguration; import com.jogamp.gluegen.cgram.types.*; } @@ -67,6 +68,12 @@ options { this.debug = debug; } + /** Set the configuration for this + HeaderParser. Must be done before parsing. */ + public void setJavaConfiguration(JavaConfiguration cfg) { + this.cfg = cfg; + } + /** Set the dictionary mapping typedef names to types for this HeaderParser. Must be done before parsing. */ public void setTypedefDictionary(TypeDictionary dict) { @@ -105,7 +112,7 @@ options { // the enumerates from each EnumType, and fill in the enumHash // so that each enumerate maps to the enumType to which it // belongs. - throw new RuntimeException("setEnums is Unimplemented!"); + throw new RuntimeException("setEnums is Unimplemented!"); } /** Returns the EnumTypes this HeaderParser processed. */ @@ -125,14 +132,13 @@ options { return functions; } - private CompoundType lookupInStructDictionary(String typeName, + private CompoundType lookupInStructDictionary(String structName, CompoundTypeKind kind, int cvAttrs) { - CompoundType t = (CompoundType) structDictionary.get(typeName); + CompoundType t = (CompoundType) structDictionary.get(structName); if (t == null) { - t = CompoundType.create(null, null, kind, cvAttrs); - t.setStructName(typeName); - structDictionary.put(typeName, t); + t = CompoundType.create(structName, null, kind, cvAttrs); + structDictionary.put(structName, t); } return t; } @@ -153,8 +159,33 @@ options { this.id = id; this.type = type; } - String id() { return id; } - Type type() { return type; } + String id() { return id; } + Type type() { return type; } + void setType(final Type t) { type = t; } + public String toString() { return "ParamDecl["+id+": "+type.getDebugString()+"]"; } + } + Type resolveAnonCompound(Type type) { + int mode = 0; + debugPrint("resolveAnonCompound: "+type.getDebugString()); + if( !type.hasName() ) { + if( type.isCompound() ) { + final CompoundType ct = type.asCompound(); + // return a copy w/ resolved name + type = ((CompoundType) ct.clone()).evalStructTypeName(); + mode = 1; + } else if( type.isPointer() ) { + // non typedefed PointerType and base-elem w/o name + final PointerType pt = type.asPointer(); + final Type b = pt.getBaseElementType(); + if( b != null && b.isCompound() && !b.hasName() ) { + // return same w/ resolved name + b.asCompound().evalStructTypeName(); + mode = 2; + } + } + } + debugPrintln(" -> "+type.getDebugString()+" - MODE "+mode); + return type; } // A box for a Type. Allows type to be passed down to be modified by recursive rules. @@ -207,22 +238,27 @@ options { } } + private String getDebugTypeString(Type t) { + if(debug) { + return getTypeString(t); + } else { + return null; + } + } private String getTypeString(Type t) { StringBuilder sb = new StringBuilder(); sb.append("["); - sb.append(t); - sb.append(", size: "); if(null!=t) { - SizeThunk st = t.getSize(); - if(null!=st) { - sb.append(st.getClass().getName()); - } else { - sb.append("undef"); - } + sb.append(t.getDebugString()); + sb.append(", opaque ").append(isOpaque(t)).append("]"); + } else { + sb.append("nil]"); } - sb.append("]"); return sb.toString(); } + private boolean isOpaque(final Type type) { + return (cfg.typeInfo(type) != null); + } private void debugPrintln(String msg) { if(debug) { @@ -236,14 +272,13 @@ options { } } - private boolean doDeclaration; // Used to only process function typedefs - private String declId; - private List parameters; + private JavaConfiguration cfg; private TypeDictionary typedefDictionary; private TypeDictionary structDictionary; private List<FunctionSymbol> functions = new ArrayList<FunctionSymbol>(); // hash from name of an enumerated value to the EnumType to which it belongs private HashMap<String, EnumType> enumHash = new HashMap<String, EnumType>(); + private HashMap<String, EnumType> enumMap = new HashMap<String, EnumType>(); // Storage class specifiers private static final int AUTO = 1 << 0; @@ -259,25 +294,36 @@ options { private static final int SIGNED = 1 << 8; private static final int UNSIGNED = 1 << 9; - private void initDeclaration() { - doDeclaration = false; - declId = null; - } + private boolean isFuncDeclaration; // Used to only process function typedefs + private String funcDeclName; + private List<ParameterDeclaration> funcDeclParams; - private void doDeclaration() { - doDeclaration = true; + private void resetFuncDeclaration() { + isFuncDeclaration = false; + funcDeclName = null; + funcDeclParams = null; + } + private void setFuncDeclaration(final String name, final List<ParameterDeclaration> p) { + isFuncDeclaration = true; + funcDeclName = name; + funcDeclParams = p; } private void processDeclaration(Type returnType) { - if (doDeclaration) { - FunctionSymbol sym = new FunctionSymbol(declId, new FunctionType(null, null, returnType, 0)); - if (parameters != null) { // handle funcs w/ empty parameter lists (e.g., "foo()") - for (Iterator iter = parameters.iterator(); iter.hasNext(); ) { - ParameterDeclaration pd = (ParameterDeclaration) iter.next(); + if (isFuncDeclaration) { + final FunctionSymbol sym = new FunctionSymbol(funcDeclName, new FunctionType(null, null, resolveAnonCompound(returnType), 0)); + debugPrintln("Function ... "+sym.toString()); + if (funcDeclParams != null) { // handle funcs w/ empty parameter lists (e.g., "foo()") + for (Iterator<ParameterDeclaration> iter = funcDeclParams.iterator(); iter.hasNext(); ) { + ParameterDeclaration pd = iter.next(); + pd.setType(resolveAnonCompound(pd.type())); + debugPrintln(" add "+pd.toString()); sym.addArgument(pd.type(), pd.id()); } - } + } + debugPrintln("Function Added "+sym.toString()); functions.add(sym); + resetFuncDeclaration(); } } @@ -305,8 +351,7 @@ options { } } tb.setType(canonicalize(new PointerType(SizeThunk.POINTER, - tb.type(), - 0))); + tb.type(), 0, null))); } private int parseIntConstExpr(AST t) throws RecognitionException { @@ -315,47 +360,49 @@ options { /** Utility function: creates a new EnumType with the given name, or returns an existing one if it has already been created. */ - private EnumType getEnumType(String enumTypeName) { + private EnumType getEnumType(String enumTypeName) { EnumType enumType = null; Iterator<EnumType> it = enumHash.values().iterator(); while (it.hasNext()) { EnumType potentialMatch = it.next(); if (potentialMatch.getName().equals(enumTypeName)) { - enumType = potentialMatch; - break; + enumType = potentialMatch; + break; } } if (enumType == null) { - // This isn't quite correct. In theory the enum should expand to - // the size of the largest element, so if there were a long long - // entry the enum should expand to e.g. int64. However, using - // "long" here (which is what used to be the case) was - // definitely incorrect and caused problems. + // This isn't quite correct. In theory the enum should expand to + // the size of the largest element, so if there were a long long + // entry the enum should expand to e.g. int64. However, using + // "long" here (which is what used to be the case) was + // definitely incorrect and caused problems. enumType = new EnumType(enumTypeName, SizeThunk.INT32); } return enumType; - } + } // Map used to canonicalize types. For example, we may typedef // struct foo { ... } *pfoo; subsequent references to struct foo* should // point to the same PointerType object that had its name set to "pfoo". - private Map canonMap = new HashMap(); + // Opaque canonical types are excluded. + private Map<Type, Type> canonMap = new HashMap<Type, Type>(); private Type canonicalize(Type t) { Type res = (Type) canonMap.get(t); if (res != null) { return res; + } else { + canonMap.put(t, t); + return t; } - canonMap.put(t, t); - return t; } } declarator[TypeBox tb] returns [String s] { - initDeclaration(); + resetFuncDeclaration(); s = null; - List params = null; + List<ParameterDeclaration> params = null; String funcPointerName = null; TypeBox dummyTypeBox = null; } @@ -374,28 +421,25 @@ declarator[TypeBox tb] returns [String s] { RPAREN ) { if (id != null) { - declId = id.getText(); - parameters = params; // FIXME: Ken, why are we setting this class member here? - doDeclaration(); + setFuncDeclaration(id.getText(), params); } else if ( funcPointerName != null ) { /* TypeBox becomes function pointer in this case */ FunctionType ft = new FunctionType(null, null, tb.type(), 0); if (params == null) { - // If the function pointer has no declared parameters, it's a - // void function. I'm not sure if the parameter name is - // ever referenced anywhere when the type is VoidType, so + // If the function pointer has no declared parameters, it's a + // void function. I'm not sure if the parameter name is + // ever referenced anywhere when the type is VoidType, so // just in case I'll set it to a comment string so it will - // still compile if written out to code anywhere. - ft.addArgument(new VoidType(0), "/*unnamed-void*/"); - } else { - for (Iterator iter = params.iterator(); iter.hasNext(); ) { - ParameterDeclaration pd = (ParameterDeclaration) iter.next(); - ft.addArgument(pd.type(), pd.id()); - } + // still compile if written out to code anywhere. + ft.addArgument(new VoidType(0), "/*unnamed-void*/"); + } else { + for (Iterator iter = params.iterator(); iter.hasNext(); ) { + ParameterDeclaration pd = (ParameterDeclaration) iter.next(); + ft.addArgument(pd.type(), pd.id()); + } } tb.setType(canonicalize(new PointerType(SizeThunk.POINTER, - ft, - 0))); + ft, 0, null))); s = funcPointerName; } } @@ -422,8 +466,8 @@ declaration { ) { processDeclaration(tb.type()); } ; -parameterTypeList returns [List l] { l = new ArrayList(); ParameterDeclaration decl = null; } - : ( decl = parameterDeclaration { if (decl != null) l.add(decl); } ( COMMA | SEMI )? )+ ( VARARGS )? +parameterTypeList returns [List<ParameterDeclaration> l] { l = new ArrayList<ParameterDeclaration>(); ParameterDeclaration decl = null; } + : ( decl = parameterDeclaration { if (decl != null) { l.add(decl); } } ( COMMA | SEMI )? )+ ( VARARGS )? ; parameterDeclaration returns [ParameterDeclaration pd] { @@ -533,9 +577,12 @@ typeSpecifier[int attributes] returns [Type t] { typedefName[int cvAttrs] returns [Type t] { t = null; } : #(NTypedefName id : ID) { - Type tdict = lookupInTypedefDictionary(id.getText()); - t = canonicalize(tdict.getCVVariant(cvAttrs)); - debugPrintln("Adding typedef canon : [" + id.getText() + "] -> [" + tdict + "] -> "+getTypeString(t)); + final Type t0 = lookupInTypedefDictionary(id.getText()); + debugPrint("Adding typedef lookup: [" + id.getText() + "] -> "+getDebugTypeString(t0)); + final Type t1 = t0.getCVVariant(cvAttrs); + debugPrintln(" - cvvar -> "+getDebugTypeString(t1)); + t = canonicalize(t1); + debugPrintln(" - canon -> "+getDebugTypeString(t)); } ; @@ -549,25 +596,35 @@ unionSpecifier[int cvAttrs] returns [Type t] { t = null; } structOrUnionBody[CompoundTypeKind kind, int cvAttrs] returns [CompoundType t] { t = null; + boolean addedAny = false; } : ( (ID LCURLY) => id:ID LCURLY { + // fully declared struct, i.e. not anonymous t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs)); - } ( structDeclarationList[t] )? - RCURLY { t.setBodyParsed(); } - | LCURLY { t = CompoundType.create(null, null, kind, cvAttrs); } - ( structDeclarationList[t] )? - RCURLY { t.setBodyParsed(); } - | id2:ID { t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs)); } + } ( addedAny = structDeclarationList[t] )? + RCURLY { t.setBodyParsed(addedAny); } + | LCURLY { + // anonymous declared struct + t = CompoundType.create(null, null, kind, cvAttrs); + } ( structDeclarationList[t] )? + RCURLY { t.setBodyParsed(false); } + | id2:ID { + // anonymous struct + t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs)); + } ) ; -structDeclarationList[CompoundType t] - : ( structDeclaration[t] )+ +structDeclarationList[CompoundType t] returns [boolean addedAny] { + addedAny = false; + boolean addedOne = false; +} + : ( addedOne = structDeclaration[t] { addedAny |= addedOne; } )+ ; -structDeclaration[CompoundType containingType] { +structDeclaration[CompoundType containingType] returns [boolean addedAny] { + addedAny = false; Type t = null; - boolean addedAny = false; } : t = specifierQualifierList addedAny = structDeclaratorList[containingType, t] { if (!addedAny) { @@ -629,13 +686,28 @@ structDeclarator[CompoundType containingType, Type t] returns [boolean addedAny] // "enumName" *before* executing the enumList rule. enumSpecifier [int cvAttrs] returns [Type t] { t = null; + EnumType e = null; } : #( "enum" - ( ( ID LCURLY )=> i:ID LCURLY enumList[(EnumType)(t = getEnumType(i.getText()))] RCURLY - | LCURLY enumList[(EnumType)(t = getEnumType(ANONYMOUS_ENUM_NAME))] RCURLY - | ID { t = getEnumType(i.getText()); } - ) - ) + ( ( ID LCURLY )=> i:ID LCURLY enumList[(EnumType)(e = getEnumType(i.getText()))] RCURLY + | LCURLY enumList[(EnumType)(e = getEnumType(ANONYMOUS_ENUM_NAME))] RCURLY + | ID { e = getEnumType(i.getText()); } + ) { + debugPrintln("Adding enum mapping: "+getDebugTypeString(e)); + if( null != e ) { + final String eName = e.getName(); + if( null != eName && !eName.equals(ANONYMOUS_ENUM_NAME) ) { // validate only non-anonymous enum + final EnumType dupE = enumMap.get(eName); + if( null != dupE && !dupE.equalSemantics(e) ) { + throw new RuntimeException(String.format("Duplicate enum w/ incompatible type:%n have '%s',%n this '%s'", + getTypeString(dupE), getTypeString(e))); + } + enumMap.put(eName, (EnumType)e.clone()); + } + } + t = e; // return val + } + ) ; enumList[EnumType enumeration] { @@ -648,42 +720,42 @@ enumerator[EnumType enumeration, long defaultValue] returns [long newDefaultValu newDefaultValue = defaultValue; } : eName:ID ( ASSIGN eVal:expr )? { - long value = 0; + final long newValue; if (eVal != null) { String vTxt = eVal.getAllChildrenText(); if (enumHash.containsKey(vTxt)) { EnumType oldEnumType = enumHash.get(vTxt); - value = oldEnumType.getEnumValue(vTxt); + newValue = oldEnumType.getEnumValue(vTxt); } else { try { - value = Long.decode(vTxt).longValue(); + newValue = Long.decode(vTxt).longValue(); } catch (NumberFormatException e) { System.err.println("NumberFormatException: ID[" + eName.getText() + "], VALUE=[" + vTxt + "]"); throw e; } } } else { - value = defaultValue; + newValue = defaultValue; } - newDefaultValue = value+1; - String eTxt = eName.getText(); - if (enumHash.containsKey(eTxt)) { - EnumType oldEnumType = enumHash.get(eTxt); - long oldValue = oldEnumType.getEnumValue(eTxt); - System.err.println("WARNING: redefinition of enumerated value '" + eTxt + "';" + - " existing definition is in enumeration '" + oldEnumType.getName() + - "' with value " + oldValue + " and new definition is in enumeration '" + - enumeration.getName() + "' with value " + value); - // remove old definition - oldEnumType.removeEnumerate(eTxt); - } - // insert new definition - enumeration.addEnum(eTxt, value); - enumHash.put(eTxt, enumeration); - debugPrintln("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + enumeration.getEnumValue(eTxt) + - " (new default = " + newDefaultValue + ")"); - } + newDefaultValue = newValue+1; + String eTxt = eName.getText(); + if (enumHash.containsKey(eTxt)) { + EnumType oldEnumType = enumHash.get(eTxt); + final long oldValue = oldEnumType.getEnumValue(eTxt); + if( oldValue != newValue ) { + throw new RuntimeException(String.format("Duplicate enum value '%s.%s' w/ diff value:%n have %d,%n this %d", + oldEnumType.getName(), eTxt, oldValue, newValue)); + } + // remove old definition + oldEnumType.removeEnumerate(eTxt); + } + // insert new definition + enumeration.addEnum(eTxt, newValue); + enumHash.put(eTxt, enumeration); + debugPrintln("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + enumeration.getEnumValue(eTxt) + + " (new default = " + newDefaultValue + ")"); + } ; initDeclList[TypeBox tb] @@ -705,18 +777,48 @@ initDecl[TypeBox tb] { { if ((declName != null) && (tb != null) && tb.isTypedef()) { Type t = tb.type(); - debugPrint("Adding typedef mapping: [" + declName + "] -> "+getTypeString(t)); + debugPrint("Adding typedef mapping: [" + declName + "] -> "+getDebugTypeString(t)); if (!t.hasTypedefName()) { - t.setName(declName); - debugPrint(" - declName -> "+getTypeString(t)); + if( t.isCompound() ) { + // Allow redefinition of newly defined struct, i.e. use same instance. + // This aliases '_a' -> 'A' for 'typedef struct _a { } A, *B;', where '*B' will become also '*A'. + t.setTypedefName(declName); + debugPrint(" - redefine -> "+getDebugTypeString(t)); + } else { + // Use new typedef, using a copy to preserve canonicalized base type + t = (Type) t.clone(); + t.setTypedefName(declName); + debugPrint(" - newdefine -> "+getDebugTypeString(t)); + } } else { - // copy type to preserve declName ! - t = (Type) t.clone(); - t.setName(declName); - debugPrint(" - copy -> "+getTypeString(t)); + // Adds typeInfo alias w/ t's typeInfo, if exists + cfg.addTypeInfo(declName, t); + final Type alias; + if( t.isCompound() ) { + // Attempt to find a previous declared compound typedef + // This aliases 'D' -> 'A' for 'typedef struct _a { } A, D;' + alias = typedefDictionary.getEqualSemantics1(t, cfg, true); + } else { + alias = null; + } + if( null != alias ) { + // use previous typedef + t = alias; + debugPrint(" - alias -> "+getDebugTypeString(t)); + } else { + // copy to preserve canonicalized base type + t = (Type) t.clone(); + t.setTypedefName(declName); + debugPrint(" - copy -> "+getDebugTypeString(t)); + } + } + final Type dupT = typedefDictionary.get(declName); + if( null != dupT && !dupT.equalSemantics(t) ) { + throw new RuntimeException(String.format("Duplicate typedef w/ incompatible type:%n have '%s',%n this '%s'", + getTypeString(dupT), getTypeString(t))); } t = canonicalize(t); - debugPrintln(" - canon -> "+getTypeString(t)); + debugPrintln(" - canon -> "+getDebugTypeString(t)); typedefDictionary.put(declName, t); // Clear out PointerGroup effects in case another typedef variant follows tb.reset(); @@ -731,7 +833,7 @@ pointerGroup[TypeBox tb] { int x = 0; int y = 0; } if (tb != null) { tb.setType(canonicalize(new PointerType(SizeThunk.POINTER, tb.type(), - attrs2CVAttrs(x)))); + attrs2CVAttrs(x), null))); } } )+ ) diff --git a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java index 93a1ecc..734f536 100644 --- a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java +++ b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java @@ -51,13 +51,14 @@ import java.util.logging.Logger; /** Emits the C-side component of the Java<->C JNI binding. */ public class CMethodBindingEmitter extends FunctionEmitter { - protected static final Logger LOG = Logger.getLogger(CMethodBindingEmitter.class.getPackage().getName()); protected static final CommentEmitter defaultCommentEmitter = new DefaultCommentEmitter(); protected static final String arrayResLength = "_array_res_length"; protected static final String arrayRes = "_array_res"; protected static final String arrayIdx = "_array_idx"; + protected final Logger LOG; + protected MethodBinding binding; /** Name of the package in which the corresponding Java method resides.*/ @@ -124,9 +125,11 @@ public class CMethodBindingEmitter extends FunctionEmitter { final boolean isJavaMethodStatic, final boolean forImplementingMethodCall, final boolean forIndirectBufferAndArrayImplementation, - final MachineDataInfo machDesc) + final MachineDataInfo machDesc, + final JavaConfiguration configuration) { - super(output, false); + super(output, false, configuration); + LOG = Logging.getLogger(CMethodBindingEmitter.class.getPackage().getName()); assert(binding != null); assert(javaClassName != null); @@ -152,6 +155,11 @@ public class CMethodBindingEmitter extends FunctionEmitter { return binding.getName(); } + @Override + public FunctionSymbol getCSymbol() { + return binding.getCSymbol(); + } + /** * Get the expression for the capacity of the returned java.nio.Buffer. */ @@ -451,7 +459,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { if (!cReturnType.isVoid()) { writer.print(" "); // Note we must respect const/volatile for return argument - writer.print(binding.getCSymbol().getReturnType().getName(true)); + writer.print(binding.getCSymbol().getReturnType().getCName(true)); writer.println(" _res;"); if (javaReturnType.isNIOByteBufferArray() || javaReturnType.isArrayOfCompoundTypeWrappers()) { @@ -569,7 +577,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { writer.println(" if ( NULL != " + javaArgName + " ) {"); final Type cArgType = binding.getCArgumentType(i); - String cArgTypeName = cArgType.getName(); + String cArgTypeName = cArgType.getCName(); final String convName = pointerConversionArgumentName(javaArgName); @@ -654,7 +662,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { emitMalloc( writer, convName+"_copy", - cArgElementType.getName(), + cArgElementType.getCName(), isBaseTypeConst(cArgType), arrayLenName, "Could not allocate buffer for copying data in argument \\\""+javaArgName+"\\\""); @@ -692,7 +700,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { in the method binding. */ emitGetDirectBufferAddress(writer, "_tmpObj", - cArgElementType.getName(), + cArgElementType.getCName(), convName + "_copy[_copyIndex]", true, "_offsetHandle[_copyIndex]", true); @@ -702,7 +710,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { // offset argument emitGetDirectBufferAddress(writer, "_tmpObj", - cArgElementType.getName(), + cArgElementType.getCName(), "("+convName + "_copy + _copyIndex)", false /* !receivingIsPtrPtr -> linear layout -> use memcpy */, null, true); @@ -719,13 +727,13 @@ public class CMethodBindingEmitter extends FunctionEmitter { emitMalloc( writer, convName+"_copy[_copyIndex]", - cArgElementType2.getName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !! + cArgElementType2.getCName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !! isBaseTypeConst(cArgType), "(*env)->GetArrayLength(env, _tmpObj)", "Could not allocate buffer during copying of data in argument \\\""+javaArgName+"\\\""); // FIXME: copy the data (use matched Get/ReleasePrimitiveArrayCritical() calls) if (true) { - throw new RuntimeException("Cannot yet handle type \"" + cArgType.getName() + + throw new RuntimeException("Cannot yet handle type \"" + cArgType.getCName() + "\"; need to add support for copying ptr-to-ptr-to-primitiveType subarrays"); } @@ -804,7 +812,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { writer.println(" _tmpObj = (*env)->GetObjectArrayElement(env, " + javaArgName + ", _copyIndex);"); emitReturnDirectBufferAddress(writer, "_tmpObj", - cArgType.asArray().getBaseElementType().getName(), + cArgType.asArray().getBaseElementType().getCName(), "("+convName + "_copy + _copyIndex)", false /* receivingIsPtrPtr */, null); @@ -855,7 +863,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { writer.println(");"); } else { if (true) throw new RuntimeException( - "Cannot yet handle type \"" + cArgType.getName() + + "Cannot yet handle type \"" + cArgType.getCName() + "\"; need to add support for cleaning up copied ptr-to-ptr-to-primitiveType subarrays"); } writer.println(" }"); @@ -927,7 +935,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { } } - writer.print(cArgType.getName()); + writer.print(cArgType.getCName()); writer.print(") "); if (cArgType.isPointer() && javaArgType.isPrimitive()) { writer.print("(intptr_t) "); @@ -1020,7 +1028,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { if (returnValueCapacityExpression != null) { returnSizeOf = returnValueCapacityExpression.format(argumentNameArray()); } else { - returnSizeOf = "sizeof(" + cReturnType.getName() + ")"; + returnSizeOf = "sizeof(" + cReturnType.getCName() + ")"; } writer.println(" return JVMUtil_NewDirectByteBufferCopy(env, &_res, "+returnSizeOf+");"); } else if (javaReturnType.isNIOBuffer() || javaReturnType.isCompoundTypeWrapper()) { @@ -1029,27 +1037,66 @@ public class CMethodBindingEmitter extends FunctionEmitter { // See whether capacity has been specified if (returnValueCapacityExpression != null) { - writer.print( returnValueCapacityExpression.format( argumentNameArray() ) ); + writer.println( returnValueCapacityExpression.format( argumentNameArray() ) + ");"); } else { - if (cReturnType.isPointer() && - cReturnType.asPointer().getTargetType().isCompound()) { - if (cReturnType.asPointer().getTargetType().getSize() == null) { - throw new RuntimeException( - "Error emitting code for compound return type "+ - "for function \"" + binding + "\": " + - "Structs to be emitted should have been laid out by this point " + - "(type " + cReturnType.asPointer().getTargetType().getName() + " / " + - cReturnType.asPointer().getTargetType() + " was not) for "+binding - ); + final Type cReturnTargetType = cReturnType.isPointer() ? cReturnType.getTargetType() : null; + int mode = 0; + if ( 1 == cReturnType.pointerDepth() && null != cReturnTargetType ) { + if( cReturnTargetType.isCompound() ) { + if( !cReturnTargetType.isAnonymous() && + cReturnTargetType.asCompound().getNumFields() > 0 ) + { + // fully declared non-anonymous struct pointer: pass content + if ( cReturnTargetType.getSize() == null ) { + throw new RuntimeException( + "Error emitting code for compound return type "+ + "for function \"" + binding + "\": " + + "Structs to be emitted should have been laid out by this point " + + "(type " + cReturnTargetType.getCName() + " / " + + cReturnTargetType.getDebugString() + " was not) for "+binding + ); + } + writer.println("sizeof(" + cReturnTargetType.getCName() + ") );"); + mode = 10; + } else if( cReturnTargetType.asCompound().getNumFields() == 0 ) { + // anonymous struct pointer: pass pointer + writer.println("sizeof(" + cReturnType.getCName() + ") );"); + mode = 11; + } + } + if( 0 == mode ) { + if( cReturnTargetType.isPrimitive() ) { + // primitive pointer: pass primitive + writer.println("sizeof(" + cReturnTargetType.getCName() + ") );"); + mode = 20; + } else if( cReturnTargetType.isVoid() ) { + // void pointer: pass pointer + writer.println("sizeof(" + cReturnType.getCName() + ") );"); + mode = 21; + } + } + } + if( 0 == mode ) { + if( null != cfg.typeInfo(cReturnType) ) { + // Opaque + writer.println("sizeof(" + cReturnType.getCName() + ") );"); + mode = 88; + } else { + final String wmsg = "Assumed return size of equivalent C return type"; + writer.println("sizeof(" + cReturnType.getCName() + ") ); // WARNING: "+wmsg); + mode = 99; + LOG.warning( + "No capacity specified for java.nio.Buffer return " + + "value for function \"" + binding.getName() + "\". " + wmsg + " (sizeof(" + cReturnType.getCName() + ")): " + binding); } } - writer.print("sizeof(" + cReturnType.getName() + ")"); - LOG.warning( - "No capacity specified for java.nio.Buffer return " + - "value for function \"" + binding.getName() + "\"" + - " assuming size of equivalent C return type (sizeof(" + cReturnType.getName() + ")): " + binding); + writer.println(" /** "); + writer.println(" * mode: "+mode); + writer.println(" * cReturnType: "+cReturnType.getDebugString()); + writer.println(" * cReturnTargetType: "+cReturnTargetType.getDebugString()); + writer.println(" * javaReturnType: "+javaReturnType.getDebugString()); + writer.println(" */"); } - writer.println(");"); } else if (javaReturnType.isString()) { writer.println(" if (NULL == _res) return NULL;"); writer.println(" return (*env)->NewStringUTF(env, _res);"); @@ -1071,7 +1118,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { pointerType = retType.asArray().getBaseElementType(); } writer.println(" (*env)->SetObjectArrayElement(env, " + arrayRes + ", " + arrayIdx + - ", (*env)->NewDirectByteBuffer(env, (void *)_res[" + arrayIdx + "], sizeof(" + pointerType.getName() + ")));"); + ", (*env)->NewDirectByteBuffer(env, (void *)_res[" + arrayIdx + "], sizeof(" + pointerType.getCName() + ")));"); writer.println(" }"); writer.println(" return " + arrayRes + ";"); } else if (javaReturnType.isArray()) { @@ -1386,33 +1433,34 @@ public class CMethodBindingEmitter extends FunctionEmitter { // Note that we don't need to obey const/volatile for outgoing arguments // if (javaType.isNIOBuffer()) { - ptrTypeString = cType.getName(); + // primitive NIO object + ptrTypeString = cType.getCName(); } else if (javaType.isArray() || javaType.isArrayOfCompoundTypeWrappers()) { needsDataCopy = javaArgTypeNeedsDataCopy(javaType); if (javaType.isPrimitiveArray() || javaType.isNIOBufferArray() || javaType.isArrayOfCompoundTypeWrappers()) { - ptrTypeString = cType.getName(); + ptrTypeString = cType.getCName(); } else if (!javaType.isStringArray()) { final Class<?> elementType = javaType.getJavaClass().getComponentType(); if (elementType.isArray()) { final Class<?> subElementType = elementType.getComponentType(); if (subElementType.isPrimitive()) { // type is pointer to pointer to primitive - ptrTypeString = cType.getName(); + ptrTypeString = cType.getCName(); } else { // type is pointer to pointer of some type we don't support (maybe // it's an array of pointers to structs?) - throw new RuntimeException("Unsupported pointer type: \"" + cType.getName() + "\""); + throw new RuntimeException("Unsupported pointer type: \"" + cType.getCName() + "\""); } } else { // type is pointer to pointer of some type we don't support (maybe // it's an array of pointers to structs?) - throw new RuntimeException("Unsupported pointer type: \"" + cType.getName() + "\""); + throw new RuntimeException("Unsupported pointer type: \"" + cType.getCName() + "\""); } } } else { - ptrTypeString = cType.getName(); + ptrTypeString = cType.getCName(); } writer.print(" "); @@ -1434,7 +1482,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { String cElementTypeName = "char *"; final PointerType cPtrType = cType.asPointer(); if (cPtrType != null) { - cElementTypeName = cPtrType.getTargetType().asPointer().getName(); + cElementTypeName = cPtrType.getTargetType().asPointer().getCName(); } if (isBaseTypeConst(cType)) { writer.print("const "); @@ -1470,9 +1518,9 @@ public class CMethodBindingEmitter extends FunctionEmitter { final String cVariableType; if( !cType.isPointer() && type.isCompoundTypeWrapper() ) { // FIXME: Compound call-by-value - cVariableType = cType.getName()+" *"; + cVariableType = cType.getCName()+" *"; } else { - cVariableType = cType.getName(); + cVariableType = cType.getCName(); } emitGetDirectBufferAddress(writer, incomingArgumentName, diff --git a/src/java/com/jogamp/gluegen/ConstantDefinition.java b/src/java/com/jogamp/gluegen/ConstantDefinition.java index ca67001..78d2e43 100644 --- a/src/java/com/jogamp/gluegen/ConstantDefinition.java +++ b/src/java/com/jogamp/gluegen/ConstantDefinition.java @@ -33,100 +33,131 @@ package com.jogamp.gluegen; -import java.util.*; +import com.jogamp.gluegen.cgram.types.AliasedSymbol.AliasedSymbolImpl; +import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; /** Represents the definition of a constant which was provided either via a #define statement or through an enum definition. */ -public class ConstantDefinition { - - private final String origName; - private final HashSet<String> aliasedNames; - private String name; - private final String value; +public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSemanticSymbol { + private final boolean relaxedEqSem; + private final String sValue; + private final long iValue; + private final boolean hasIntValue; private final boolean isEnum; private final String enumName; - private Set<String> aliases; + /** Covering enums */ public ConstantDefinition(final String name, - final String value, - final boolean isEnum, + final long value, final String enumName) { - this.origName = name; - this.name = name; - this.value = value; - this.isEnum = isEnum; + super(name); + this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest(); + this.sValue = String.valueOf(value); + this.iValue = value; + this.hasIntValue = true; + this.isEnum = true; this.enumName = enumName; - this.aliasedNames=new HashSet<String>(); - } - - public boolean equals(final ConstantDefinition other) { - return (equals(name, other.name) && - equals(value, other.value) && - equals(enumName, other.enumName)); } - private boolean equals(final String s1, final String s2) { - if (s1 == null || s2 == null) { - if (s1 == null && s2 == null) { - return true; + /** Covering defines */ + public ConstantDefinition(final String name, + final String value) { + super(name); + this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest(); + this.sValue = value; + { + // Attempt to parse define string as number + long v; + boolean b; + try { + v = Long.decode(value).longValue(); + b = true; + } catch (final NumberFormatException e) { + v = 0; + b = false; } - return false; + this.iValue = v; + this.hasIntValue = b; } - - return s1.equals(s2); + this.isEnum = false; + this.enumName = null; } + /** + * Hash by its given {@link #getName() name}. + */ @Override - public int hashCode() { - return name.hashCode(); - } - - /** Supports renaming in Java binding. */ - public void rename(final String name) { - if(null!=name) { - this.name = name; - aliasedNames.add(origName); - } + public final int hashCode() { + return getName().hashCode(); } - public void addAliasedName(final String name) { - aliasedNames.add(name); - } - public Collection<String> getAliasedNames() { - return aliasedNames; + /** + * Equality test by its given {@link #getName() name}. + */ + @Override + public final boolean equals(final Object arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof ConstantDefinition) ) { + return false; + } else { + final ConstantDefinition t = (ConstantDefinition)arg; + return equals(getName(), t.getName()); + } } - public String getOrigName() { - return origName; + @Override + public final int hashCodeSemantics() { + // 31 * x == (x << 5) - x + int hash = 31 + ( null != getName() ? getName().hashCode() : 0 ); + hash = ((hash << 5) - hash) + ( null != sValue ? sValue.hashCode() : 0 ); + return ((hash << 5) - hash) + ( null != enumName ? enumName.hashCode() : 0 ); } - public String getName() { - return name; + @Override + public final boolean equalSemantics(final SemanticEqualityOp arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof ConstantDefinition) ) { + return false; + } else { + final ConstantDefinition t = (ConstantDefinition) arg; + if( !equals(getName(), t.getName()) || + !equals(enumName, t.enumName) ) { + return false; + } + if( hasIntValue ) { + return iValue == t.iValue; + } else { + // define's string value may be semantical equal .. but formatted differently! + return relaxedEqSem || equals(sValue, t.sValue); + } + } } - public String getValue() { return value; } + public String getValue() { return sValue; } /** Returns null if this definition was not part of an enumeration, or if the enum was anonymous. */ public String getEnumName() { return enumName; } public boolean isEnum() { return isEnum; } - public Set<String> getAliases() { - return aliases; + @Override + public String toString() { + return "ConstantDefinition [name " + getName() + + ", value " + sValue + " (isInt " + hasIntValue + + "), enumName " + enumName + ", isEnum " + isEnum + "]"; } - public void addAlias(final String alias) { - if (aliases == null) { - aliases = new LinkedHashSet<String>(); + private static boolean equals(final String s1, final String s2) { + if (s1 == null || s2 == null) { + if (s1 == null && s2 == null) { + return true; + } + return false; } - aliases.add(alias); - } - @Override - public String toString() { - return "ConstantDefinition [name " + name + " origName " + origName + " value " + value - + " aliasedNames " + aliasedNames + " aliases " + aliases - + " enumName " + enumName + " isEnum " + isEnum + "]"; + return s1.equals(s2); } - } diff --git a/src/java/com/jogamp/gluegen/DebugEmitter.java b/src/java/com/jogamp/gluegen/DebugEmitter.java index 6381c8c..582a1d7 100644 --- a/src/java/com/jogamp/gluegen/DebugEmitter.java +++ b/src/java/com/jogamp/gluegen/DebugEmitter.java @@ -39,6 +39,7 @@ package com.jogamp.gluegen; +import java.io.IOException; import java.util.*; import com.jogamp.gluegen.cgram.types.*; @@ -46,9 +47,16 @@ import com.jogamp.gluegen.cgram.types.*; /** Debug emitter which prints the parsing results to standard output. */ public class DebugEmitter implements GlueEmitter { + protected JavaConfiguration cfg; @Override - public void readConfigurationFile(final String filename) {} + public void readConfigurationFile(final String filename) throws IOException { + cfg = createConfig(); + cfg.read(filename); + } + + @Override + public JavaConfiguration getConfiguration() { return cfg; } @Override public void beginEmission(final GlueEmitterControls controls) { @@ -110,10 +118,10 @@ public class DebugEmitter implements GlueEmitter { } @Override - public void emitStruct(final CompoundType t, final String alternateName) { + public void emitStruct(final CompoundType t, final Type typedefType) { String name = t.getName(); - if (name == null && alternateName != null) { - name = alternateName; + if (name == null && typedefType != null) { + name = typedefType.getName(); } System.out.println("Referenced type \"" + name + "\""); @@ -121,4 +129,13 @@ public class DebugEmitter implements GlueEmitter { @Override public void endStructs() {} + + /** + * Create the object that will read and store configuration information for + * this JavaEmitter. + */ + protected JavaConfiguration createConfig() { + return new JavaConfiguration(); + } + } diff --git a/src/java/com/jogamp/gluegen/FunctionEmitter.java b/src/java/com/jogamp/gluegen/FunctionEmitter.java index 8e9d306..5655e0e 100644 --- a/src/java/com/jogamp/gluegen/FunctionEmitter.java +++ b/src/java/com/jogamp/gluegen/FunctionEmitter.java @@ -42,6 +42,7 @@ package com.jogamp.gluegen; import java.util.*; import java.io.*; +import com.jogamp.gluegen.cgram.types.FunctionSymbol; import com.jogamp.gluegen.cgram.types.Type; public abstract class FunctionEmitter { @@ -52,25 +53,29 @@ public abstract class FunctionEmitter { private final ArrayList<EmissionModifier> modifiers; private CommentEmitter commentEmitter = null; private final PrintWriter defaultOutput; + // Only present to provide more clear comments + protected final JavaConfiguration cfg; /** * Constructs the FunctionEmitter with a CommentEmitter that emits nothing. */ - public FunctionEmitter(final PrintWriter defaultOutput, final boolean isInterface) { + public FunctionEmitter(final PrintWriter defaultOutput, final boolean isInterface, final JavaConfiguration configuration) { assert(defaultOutput != null); + this.isInterfaceVal = isInterface; this.modifiers = new ArrayList<EmissionModifier>(); this.defaultOutput = defaultOutput; - this.isInterfaceVal = isInterface; + this.cfg = configuration; } /** * Makes this FunctionEmitter a copy of the passed one. */ public FunctionEmitter(final FunctionEmitter arg) { + isInterfaceVal = arg.isInterfaceVal; modifiers = new ArrayList<EmissionModifier>(arg.modifiers); commentEmitter = arg.commentEmitter; defaultOutput = arg.defaultOutput; - isInterfaceVal = arg.isInterfaceVal; + cfg = arg.cfg; } public boolean isInterface() { return isInterfaceVal; } @@ -113,6 +118,8 @@ public abstract class FunctionEmitter { public abstract String getName(); + public abstract FunctionSymbol getCSymbol(); + /** * Emit the function to the specified output (instead of the default * output). diff --git a/src/java/com/jogamp/gluegen/GlueEmitter.java b/src/java/com/jogamp/gluegen/GlueEmitter.java index bb46cf5..0e8d61f 100644 --- a/src/java/com/jogamp/gluegen/GlueEmitter.java +++ b/src/java/com/jogamp/gluegen/GlueEmitter.java @@ -50,6 +50,7 @@ import com.jogamp.gluegen.cgram.types.*; public interface GlueEmitter { public void readConfigurationFile(String filename) throws Exception; + public JavaConfiguration getConfiguration(); /** * Begin the emission of glue code. This might include opening files, @@ -91,11 +92,11 @@ public interface GlueEmitter { public void beginStructs(TypeDictionary typedefDictionary, TypeDictionary structDictionary, Map<Type, Type> canonMap) throws Exception; - /** Emit glue code for the given CompoundType. alternateName is + /** Emit glue code for the given CompoundType. typedefType is provided when the CompoundType (e.g. "struct foo_t") has not been typedefed to anything but the type of "pointer to struct foo_t" has (e.g. "typedef struct foo_t {} *Foo"); in this case - alternateName would be set to Foo. */ - public void emitStruct(CompoundType t, String alternateName) throws Exception; + typedefType would be set to pointer type Foo. */ + public void emitStruct(CompoundType t, Type typedefType) throws Exception; public void endStructs() throws Exception; } diff --git a/src/java/com/jogamp/gluegen/GlueGen.java b/src/java/com/jogamp/gluegen/GlueGen.java index e123910..6428469 100644 --- a/src/java/com/jogamp/gluegen/GlueGen.java +++ b/src/java/com/jogamp/gluegen/GlueGen.java @@ -43,8 +43,10 @@ import com.jogamp.common.GlueGenVersion; import java.io.*; import java.util.*; +import java.util.logging.Level; import antlr.*; + import com.jogamp.gluegen.cgram.*; import com.jogamp.gluegen.cgram.types.*; import com.jogamp.gluegen.pcpp.*; @@ -64,8 +66,8 @@ public class GlueGen implements GlueEmitterControls { private PCPP preprocessor; // State for SymbolFilters - private List<ConstantDefinition> constants; - private List<FunctionSymbol> functions; + private List<ConstantDefinition> allConstants; + private List<FunctionSymbol> allFunctions; private static boolean debug = false; @@ -83,14 +85,14 @@ public class GlueGen implements GlueEmitterControls { @Override public void runSymbolFilter(final SymbolFilter filter) { - filter.filterSymbols(constants, functions); + filter.filterSymbols(allConstants, allFunctions); final List<ConstantDefinition> newConstants = filter.getConstants(); final List<FunctionSymbol> newFunctions = filter.getFunctions(); if (newConstants != null) { - constants = newConstants; + allConstants = newConstants; } if (newFunctions != null) { - functions = newFunctions; + allFunctions = newFunctions; } } @@ -99,6 +101,25 @@ public class GlueGen implements GlueEmitterControls { public void run(final Reader reader, final String filename, final Class<?> emitterClass, final List<String> includePaths, final List<String> cfgFiles, final String outputRootDir, final boolean copyPCPPOutput2Stderr) { try { + if(debug) { + Logging.getLogger().setLevel(Level.ALL); + } + final GlueEmitter emit; + if (emitterClass == null) { + emit = new JavaEmitter(); + } else { + try { + emit = (GlueEmitter) emitterClass.newInstance(); + } catch (final Exception e) { + throw new RuntimeException("Exception occurred while instantiating emitter class.", e); + } + } + + for (final String config : cfgFiles) { + emit.readConfigurationFile(config); + } + final JavaConfiguration cfg = emit.getConfiguration(); + final File out = File.createTempFile("PCPPTemp", ".pcpp"); final FileOutputStream outStream = new FileOutputStream(out); @@ -115,6 +136,9 @@ public class GlueGen implements GlueEmitterControls { preprocessor.run(reader, filename); outStream.flush(); outStream.close(); + if(debug) { + System.err.println("PCPP done"); + } final FileInputStream inStream = new FileInputStream(out); final DataInputStream dis = new DataInputStream(inStream); @@ -140,6 +164,7 @@ public class GlueGen implements GlueEmitterControls { final HeaderParser headerParser = new HeaderParser(); headerParser.setDebug(debug); + headerParser.setJavaConfiguration(cfg); final TypeDictionary td = new TypeDictionary(); headerParser.setTypedefDictionary(td); final TypeDictionary sd = new TypeDictionary(); @@ -162,21 +187,6 @@ public class GlueGen implements GlueEmitterControls { // generate glue code: the #defines to constants, the set of // typedefs, and the set of functions. - GlueEmitter emit = null; - if (emitterClass == null) { - emit = new JavaEmitter(); - } else { - try { - emit = (GlueEmitter) emitterClass.newInstance(); - } catch (final Exception e) { - throw new RuntimeException("Exception occurred while instantiating emitter class.", e); - } - } - - for (final String config : cfgFiles) { - emit.readConfigurationFile(config); - } - if (null != outputRootDir && outputRootDir.trim().length() > 0) { if (emit instanceof JavaEmitter) { // FIXME: hack to interfere with the *Configuration setting via commandlines @@ -189,7 +199,7 @@ public class GlueGen implements GlueEmitterControls { // Repackage the enum and #define statements from the parser into a common format // so that SymbolFilters can operate upon both identically - constants = new ArrayList<ConstantDefinition>(); + allConstants = new ArrayList<ConstantDefinition>(); for (final EnumType enumeration : headerParser.getEnums()) { String enumName = enumeration.getName(); if (enumName.equals("<anonymous>")) { @@ -198,32 +208,56 @@ public class GlueGen implements GlueEmitterControls { // iterate over all values in the enumeration for (int i = 0; i < enumeration.getNumEnumerates(); ++i) { final String enumElementName = enumeration.getEnumName(i); - final String value = String.valueOf(enumeration.getEnumValue(i)); - constants.add(new ConstantDefinition(enumElementName, value, true, enumName)); + allConstants.add(new ConstantDefinition(enumElementName, enumeration.getEnumValue(i), enumName)); } } for (final Object elem : lexer.getDefines()) { final Define def = (Define) elem; - constants.add(new ConstantDefinition(def.getName(), def.getValue(), false, null)); + allConstants.add(new ConstantDefinition(def.getName(), def.getValue())); } - functions = headerParser.getParsedFunctions(); + allFunctions = headerParser.getParsedFunctions(); - // begin emission of glue code + // begin emission of glue code, + // incl. firing up 'runSymbolFilter(SymbolFilter)' calls, which: + // - filters all ConstantDefinition + // - filters all FunctionSymbol emit.beginEmission(this); + if( debug() ) { + int i=0; + System.err.println("Filtered Constants: "+allConstants.size()); + for (final ConstantDefinition def : allConstants) { + if( debug() ) { + System.err.println("Filtered ["+i+"]: "+def.getAliasedString()); + i++; + } + } + i=0; + System.err.println("Filtered Functions: "+allFunctions.size()); + for (final FunctionSymbol cFunc : allFunctions) { + System.err.println("Filtered ["+i+"]: "+cFunc.getAliasedString()); + i++; + } + } + emit.beginDefines(); final Set<String> emittedDefines = new HashSet<String>(100); // emit java equivalent of enum { ... } statements final StringBuilder comment = new StringBuilder(); - for (final ConstantDefinition def : constants) { + for (final ConstantDefinition def : allConstants) { if (!emittedDefines.contains(def.getName())) { emittedDefines.add(def.getName()); - final Set<String> aliases = def.getAliases(); - if (aliases != null) { + final Set<String> aliases = cfg.getAliasedDocNames(def); + if (aliases != null && aliases.size() > 0 ) { + int i=0; comment.append("Alias for: <code>"); for (final String alias : aliases) { - comment.append(" ").append(alias); + if(0 < i) { + comment.append("</code>, <code>"); + } + comment.append(alias); + i++; } comment.append("</code>"); } @@ -249,7 +283,7 @@ public class GlueGen implements GlueEmitterControls { // Iterate through the functions finding structs that are referenced in // the function signatures; these will be remembered for later emission final ReferencedStructs referencedStructs = new ReferencedStructs(); - for (final FunctionSymbol sym : functions) { + for (final FunctionSymbol sym : allFunctions) { // FIXME: this doesn't take into account the possibility that some of // the functions we send to emitMethodBindings() might not actually be // emitted (e.g., if an Ignore directive in the JavaEmitter causes it @@ -290,19 +324,20 @@ public class GlueGen implements GlueEmitterControls { for (final Iterator<Type> iter = referencedStructs.results(); iter.hasNext();) { final Type t = iter.next(); if (t.isCompound()) { + assert t.hasTypedefName() && t.getName() == null : "ReferencedStructs incorrectly recorded compound type " + t; emit.emitStruct(t.asCompound(), null); } else if (t.isPointer()) { final PointerType p = t.asPointer(); final CompoundType c = p.getTargetType().asCompound(); - assert p.hasTypedefedName() && c.getName() == null : "ReferencedStructs incorrectly recorded pointer type " + p; - emit.emitStruct(c, p.getName()); + assert p.hasTypedefName() && c.getName() == null : "ReferencedStructs incorrectly recorded pointer type " + p; + emit.emitStruct(c, p); } } emit.endStructs(); // emit java and C code to interface with the native functions emit.beginFunctions(td, sd, headerParser.getCanonMap()); - emit.emitFunctions(functions); + emit.emitFunctions(allFunctions); emit.endFunctions(); // end emission of glue code diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java index 346920d..5eadf94 100644 --- a/src/java/com/jogamp/gluegen/JavaConfiguration.java +++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java @@ -46,7 +46,6 @@ import com.jogamp.gluegen.JavaEmitter.MethodAccess; import java.io.*; import java.lang.reflect.Array; import java.util.*; -import java.util.Map.Entry; import java.util.regex.*; import com.jogamp.gluegen.jgram.*; @@ -54,7 +53,6 @@ import com.jogamp.gluegen.cgram.types.*; import java.util.logging.Logger; -import jogamp.common.os.MachineDataInfoRuntime; import static java.util.logging.Level.*; import static com.jogamp.gluegen.JavaEmitter.MethodAccess.*; import static com.jogamp.gluegen.JavaEmitter.EmissionStyle.*; @@ -73,7 +71,7 @@ public class JavaConfiguration { private String className; private String implClassName; - protected static final Logger LOG = Logger.getLogger(JavaConfiguration.class.getPackage().getName()); + protected final Logger LOG; public static String NEWLINE = System.getProperty("line.separator"); @@ -108,6 +106,13 @@ public class JavaConfiguration { private boolean tagNativeBinding; /** + * If true, {@link TypeConfig.SemanticEqualityOp#equalSemantics(TypeConfig.SemanticEqualityOp)} + * will attempt to perform a relaxed semantic equality test, e.g. skip the {@code const} and {@code volatile} qualifiers. + * Otherwise a full semantic equality test will be performed. + */ + private boolean relaxedEqualSemanticsTest; + + /** * Style of code emission. Can emit everything into one class * (AllStatic), separate interface and implementing classes * (InterfaceAndImpl), only the interface (InterfaceOnly), or only @@ -180,6 +185,10 @@ public class JavaConfiguration { private final Map<String, List<String>> javaPrologues = new HashMap<String, List<String>>(); private final Map<String, List<String>> javaEpilogues = new HashMap<String, List<String>>(); + public JavaConfiguration() { + LOG = Logging.getLogger(JavaConfiguration.class.getPackage().getName()); + } + /** Reads the configuration file. @param filename path to file that should be read */ @@ -317,6 +326,15 @@ public class JavaConfiguration { return tagNativeBinding; } + /** + * Returns whether {@link TypeConfig.SemanticEqualityOp#equalSemantics(TypeConfig.SemanticEqualityOp)} + * shall attempt to perform a relaxed semantic equality test, e.g. skip the {@code const} and {@code volatile} qualifier + * - or not. + */ + public boolean relaxedEqualSemanticsTest() { + return relaxedEqualSemanticsTest; + } + /** Returns the code emission style (constants in JavaEmitter) parsed from the configuration file. */ public EmissionStyle emissionStyle() { return emissionStyle; @@ -361,12 +379,12 @@ public class JavaConfiguration { /** If this type should be considered opaque, returns the TypeInfo describing the replacement type. Returns null if this type should not be considered opaque. */ - public TypeInfo typeInfo(Type type, final TypeDictionary typedefDictionary) { + public TypeInfo typeInfo(Type type) { // Because typedefs of pointer types can show up at any point, // walk the pointer chain looking for a typedef name that is in // the TypeInfo map. if (DEBUG_TYPE_INFO) - System.err.println("Incoming type = " + type); + System.err.println("Incoming type = " + type + ", " + type.getDebugString()); final int pointerDepth = type.pointerDepth(); for (int i = 0; i <= pointerDepth; i++) { String name = type.getName(); @@ -377,12 +395,13 @@ public class JavaConfiguration { if (name != null) { final TypeInfo info = closestTypeInfo(name, i + type.pointerDepth()); if (info != null) { + final TypeInfo res = promoteTypeInfo(info, i); if (DEBUG_TYPE_INFO) { - System.err.println(" info.name=" + info.name() + ", name=" + name + + System.err.println(" [1] info.name=" + info.name() + ", name=" + name + ", info.pointerDepth=" + info.pointerDepth() + - ", type.pointerDepth=" + type.pointerDepth()); + ", type.pointerDepth=" + type.pointerDepth() + " -> "+res); } - return promoteTypeInfo(info, i); + return res; } } @@ -392,33 +411,13 @@ public class JavaConfiguration { if (name != null) { final TypeInfo info = closestTypeInfo(name, i + type.pointerDepth()); if (info != null) { + final TypeInfo res = promoteTypeInfo(info, i); if (DEBUG_TYPE_INFO) { - System.err.println(" info.name=" + info.name() + ", name=" + name + - ", info.pointerDepth=" + info.pointerDepth() + - ", type.pointerDepth=" + type.pointerDepth()); - } - return promoteTypeInfo(info, i); - } - } - } - - // Try all typedef names that map to this type - final Set<Entry<String, Type>> entrySet = typedefDictionary.entrySet(); - for (final Map.Entry<String, Type> entry : entrySet) { - // "eq" equality is OK to use here since all types have been canonicalized - if (entry.getValue() == type) { - name = entry.getKey(); - if (DEBUG_TYPE_INFO) { - System.err.println("Looking under typedef name " + name); - } - final TypeInfo info = closestTypeInfo(name, i + type.pointerDepth()); - if (info != null) { - if (DEBUG_TYPE_INFO) { - System.err.println(" info.name=" + info.name() + ", name=" + name + + System.err.println(" [2] info.name=" + info.name() + ", name=" + name + ", info.pointerDepth=" + info.pointerDepth() + - ", type.pointerDepth=" + type.pointerDepth()); + ", type.pointerDepth=" + type.pointerDepth() + " -> "+res); } - return promoteTypeInfo(info, i); + return res; } } } @@ -427,7 +426,9 @@ public class JavaConfiguration { type = type.asPointer().getTargetType(); } } - + if (DEBUG_TYPE_INFO) { + System.err.println(" [X] NULL"); + } return null; } @@ -782,120 +783,184 @@ public class JavaConfiguration { } /** - * Returns true if this #define, function, struct, or field within - * a struct should be ignored during glue code generation of interfaces and implementation. + * Returns true if the given struct, or field within a struct + * should be ignored during glue code generation of interfaces and implementation. + * For other types, use {@link #shouldIgnoreInInterface(AliasedSymbol)}. + * <p> + * This method only considers the {@link AliasedSymbol#getName() current-name} + * of the given symbol, i.e. does not test the {@link #getJavaSymbolRename(String) renamed-symbol}. + * </p> * <p> * For struct fields see {@link #canonicalStructFieldSymbol(String, String)}. * </p> + * <p> + * Implementation calls {@link #shouldIgnoreInInterface(AliasedSymbol)} + * </p> + * @param symbol the symbolic name to check for exclusion + * + */ + public final boolean shouldIgnoreInInterface(final String symbol) { + return shouldIgnoreInInterface( new AliasedSymbol.NoneAliasedSymbol(symbol) ); + } + /** + * Returns true if this aliased symbol should be ignored + * during glue code generation of interfaces and implementation. + * <p> + * Both, the {@link AliasedSymbol#getName() current-name} + * and all {@link AliasedSymbol#getAliasedNames() aliases} shall be considered. + * </p> + * <p> + * Implementation calls {@link #shouldIgnoreInInterface_Int(AliasedSymbol)} + * and overriding implementations shall ensure its being called as well! + * </p> + * @param symbol the symbolic aliased name to check for exclusion */ - public boolean shouldIgnoreInInterface(final String symbol) { - if(DEBUG_IGNORES) { - dumpIgnoresOnce(); - } - // Simple case-1; the entire symbol (orig or renamed) is in the interface ignore table - final String renamedSymbol = getJavaSymbolRename(symbol); - if ( extendedIntfSymbolsIgnore.contains( symbol ) || - extendedIntfSymbolsIgnore.contains( renamedSymbol ) ) { + public boolean shouldIgnoreInInterface(final AliasedSymbol symbol) { + return shouldIgnoreInInterface_Int(symbol); + } + private static boolean oneInSet(final Set<String> ignoreSymbols, final Set<String> symbols) { + if( null != ignoreSymbols && ignoreSymbols.size() > 0 && + null != symbols && symbols.size() > 0 ) { + for(final String sym : symbols) { + if( ignoreSymbols.contains( sym ) ) { + return true; + } + } + } + return false; + } + /** private static boolean allInSet(final Set<String> ignoreSymbols, final Set<String> symbols) { + if( null != ignoreSymbols && ignoreSymbols.size() > 0 && + null != symbols && symbols.size() > 0 ) { + return ignoreSymbols.containsAll(symbols); + } + return false; + } */ + private static boolean onePatternMatch(final Pattern ignoreRegexp, final Set<String> symbols) { + if( null != ignoreRegexp && null != symbols && symbols.size() > 0 ) { + for(final String sym : symbols) { + final Matcher matcher = ignoreRegexp.matcher(sym); + if (matcher.matches()) { + return true; + } + } + } + return false; + } + protected final boolean shouldIgnoreInInterface_Int(final AliasedSymbol symbol) { if(DEBUG_IGNORES) { - System.err.println("Ignore Intf ignore : "+symbol); + dumpIgnoresOnce(); } - return true; - } - // Simple case-2; the entire symbol (orig or renamed) is _not_ in the not-empty interface only table - if ( !extendedIntfSymbolsOnly.isEmpty() && - !extendedIntfSymbolsOnly.contains( symbol ) && - !extendedIntfSymbolsOnly.contains( renamedSymbol ) ) { + final String name = symbol.getName(); + final Set<String> aliases = symbol.getAliasedNames(); + + // Simple case-1; the symbol (orig or renamed) is in the interface ignore table + if ( extendedIntfSymbolsIgnore.contains( name ) || + oneInSet(extendedIntfSymbolsIgnore, aliases) + ) + { if(DEBUG_IGNORES) { - System.err.println("Ignore Intf !extended: " + symbol); + System.err.println("Ignore Intf ignore (one): "+symbol.getAliasedString()); } return true; - } - return shouldIgnoreInImpl_Int(symbol); + } + // Simple case-2; the entire symbol (orig and renamed) is _not_ in the not-empty interface only table + if ( !extendedIntfSymbolsOnly.isEmpty() && + !extendedIntfSymbolsOnly.contains( name ) && + !oneInSet(extendedIntfSymbolsOnly, aliases) ) { + if(DEBUG_IGNORES) { + System.err.println("Ignore Intf !extended (all): " + symbol.getAliasedString()); + } + return true; + } + return shouldIgnoreInImpl_Int(symbol); } /** - * Returns true if this #define, function, struct, or field within - * a struct should be ignored during glue code generation of implementation only. + * Returns true if this aliased symbol should be ignored + * during glue code generation of implementation only. * <p> - * For struct fields see {@link #canonicalStructFieldSymbol(String, String)}. + * Both, the {@link AliasedSymbol#getName() current-name} + * and all {@link AliasedSymbol#getAliasedNames() aliases} shall be considered. + * </p> + * <p> + * Implementation calls {@link #shouldIgnoreInImpl_Int(AliasedSymbol)} + * and overriding implementations shall ensure its being called as well! * </p> + * @param symbol the symbolic aliased name to check for exclusion */ - public boolean shouldIgnoreInImpl(final String symbol) { + public boolean shouldIgnoreInImpl(final AliasedSymbol symbol) { return shouldIgnoreInImpl_Int(symbol); } + protected final boolean shouldIgnoreInImpl_Int(final AliasedSymbol symbol) { + final String name = symbol.getName(); + final Set<String> aliases = symbol.getAliasedNames(); - private boolean shouldIgnoreInImpl_Int(final String symbol) { - - if(DEBUG_IGNORES) { - dumpIgnoresOnce(); - } - - // Simple case-1; the entire symbol (orig or renamed) is in the implementation ignore table - final String renamedSymbol = getJavaSymbolRename(symbol); - if ( extendedImplSymbolsIgnore.contains( symbol ) || - extendedImplSymbolsIgnore.contains( renamedSymbol ) ) { - if(DEBUG_IGNORES) { - System.err.println("Ignore Impl ignore : "+symbol); + // Simple case-1; the symbol (orig or renamed) is in the interface ignore table + if ( extendedImplSymbolsIgnore.contains( name ) || + oneInSet(extendedImplSymbolsIgnore, aliases) + ) + { + if(DEBUG_IGNORES) { + System.err.println("Ignore Impl ignore (one): "+symbol.getAliasedString()); + } + return true; } - return true; - } - // Simple case-2; the entire symbol (orig or renamed) is _not_ in the not-empty implementation only table - if ( !extendedImplSymbolsOnly.isEmpty() && - !extendedImplSymbolsOnly.contains( symbol ) && - !extendedImplSymbolsOnly.contains( renamedSymbol ) ) { + // Simple case-2; the entire symbol (orig and renamed) is _not_ in the not-empty interface only table + if ( !extendedImplSymbolsOnly.isEmpty() && + !extendedImplSymbolsOnly.contains( name ) && + !oneInSet(extendedImplSymbolsOnly, aliases) ) { if(DEBUG_IGNORES) { - System.err.println("Ignore Impl !extended: " + symbol); + System.err.println("Ignore Impl !extended (all): " + symbol.getAliasedString()); } return true; - } - - // Ok, the slow case. We need to check the entire table, in case the table - // contains an regular expression that matches the symbol. - for (final Pattern regexp : ignores) { - final Matcher matcher = regexp.matcher(symbol); - if (matcher.matches()) { - if(DEBUG_IGNORES) { - System.err.println("Ignore Impl RegEx: "+symbol); - } - return true; } - } - // Check negated ignore table if not empty - if (ignoreNots.size() > 0) { // Ok, the slow case. We need to check the entire table, in case the table // contains an regular expression that matches the symbol. - for (final Pattern regexp : ignoreNots) { - final Matcher matcher = regexp.matcher(symbol); - if (!matcher.matches()) { - // Special case as this is most often likely to be the case. - // Unignores are not used very often. - if(unignores.isEmpty()) { - if(DEBUG_IGNORES) { - System.err.println("Ignore Impl unignores==0: "+symbol); - } - return true; + for (final Pattern ignoreRegexp : ignores) { + final Matcher matcher = ignoreRegexp.matcher(name); + if ( matcher.matches() || onePatternMatch(ignoreRegexp, aliases) ) { + if(DEBUG_IGNORES) { + System.err.println("Ignore Impl RegEx: "+symbol.getAliasedString()); + } + return true; } + } - boolean unignoreFound = false; - for (final Pattern unignoreRegexp : unignores) { - final Matcher unignoreMatcher = unignoreRegexp.matcher(symbol); - if (unignoreMatcher.matches()) { - unignoreFound = true; - break; - } + // Check negated ignore table if not empty + if (ignoreNots.size() > 0) { + // Ok, the slow case. We need to check the entire table, in case the table + // contains an regular expression that matches the symbol. + for (final Pattern ignoreNotRegexp : ignoreNots) { + final Matcher matcher = ignoreNotRegexp.matcher(name); + if ( !matcher.matches() && !onePatternMatch(ignoreNotRegexp, aliases) ) { + // Special case as this is most often likely to be the case. + // Unignores are not used very often. + if(unignores.isEmpty()) { + if(DEBUG_IGNORES) { + System.err.println("Ignore Impl unignores==0: "+symbol.getAliasedString()+" -> "+name); + } + return true; + } + boolean unignoreFound = false; + for (final Pattern unignoreRegexp : unignores) { + final Matcher unignoreMatcher = unignoreRegexp.matcher(name); + if ( unignoreMatcher.matches() || onePatternMatch(unignoreRegexp, aliases) ) { + unignoreFound = true; + break; + } + } + + if (!unignoreFound) + if(DEBUG_IGNORES) { + System.err.println("Ignore Impl !unignore: "+symbol.getAliasedString()+" -> "+name); + } + return true; + } } - - if (!unignoreFound) - if(DEBUG_IGNORES) { - System.err.println("Ignore Impl !unignore: "+symbol); - } - return true; - } } - } - - return false; + return false; } /** Returns true if this function should be given a body which @@ -914,6 +979,19 @@ public class JavaConfiguration { return false; } + /** + * Return a set of aliased-name for comment in docs. + * <p> + * This is usually {@link AliasedSymbol#addAliasedName(String)}, + * however an implementation may choose otherwise. + * </p> + * @param symbol the aliased symbol to retrieve the aliases + * @return set of aliased-names or {@code null}. + */ + public Set<String> getAliasedDocNames(final AliasedSymbol symbol) { + return symbol.getAliasedNames(); + } + /** Returns a replacement name for this type, which should be the name of a Java wrapper class for a C struct, or the name unchanged if no RenameJavaType directive was specified for this @@ -1033,6 +1111,9 @@ public class JavaConfiguration { nativeOutputUsesJavaHierarchy = Boolean.valueOf(tmp).booleanValue(); } else if (cmd.equalsIgnoreCase("TagNativeBinding")) { tagNativeBinding = readBoolean("TagNativeBinding", tok, filename, lineNo).booleanValue(); + } else if (cmd.equalsIgnoreCase("RelaxedEqualSemanticsTest")) { + relaxedEqualSemanticsTest = readBoolean("RelaxedEqualSemanticsTest", tok, filename, lineNo).booleanValue(); + TypeConfig.setRelaxedEqualSemanticsTest(relaxedEqualSemanticsTest); // propagate .. } else if (cmd.equalsIgnoreCase("Style")) { try{ emissionStyle = EmissionStyle.valueOf(readString("Style", tok, filename, lineNo)); @@ -1222,7 +1303,7 @@ public class JavaConfiguration { protected void readOpaque(final StringTokenizer tok, final String filename, final int lineNo) { try { - final JavaType javaType = JavaType.createForClass(stringToPrimitiveType(tok.nextToken())); + final JavaType javaType = JavaType.createForOpaqueClass(stringToPrimitiveType(tok.nextToken())); String cType = null; while (tok.hasMoreTokens()) { if (cType == null) { @@ -1755,6 +1836,16 @@ public class JavaConfiguration { return new TypeInfo(typeName, pointerDepth, javaType); } + public TypeInfo addTypeInfo(final String alias, final Type superType) { + final TypeInfo superInfo = typeInfo(superType); + if( null != superInfo ) { + final TypeInfo res = new TypeInfo(alias, superInfo.pointerDepth(), superInfo.javaType()); + addTypeInfo(res); + return res; + } else { + return null; + } + } protected void addTypeInfo(final TypeInfo info) { TypeInfo tmp = typeInfoMap.get(info.name()); if (tmp == null) { diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java index d2dc4ba..4db0482 100644 --- a/src/java/com/jogamp/gluegen/JavaEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaEmitter.java @@ -49,6 +49,7 @@ import java.util.*; import java.text.MessageFormat; import com.jogamp.gluegen.cgram.types.*; +import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol; import java.nio.Buffer; import java.util.logging.Logger; @@ -70,7 +71,6 @@ import static com.jogamp.gluegen.JavaEmitter.MethodAccess.*; public class JavaEmitter implements GlueEmitter { private StructLayout layout; - private TypeDictionary typedefDictionary; private Map<Type, Type> canonMap; protected JavaConfiguration cfg; private boolean requiresStaticInitialization = false; @@ -103,7 +103,11 @@ public class JavaEmitter implements GlueEmitter { private final MachineDataInfo machDescJava = MachineDataInfo.StaticConfig.LP64_UNIX.md; private final MachineDataInfo.StaticConfig[] machDescTargetConfigs = MachineDataInfo.StaticConfig.values(); - protected final static Logger LOG = Logger.getLogger(JavaEmitter.class.getPackage().getName()); + protected final Logger LOG; + + public JavaEmitter() { + LOG = Logging.getLogger(JavaEmitter.class.getPackage().getName()); + } @Override public void readConfigurationFile(final String filename) throws Exception { @@ -111,39 +115,83 @@ public class JavaEmitter implements GlueEmitter { cfg.read(filename); } - class ConstantRenamer implements SymbolFilter { + @Override + public JavaConfiguration getConfiguration() { return cfg; } + class ConstFuncRenamer implements SymbolFilter { private List<ConstantDefinition> constants; - - @Override - public void filterSymbols(final List<ConstantDefinition> constants, final List<FunctionSymbol> functions) { - this.constants = constants; - doWork(); - } + private List<FunctionSymbol> functions; @Override public List<ConstantDefinition> getConstants() { return constants; } - @Override public List<FunctionSymbol> getFunctions() { - return null; + return functions; + } + + private <T extends AliasedSemanticSymbol> List<T> filterSymbolsInt(final List<T> inList, final List<T> outList) { + final JavaConfiguration cfg = getConfig(); + final HashMap<String, T> symMap = new HashMap<String, T>(100); + for (final T sym : inList) { + final String origName = sym.getName(); + final String newName = cfg.getJavaSymbolRename(origName); + if( null != newName ) { + // Alias Name + final T dupSym = symMap.get(newName); + if( null != dupSym ) { + // Duplicate alias .. check and add aliased name + sym.rename(newName); // only rename to allow 'equalSemantics' to not care .. + if( !dupSym.equalSemantics(sym) ) { + throw new RuntimeException( + String.format("Duplicate Name (alias) w/ incompatible value:%n have '%s',%n this '%s'", + dupSym.getAliasedString(), sym.getAliasedString())); + } + dupSym.addAliasedName(origName); + } else { + // No duplicate .. rename and add + sym.rename(newName); + symMap.put(newName, sym); + } + } else { + // Original Name + final T dupSym = symMap.get(origName); + if( null != dupSym ) { + // Duplicate orig .. check and drop + if( !dupSym.equalSemantics(sym) ) { + throw new RuntimeException( + String.format("Duplicate Name (orig) w/ incompatible value:%n have '%s',%n this '%s'", + dupSym.getAliasedString(), sym.getAliasedString())); + } + } else { + // No duplicate orig .. add + symMap.put(origName, sym); + } + } + } + outList.addAll(symMap.values()); + // sort constants to make them easier to find in native code + Collections.sort(outList, new Comparator<T>() { + @Override + public int compare(final T o1, final T o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + return outList; } - private void doWork() { - final List<ConstantDefinition> newConstants = new ArrayList<ConstantDefinition>(); - final JavaConfiguration cfg = getConfig(); - for (final ConstantDefinition def : constants) { - def.rename(cfg.getJavaSymbolRename(def.getName())); - newConstants.add(def); - } - constants = newConstants; + @Override + public void filterSymbols(final List<ConstantDefinition> inConstList, final List<FunctionSymbol> inFuncList) { + constants = filterSymbolsInt(inConstList, new ArrayList<ConstantDefinition>(100)); + functions = filterSymbolsInt(inFuncList, new ArrayList<FunctionSymbol>(100)); } } @Override public void beginEmission(final GlueEmitterControls controls) throws IOException { + // Handle renaming of constants and functions + controls.runSymbolFilter(new ConstFuncRenamer()); // Request emission of any structs requested for (final String structs : cfg.forcedStructs()) { @@ -157,9 +205,6 @@ public class JavaEmitter implements GlueEmitter { throw new RuntimeException("Unable to open files for writing", e); } emitAllFileHeaders(); - - // Handle renaming of constants - controls.runSymbolFilter(new ConstantRenamer()); } } @@ -374,7 +419,7 @@ public class JavaEmitter implements GlueEmitter { final String name = def.getName(); String value = def.getValue(); - if (!cfg.shouldIgnoreInInterface(name)) { + if ( !cfg.shouldIgnoreInInterface(def) ) { final String type = getJavaType(name, value); if (optionalComment != null && optionalComment.length() != 0) { javaWriter().println(" /** " + optionalComment + " */"); @@ -402,7 +447,7 @@ public class JavaEmitter implements GlueEmitter { final TypeDictionary structDictionary, final Map<Type, Type> canonMap) throws Exception { - this.typedefDictionary = typedefDictionary; + // this.typedefDictionary = typedefDictionary; this.canonMap = canonMap; this.requiresStaticInitialization = false; // reset @@ -412,55 +457,44 @@ public class JavaEmitter implements GlueEmitter { } @Override - public Iterator<FunctionSymbol> emitFunctions(final List<FunctionSymbol> originalCFunctions) throws Exception { - - // Sometimes headers will have the same function prototype twice, once - // with the argument names and once without. We'll remember the signatures - // we've already processed we don't generate duplicate bindings. - // - // Note: this code assumes that on the equals() method in FunctionSymbol - // only considers function name and argument types (i.e., it does not - // consider argument *names*) when comparing FunctionSymbols for equality - final Set<FunctionSymbol> funcsToBindSet = new HashSet<FunctionSymbol>(100); - for (final FunctionSymbol cFunc : originalCFunctions) { - if (!funcsToBindSet.contains(cFunc)) { - funcsToBindSet.add(cFunc); - } - } - - // validateFunctionsToBind(funcsToBindSet); - - final ArrayList<FunctionSymbol> funcsToBind = new ArrayList<FunctionSymbol>(funcsToBindSet); - // sort functions to make them easier to find in native code - Collections.sort(funcsToBind, new Comparator<FunctionSymbol>() { - @Override - public int compare(final FunctionSymbol o1, final FunctionSymbol o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - + public Iterator<FunctionSymbol> emitFunctions(final List<FunctionSymbol> funcsToBind) throws Exception { // Bind all the C funcs to Java methods final HashSet<MethodBinding> methodBindingSet = new HashSet<MethodBinding>(); final ArrayList<FunctionEmitter> methodBindingEmitters = new ArrayList<FunctionEmitter>(2*funcsToBind.size()); - for (final FunctionSymbol cFunc : funcsToBind) { - // Check to see whether this function should be ignored - if (!cfg.shouldIgnoreInImpl(cFunc.getName())) { - methodBindingEmitters.addAll(generateMethodBindingEmitters(methodBindingSet, cFunc)); - } + { + int i=0; + for (final FunctionSymbol cFunc : funcsToBind) { + // Check to see whether this function should be ignored + if ( !cfg.shouldIgnoreInImpl(cFunc) ) { + methodBindingEmitters.addAll(generateMethodBindingEmitters(methodBindingSet, cFunc)); + if( GlueGen.debug() ) { + System.err.println("Non-Ignored Impl["+i+"]: "+cFunc.getAliasedString()); + i++; + } + } + } } // Emit all the methods - for (final FunctionEmitter emitter : methodBindingEmitters) { - try { - if (!emitter.isInterface() || !cfg.shouldIgnoreInInterface(emitter.getName())) { - emitter.emit(); - emitter.getDefaultOutput().println(); // put newline after method body + { + int i=0; + for (final FunctionEmitter emitter : methodBindingEmitters) { + try { + final FunctionSymbol cFunc = emitter.getCSymbol(); + if ( !emitter.isInterface() || !cfg.shouldIgnoreInInterface(cFunc) ) { + emitter.emit(); + emitter.getDefaultOutput().println(); // put newline after method body + if( GlueGen.debug() ) { + System.err.println("Non-Ignored Intf["+i+"]: "+cFunc.getAliasedString()); + i++; + } + } + } catch (final Exception e) { + throw new RuntimeException( + "Error while emitting binding for \"" + emitter.getName() + "\"", e); + } } - } catch (final Exception e) { - throw new RuntimeException( - "Error while emitting binding for \"" + emitter.getName() + "\"", e); - } } // Return the list of FunctionSymbols that we generated gluecode for @@ -658,7 +692,7 @@ public class JavaEmitter implements GlueEmitter { cfg.allStatic(), (binding.needsNIOWrappingOrUnwrapping() || hasPrologueOrEpilogue), !cfg.useNIODirectOnly(binding.getName()), - machDescJava); + machDescJava, getConfiguration()); prepCEmitter(binding.getName(), binding.getJavaReturnType(), cEmitter); allEmitters.add(cEmitter); } @@ -821,40 +855,69 @@ public class JavaEmitter implements GlueEmitter { public void beginStructs(final TypeDictionary typedefDictionary, final TypeDictionary structDictionary, final Map<Type, Type> canonMap) throws Exception { - this.typedefDictionary = typedefDictionary; + // this.typedefDictionary = typedefDictionary; this.canonMap = canonMap; } @Override - public void emitStruct(final CompoundType structCType, final String alternateName) throws Exception { - final String structCTypeName; + public void emitStruct(final CompoundType structCType, final Type typedefed) throws Exception { + final String structCTypeName, typedefedName; { - String _name = structCType.getName(); - if (_name == null && alternateName != null) { - _name = alternateName; + final String _name = structCType.getName(); + if ( null == _name && null != typedefed && null != typedefed.getName() ) { + // use typedef'ed name + typedefedName = typedefed.getName(); + structCTypeName = typedefedName; + } else { + // use actual struct type name + typedefedName = null; + structCTypeName = _name; } - structCTypeName = _name; } - - if (structCTypeName == null) { + if ( null == structCTypeName ) { final String structName = structCType.getStructName(); if ( null != structName && cfg.shouldIgnoreInInterface(structName) ) { + LOG.log(INFO, "skipping emission of unnamed ignored struct \"{0}\": {1}", new Object[] { structName, structCType.getDebugString() }); + return; + } else { + final String d1 = null != typedefed ? typedefed.getDebugString() : null; + LOG.log(INFO, "skipping emission of unnamed struct {0}, typedef {1} ", new Object[] { structCType.getDebugString(), d1 }); return; } - LOG.log(WARNING, "skipping emission of unnamed struct \"{0}\"", structCType); + } + if ( cfg.shouldIgnoreInInterface(structCTypeName) ) { + LOG.log(INFO, "skipping emission of ignored \"{0}\": {1}", new Object[] { structCTypeName, structCType.getDebugString() }); return; } - - if (cfg.shouldIgnoreInInterface(structCTypeName)) { - return; + if( null != typedefed && isOpaque(typedefed) ) { + LOG.log(INFO, "skipping emission of opaque typedef {0}, c-struct {1}", new Object[] { typedefed.getDebugString(), structCType.getDebugString() }); + return; } - final Type containingCType = canonicalize(new PointerType(SizeThunk.POINTER, structCType, 0)); + final Type containingCType = canonicalize(new PointerType(SizeThunk.POINTER, structCType, 0, typedefedName)); final JavaType containingJType = typeToJavaType(containingCType, null); - if (!containingJType.isCompoundTypeWrapper()) { - return; + if( containingJType.isOpaqued() ) { + LOG.log(INFO, "skipping emission of opaque {0}, {1}", new Object[] { containingJType.getDebugString(), structCType.getDebugString() }); + return; + } + if( !containingJType.isCompoundTypeWrapper() ) { + LOG.log(WARNING, "skipping emission of non-compound {0}, {1}", new Object[] { containingJType.getDebugString(), structCType.getDebugString() }); + return; } final String containingJTypeName = containingJType.getName(); + LOG.log(INFO, "perform emission of \"{0}\" -> \"{1}\": {2}", new Object[] { structCTypeName, containingJTypeName, structCType.getDebugString()}); + if( GlueGen.debug() ) { + if( null != typedefed ) { + LOG.log(INFO, " typedefed {0}", typedefed.getDebugString()); + } else { + LOG.log(INFO, " typedefed NULL"); + } + LOG.log(INFO, " containingCType {0}", containingCType.getDebugString()); + LOG.log(INFO, " containingJType {0}", containingJType.getDebugString()); + } + if( 0 == structCType.getNumFields() ) { + LOG.log(INFO, "emission of \"{0}\" with zero fields {1}", new Object[] { containingJTypeName, structCType.getDebugString() }); + } this.requiresStaticInitialization = false; // reset @@ -1355,7 +1418,7 @@ public class JavaEmitter implements GlueEmitter { false, true, false, // forIndirectBufferAndArrayImplementation - machDescJava); + machDescJava, getConfiguration()); cEmitter.setIsCStructFunctionPointer(true); prepCEmitter(returnSizeLookupName, binding.getJavaReturnType(), cEmitter); cEmitter.emit(); @@ -1420,7 +1483,7 @@ public class JavaEmitter implements GlueEmitter { false, true, false, // forIndirectBufferAndArrayImplementation - machDescJava); + machDescJava, getConfiguration()); cEmitter.setIsCStructFunctionPointer(false); final String lenExprSet; if( null != nativeArrayLenExpr ) { @@ -1947,10 +2010,9 @@ public class JavaEmitter implements GlueEmitter { } } - private static final boolean DEBUG_TYPEC2JAVA = false; private JavaType typeToJavaType(final Type cType, final MachineDataInfo curMachDesc) { final JavaType jt = typeToJavaTypeImpl(cType, curMachDesc); - if( DEBUG_TYPEC2JAVA ) { + if( GlueGen.debug() ) { System.err.println("typeToJavaType: "+cType.getDebugString()+" -> "+jt.getDebugString()); } return jt; @@ -1968,7 +2030,7 @@ public class JavaEmitter implements GlueEmitter { } // Opaque specifications override automatic conversions // in case the identity is being used .. not if ptr-ptr - final TypeInfo info = cfg.typeInfo(cType, typedefDictionary); + final TypeInfo info = cfg.typeInfo(cType); if (info != null) { boolean isPointerPointer = false; if (cType.pointerDepth() > 0 || cType.arrayDimension() > 0) { @@ -1986,16 +2048,15 @@ public class JavaEmitter implements GlueEmitter { // target type) if (targetType.isPointer()) { isPointerPointer = true; - - // t is<type>**, targetType is <type>*, we need to get <type> - final Type bottomType = targetType.asPointer().getTargetType(); if( GlueGen.debug() ) { + // t is<type>**, targetType is <type>*, we need to get <type> + final Type bottomType = targetType.asPointer().getTargetType(); LOG.log(INFO, "Opaque Type: {0}, targetType: {1}, bottomType: {2} is ptr-ptr", new Object[]{cType.getDebugString(), targetType, bottomType}); } } } } - if(!isPointerPointer) { + if( !isPointerPointer ) { return info.javaType(); } } @@ -2066,7 +2127,6 @@ public class JavaEmitter implements GlueEmitter { throw new RuntimeException("Couldn't find a proper type name for pointer type " + cType.getDebugString()); } } - return JavaType.createForCStruct(cfg.renameJavaType(name)); } else { throw new RuntimeException("Don't know how to convert pointer/array type \"" + @@ -2189,7 +2249,7 @@ public class JavaEmitter implements GlueEmitter { } private boolean isOpaque(final Type type) { - return (cfg.typeInfo(type, typedefDictionary) != null); + return (cfg.typeInfo(type) != null); } private String compatiblePrimitiveJavaTypeName(final Type fieldType, @@ -2586,9 +2646,6 @@ public class JavaEmitter implements GlueEmitter { final MachineDataInfo curMachDesc) { final MethodBinding binding = new MethodBinding(sym, containingType, containingCType); - - binding.renameMethodName(cfg.getJavaSymbolRename(sym.getName())); - // System.out.println("bindFunction(0) "+sym.getReturnType()); if (cfg.returnsString(binding.getName())) { @@ -2779,10 +2836,11 @@ public class JavaEmitter implements GlueEmitter { private Type canonicalize(final Type t) { final Type res = canonMap.get(t); if (res != null) { - return res; + return res; + } else { + canonMap.put(t, t); + return t; } - canonMap.put(t, t); - return t; } /** diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java index 6966315..9d02c14 100644 --- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java @@ -40,14 +40,17 @@ package com.jogamp.gluegen; import com.jogamp.gluegen.cgram.HeaderParser; +import com.jogamp.gluegen.cgram.types.AliasedSymbol; import com.jogamp.gluegen.cgram.types.ArrayType; import com.jogamp.gluegen.cgram.types.EnumType; +import com.jogamp.gluegen.cgram.types.FunctionSymbol; import com.jogamp.gluegen.cgram.types.Type; import java.io.PrintWriter; import java.text.MessageFormat; import java.util.Iterator; import java.util.List; +import java.util.Set; /** * An emitter that emits only the interface for a Java<->C JNI binding. @@ -97,9 +100,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { // represent an array of compound type wrappers private static final String COMPOUND_ARRAY_SUFFIX = "_buf_array_copy"; - // Only present to provide more clear comments - private final JavaConfiguration cfg; - public JavaMethodBindingEmitter(final MethodBinding binding, final PrintWriter output, final String runtimeExceptionType, @@ -115,7 +115,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { final boolean isUnimplemented, final boolean isInterface, final JavaConfiguration configuration) { - super(output, isInterface); + super(output, isInterface, configuration); this.binding = binding; this.runtimeExceptionType = runtimeExceptionType; this.unsupportedExceptionType = unsupportedExceptionType; @@ -133,7 +133,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { } else { setCommentEmitter(defaultInterfaceCommentEmitter); } - cfg = configuration; } public JavaMethodBindingEmitter(final JavaMethodBindingEmitter arg) { @@ -154,7 +153,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { epilogue = arg.epilogue; returnedArrayLengthExpression = arg.returnedArrayLengthExpression; returnedArrayLengthExpressionOnlyForComments = arg.returnedArrayLengthExpressionOnlyForComments; - cfg = arg.cfg; } public final MethodBinding getBinding() { return binding; } @@ -168,6 +166,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { return binding.getName(); } + @Override + public FunctionSymbol getCSymbol() { + return binding.getCSymbol(); + } + protected String getArgumentName(final int i) { return binding.getArgumentName(i); } @@ -812,6 +815,26 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { * emitter java method. */ protected class DefaultCommentEmitter implements CommentEmitter { + protected void emitAliasedDocNamesComment(final AliasedSymbol sym, final PrintWriter writer) { + writer.print(emitAliasedDocNamesComment(sym, new StringBuilder()).toString()); + } + protected StringBuilder emitAliasedDocNamesComment(final AliasedSymbol sym, final StringBuilder sb) { + final Set<String> aliases = cfg.getAliasedDocNames(sym); + if (aliases != null && aliases.size() > 0 ) { + int i=0; + sb.append("Alias for: <code>"); + for (final String alias : aliases) { + if(0 < i) { + sb.append("</code>, <code>"); + } + sb.append(alias); + i++; + } + sb.append("</code>"); + } + return sb; + } + @Override public void emit(final FunctionEmitter emitter, final PrintWriter writer) { emitBeginning(emitter, writer); @@ -826,9 +849,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter { writer.print("Entry point to C language function: "); } protected void emitBindingCSignature(final MethodBinding binding, final PrintWriter writer) { - writer.print("<code> "); - writer.print(binding.getCSymbol().toString(tagNativeBinding)); - writer.print(" </code> "); + final FunctionSymbol funcSym = binding.getCSymbol(); + writer.print("<code>"); + writer.print(funcSym.toString(tagNativeBinding)); + writer.print("</code><br>"); + emitAliasedDocNamesComment(funcSym, writer); } protected void emitEnding(final FunctionEmitter emitter, final PrintWriter writer) { // If argument type is a named enum, then emit a comment detailing the diff --git a/src/java/com/jogamp/gluegen/JavaType.java b/src/java/com/jogamp/gluegen/JavaType.java index 87804bd..9bcd663 100644 --- a/src/java/com/jogamp/gluegen/JavaType.java +++ b/src/java/com/jogamp/gluegen/JavaType.java @@ -63,6 +63,7 @@ public class JavaType { private final String structName; // Types we're generating glue code for (i.e., C structs) private final Type elementType; // Element type if this JavaType represents a C array private final C_PTR primitivePointerType; + private final boolean opaqued; private static JavaType nioBufferType; private static JavaType nioByteBufferType; @@ -107,12 +108,20 @@ public class JavaType { return elementType; } + /** Creates a JavaType corresponding to the given opaque Java type. This + can be used to represent arrays of primitive values or Strings; + the emitters understand how to perform proper conversion from + the corresponding C type. */ + public static JavaType createForOpaqueClass(final Class<?> clazz) { + return new JavaType(clazz, true); + } + /** Creates a JavaType corresponding to the given Java type. This can be used to represent arrays of primitive values or Strings; the emitters understand how to perform proper conversion from the corresponding C type. */ public static JavaType createForClass(final Class<?> clazz) { - return new JavaType(clazz); + return new JavaType(clazz, false); } /** Creates a JavaType corresponding to the specified C CompoundType @@ -336,6 +345,8 @@ public class JavaType { return "jobject"; } + public boolean isOpaqued() { return opaqued; } + public boolean isNIOBuffer() { return clazz != null && ( java.nio.Buffer.class.isAssignableFrom(clazz) || com.jogamp.common.nio.NativeBuffer.class.isAssignableFrom(clazz)) ; @@ -528,34 +539,39 @@ public class JavaType { append(sb, "primitivePointerType = "+primitivePointerType, prepComma); prepComma=true; } append(sb, "is[", prepComma); prepComma=false; - if( isArray() ) { - append(sb, "array", prepComma); prepComma=true; - } - if( isArrayOfCompoundTypeWrappers() ) { - append(sb, "compoundArray", prepComma); prepComma=true; - } - if( isCompoundTypeWrapper() ) { - append(sb, "compound", prepComma); prepComma=true; - } - if( isArray() ) { - append(sb, "array", prepComma); prepComma=true; - } - if( isPrimitive() ) { - append(sb, "primitive", prepComma); prepComma=true; - } - if( isPrimitiveArray() ) { - append(sb, "primitiveArray", prepComma); prepComma=true; - } - if( isNIOBuffer() ) { - append(sb, "nioBuffer", prepComma); prepComma=true; - } - if( isNIOBufferArray() ) { - append(sb, "nioBufferArray", prepComma); prepComma=true; - } - if( isCPrimitivePointerType() ) { - append(sb, "C-Primitive-Pointer", prepComma); prepComma=true; + { + if( isOpaqued() ) { + append(sb, "opaque", prepComma); prepComma=true; + } + if( isArray() ) { + append(sb, "array", prepComma); prepComma=true; + } + if( isArrayOfCompoundTypeWrappers() ) { + append(sb, "compoundArray", prepComma); prepComma=true; + } + if( isCompoundTypeWrapper() ) { + append(sb, "compound", prepComma); prepComma=true; + } + if( isArray() ) { + append(sb, "array", prepComma); prepComma=true; + } + if( isPrimitive() ) { + append(sb, "primitive", prepComma); prepComma=true; + } + if( isPrimitiveArray() ) { + append(sb, "primitiveArray", prepComma); prepComma=true; + } + if( isNIOBuffer() ) { + append(sb, "nioBuffer", prepComma); prepComma=true; + } + if( isNIOBufferArray() ) { + append(sb, "nioBufferArray", prepComma); prepComma=true; + } + if( isCPrimitivePointerType() ) { + append(sb, "C-Primitive-Pointer", prepComma); prepComma=true; + } } - append(sb, "descriptor '"+getDescriptor()+"'", prepComma); prepComma=true; + append(sb, "], descriptor '"+getDescriptor()+"']", prepComma); prepComma=true; return sb.toString(); } @@ -563,11 +579,12 @@ public class JavaType { * Constructs a representation for a type corresponding to the given Class * argument. */ - private JavaType(final Class<?> clazz) { + private JavaType(final Class<?> clazz, final boolean opaqued) { this.primitivePointerType = null; this.clazz = clazz; this.structName = null; this.elementType = null; + this.opaqued = opaqued; } /** Constructs a type representing a named C struct. */ @@ -576,6 +593,7 @@ public class JavaType { this.clazz = null; this.structName = structName; this.elementType = null; + this.opaqued = false; } /** Constructs a type representing a pointer to a C primitive @@ -585,6 +603,7 @@ public class JavaType { this.clazz = null; this.structName = null; this.elementType = null; + this.opaqued = false; } /** Constructs a type representing an array of C pointers. */ @@ -593,6 +612,7 @@ public class JavaType { this.clazz = null; this.structName = null; this.elementType = elementType; + this.opaqued = false; } /** clone only */ @@ -601,6 +621,7 @@ public class JavaType { this.clazz = clazz; this.structName = name; this.elementType = elementType; + this.opaqued = false; } private String arrayName(Class<?> clazz) { diff --git a/src/java/com/jogamp/gluegen/Logging.java b/src/java/com/jogamp/gluegen/Logging.java index 40eadcb..77856f4 100644 --- a/src/java/com/jogamp/gluegen/Logging.java +++ b/src/java/com/jogamp/gluegen/Logging.java @@ -33,6 +33,7 @@ package com.jogamp.gluegen; import java.util.logging.ConsoleHandler; import java.util.logging.Formatter; +import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; @@ -41,11 +42,13 @@ import com.jogamp.common.util.PropertyAccess; /** * - * @author Michael Bien + * @author Michael Bien, et.al. */ public class Logging { - static void init() { + final static Logger rootPackageLogger; + + static { final String packageName = Logging.class.getPackage().getName(); final String property = PropertyAccess.getProperty(packageName+".level", true); Level level; @@ -64,12 +67,35 @@ public class Logging { handler.setFormatter(new PlainLogFormatter()); handler.setLevel(level); - final Logger rootPackageLogger = Logger.getLogger(packageName); + rootPackageLogger = Logger.getLogger(packageName); rootPackageLogger.setUseParentHandlers(false); rootPackageLogger.setLevel(level); rootPackageLogger.addHandler(handler); } + /** provokes static initialization */ + static void init() { } + + /** Returns the <i>root package logger</i>. */ + public static Logger getLogger() { + return rootPackageLogger; + } + /** Returns the demanded logger, while aligning its log-level to the root logger's level. */ + public static synchronized Logger getLogger(final String name) { + final Logger l = Logger.getLogger(name); + alignLevel(l); + return l; + } + /** Align log-level of given logger to the root logger's level. */ + public static void alignLevel(final Logger l) { + final Level level = rootPackageLogger.getLevel(); + l.setLevel(level); + final Handler[] hs = l.getHandlers(); + for(final Handler h:hs) { + h.setLevel(level); + } + } + /** * This log formatter needs usually one line per log record. * @author Michael Bien diff --git a/src/java/com/jogamp/gluegen/MethodBinding.java b/src/java/com/jogamp/gluegen/MethodBinding.java index 93c55d5..56b4fc8 100644 --- a/src/java/com/jogamp/gluegen/MethodBinding.java +++ b/src/java/com/jogamp/gluegen/MethodBinding.java @@ -44,7 +44,6 @@ import com.jogamp.gluegen.cgram.types.Type; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.List; /** Represents the binding of a C function to a Java method. Also used @@ -54,8 +53,6 @@ import java.util.List; public class MethodBinding { private final FunctionSymbol sym; - private String renamedMethodName; - private final HashSet<String> aliasedNames; private JavaType javaReturnType; private List<JavaType> javaArgumentTypes; private boolean computedSignatureProperties; @@ -81,8 +78,6 @@ public class MethodBinding { public MethodBinding(final MethodBinding bindingToCopy) { this.sym = bindingToCopy.sym; - this.renamedMethodName = bindingToCopy.renamedMethodName; - this.aliasedNames = new HashSet<String>(bindingToCopy.aliasedNames); this.containingType = bindingToCopy.containingType; this.containingCType = bindingToCopy.containingCType; this.javaReturnType = bindingToCopy.javaReturnType; @@ -104,7 +99,6 @@ public class MethodBinding { /** Constructor for calling a C function. */ public MethodBinding(final FunctionSymbol sym) { this.sym = sym; - this.aliasedNames = new HashSet<String>(); } /** Constructor for calling a function pointer contained in a @@ -113,7 +107,6 @@ public class MethodBinding { this.sym = sym; this.containingType = containingType; this.containingCType = containingCType; - this.aliasedNames = new HashSet<String>(); } public void setJavaReturnType(final JavaType type) { @@ -166,34 +159,13 @@ public class MethodBinding { return "arg" + i; } - public String getOrigName() { - return sym.getName(); + public Collection<String> getAliasedNames() { + return sym.getAliasedNames(); } - public String getName() { - // Defaults to same as C symbol unless renamed - if (renamedMethodName != null) { - return renamedMethodName; - } return sym.getName(); } - /** Supports renaming C function in Java binding. */ - public void renameMethodName(final String name) { - if (null != name) { - renamedMethodName = name; - aliasedNames.add(sym.getName()); - } - } - - public void addAliasedName(final String name) { - aliasedNames.add(name); - } - - public Collection<String> getAliasedNames() { - return aliasedNames; - } - /** Creates a new MethodBinding replacing the specified Java argument type with a new argument type. If argumentNumber is less than 0 then replaces the return type. */ diff --git a/src/java/com/jogamp/gluegen/ReferencedStructs.java b/src/java/com/jogamp/gluegen/ReferencedStructs.java index d06d47f..546726f 100644 --- a/src/java/com/jogamp/gluegen/ReferencedStructs.java +++ b/src/java/com/jogamp/gluegen/ReferencedStructs.java @@ -58,7 +58,7 @@ public class ReferencedStructs implements TypeVisitor { public void visitType(final Type t) { if (t.isPointer()) { final PointerType p = t.asPointer(); - if (p.hasTypedefedName()) { + if (p.hasTypedefName()) { final CompoundType c = p.getTargetType().asCompound(); if (c != null && c.getName() == null) { // This otherwise-unnamed CompoundType is referred to by a diff --git a/src/java/com/jogamp/gluegen/TypeConfig.java b/src/java/com/jogamp/gluegen/TypeConfig.java new file mode 100644 index 0000000..5f389f4 --- /dev/null +++ b/src/java/com/jogamp/gluegen/TypeConfig.java @@ -0,0 +1,52 @@ +/** + * Copyright 2015 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.gluegen; + +import com.jogamp.gluegen.cgram.types.SizeThunk; +import com.jogamp.gluegen.cgram.types.Type; + +/** + * Static {@link Type} config helper + * binding {@link JavaConfiguration#relaxedEqualSemanticsTest()} system wide. + */ +public class TypeConfig { + private static boolean relaxedEqualSemanticsTest = false; + + /** + * Returns whether {@link TypeConfig.SemanticEqualityOp#equalSemantics(TypeConfig.SemanticEqualityOp)} + * shall attempt to perform a relaxed semantic equality test, e.g. skip the {@code const} and {@code volatile} qualifier + * - or not. + */ + public static boolean relaxedEqualSemanticsTest() { + return relaxedEqualSemanticsTest; + } + /* pp */ static void setRelaxedEqualSemanticsTest(final boolean v) { + relaxedEqualSemanticsTest = v; + SizeThunk.setRelaxedEqualSemanticsTest(v); + } +} diff --git a/src/java/com/jogamp/gluegen/TypeInfo.java b/src/java/com/jogamp/gluegen/TypeInfo.java index d89ac79..52fdc04 100644 --- a/src/java/com/jogamp/gluegen/TypeInfo.java +++ b/src/java/com/jogamp/gluegen/TypeInfo.java @@ -66,7 +66,7 @@ public class TypeInfo { buf.append(name); buf.append(" pointerDepth "); buf.append(pointerDepth); - buf.append(" JavaType " + javaType); + buf.append(" JavaType " + javaType.getDebugString()); return buf.toString(); } } diff --git a/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java b/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java new file mode 100644 index 0000000..a924876 --- /dev/null +++ b/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java @@ -0,0 +1,154 @@ +/** + * Copyright 2015 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.gluegen.cgram.types; + +import java.util.HashSet; +import java.util.Set; + +/** + * Supports symbol aliasing, i.e. renaming, + * while preserving all its original names, i.e. aliases. + */ +public interface AliasedSymbol { + /** + * Rename this symbol with the given {@code newName} if not equal {@link #getName() current-name}. + * <p> + * Before renaming the {@link #getName() current-name} will be added + * to the list of {@link #getAliasedNames() aliases}. + * while the given {@code newName} will be removed. + * </p> + * @param newName the new {@link #getName() current-name} + */ + void rename(final String newName); + /** + * Add the given {@code origName} to the list of {@link #getAliasedNames() aliases} + * if not equal {@link #getName() current-name}. + * @param origName the new alias to be added + */ + void addAliasedName(final String origName); + /** + * + * Returns {@code true} if this symbol has aliases, i.e. either being {@link #rename(String) renamed} + * or {@link #addAliasedName(String) aliases-added}. + * <p> + * Otherwise {@code false} is being returned. + * </p> + */ + boolean hasAliases(); + /** + * Return all aliases for this symbol, i.e. original names, for this symbol. + * <p> + * Exclusive {@link #getName() current-name}. + * </p> + * <p> + * May return {@code null} or a zero sized {@link Set} for no aliases. + * </p> + */ + Set<String> getAliasedNames(); + /** + * Return the current-name, which is the last {@link #rename(String) renamed-name} if issued, + * or the original-name. + */ + String getName(); + /** + * Return this object's {@link #toString()} wrapped w/ the {@link #getName() current-name} + * and all {@link #getAliasedNames() aliases}. + */ + String getAliasedString(); + + public static class AliasedSymbolImpl implements AliasedSymbol { + private final HashSet<String> aliasedNames; + private String name; + + public AliasedSymbolImpl(final String origName) { + this.aliasedNames=new HashSet<String>(); + this.name = origName; + } + @Override + public void rename(final String newName) { + if( !name.equals(newName) ) { + aliasedNames.add(name); + aliasedNames.remove(newName); + name = newName; + } + } + @Override + public void addAliasedName(final String origName) { + if( !name.equals(origName) ) { + aliasedNames.add(origName); + } + } + @Override + public boolean hasAliases() { + return aliasedNames.size() > 0; + } + @Override + public Set<String> getAliasedNames() { + return aliasedNames; + } + @Override + public String getName() { + return name; + } + @Override + public String getAliasedString() { + return "["+name+", aliases "+aliasedNames.toString()+", "+toString()+"]"; + } + } + public static class NoneAliasedSymbol implements AliasedSymbol { + private final String name; + + public NoneAliasedSymbol(final String origName) { + this.name = origName; + } + @Override + public void rename(final String newName) { + throw new UnsupportedOperationException(); + } + @Override + public void addAliasedName(final String origName) { + throw new UnsupportedOperationException(); + } + @Override + public boolean hasAliases() { + return false; + } + @Override + public Set<String> getAliasedNames() { + return null; + } + @Override + public String getName() { + return name; + } + @Override + public String getAliasedString() { + return toString(); + } + } +} diff --git a/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java b/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java index d867b40..281c68d 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java @@ -48,7 +48,6 @@ package com.jogamp.gluegen.cgram.types; public class ArrayType extends MemoryLayoutType implements Cloneable { private final Type elementType; private final int length; - private String computedName; public ArrayType(final Type elementType, final SizeThunk sizeInBytes, final int length, final int cvAttributes) { super(elementType.getName() + " *", sizeInBytes, cvAttributes); @@ -57,24 +56,39 @@ public class ArrayType extends MemoryLayoutType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) return true; - if (arg == null || (!(arg instanceof ArrayType))) { - return false; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = elementType.hashCode(); + return ((hash << 5) - hash) + length; + } + + @Override + protected boolean equalsImpl(final Type arg) { + final ArrayType t = (ArrayType) arg; + return elementType.equals(t.elementType) && + length == t.length; + } + + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + final int hash = elementType.hashCodeSemantics(); + return ((hash << 5) - hash) + length; + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { final ArrayType t = (ArrayType) arg; - return (super.equals(arg) && elementType.equals(t.elementType) && (length == t.length)); + return elementType.equalSemantics(t.elementType) && + length == t.length; } @Override + public boolean hasName() { return null != elementType.getName(); } + + @Override public String getName(final boolean includeCVAttrs) { - // Lazy computation of name due to lazy setting of compound type - // names during parsing - // Note: don't think cvAttributes can be set for array types (unlike pointer types) - if (computedName == null) { - computedName = (elementType.getName() + " *").intern(); - } - return computedName; + return elementType.getName() + " *"; } @Override @@ -114,7 +128,7 @@ public class ArrayType extends MemoryLayoutType implements Cloneable { if(elementType.isConst()) { buf.append("const "); } - buf.append(elementType.getName()); + buf.append(elementType.getCName()); if (variableName != null) { buf.append(" "); buf.append(variableName); diff --git a/src/java/com/jogamp/gluegen/cgram/types/BitType.java b/src/java/com/jogamp/gluegen/cgram/types/BitType.java index 2644551..87eb8ce 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/BitType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/BitType.java @@ -40,6 +40,8 @@ package com.jogamp.gluegen.cgram.types; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; + /** Represents a bitfield in a struct. */ public class BitType extends IntType implements Cloneable { @@ -55,14 +57,35 @@ public class BitType extends IntType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) return true; - if (arg == null || (!(arg instanceof BitType))) { - return false; - } - final BitType t = (BitType) arg; - return (super.equals(arg) && underlyingType.equals(t.underlyingType) && - (sizeInBits == t.sizeInBits) && (offset == t.offset)); + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = underlyingType.hashCode(); + hash = ((hash << 5) - hash) + sizeInBits; + return ((hash << 5) - hash) + offset; + } + + @Override + protected boolean equalsImpl(final Type arg) { + final BitType t = (BitType) arg; + return underlyingType.equals(t.underlyingType) && + sizeInBits == t.sizeInBits && + offset == t.offset; + } + + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + int hash = underlyingType.hashCodeSemantics(); + hash = ((hash << 5) - hash) + sizeInBits; + return ((hash << 5) - hash) + offset; + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { + final BitType t = (BitType) arg; + return underlyingType.equalSemantics(t.underlyingType) && + sizeInBits == t.sizeInBits && + offset == t.offset; } @Override diff --git a/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java b/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java index 9716f54..c3aca40 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java @@ -46,29 +46,67 @@ import java.util.*; and unions. The boolean type accessors indicate how the type is really defined. */ -public abstract class CompoundType extends MemoryLayoutType implements Cloneable { +public abstract class CompoundType extends MemoryLayoutType implements Cloneable, AliasedSymbol { // The name "foo" in the construct "struct foo { ... }"; - private String structName; + private final String structName; private ArrayList<Field> fields; private boolean visiting; private boolean bodyParsed; - private boolean computedHashcode; - private int hashcode; - + /** + * + * @param name + * @param size + * @param cvAttributes + * @param structName + */ CompoundType(final String name, final SizeThunk size, final int cvAttributes, final String structName) { super(name, size, cvAttributes); this.structName = structName; } - public static CompoundType create(final String name, final SizeThunk size, final CompoundTypeKind kind, final int cvAttributes) { + @Override + public void rename(final String newName) { + throw new UnsupportedOperationException(); + } + @Override + public void addAliasedName(final String origName) { + throw new UnsupportedOperationException(); + } + @Override + public boolean hasAliases() { + return false; + } + @Override + public Set<String> getAliasedNames() { + return null; + } + @Override + public String getAliasedString() { + return toString(); + } + + /** + * @param structName struct name of this CompoundType, i.e. the "foo" in the + construct {@code struct foo { int a, ... };} or {@code struct foo;} <i>even</i> for anonymous structs. + * @param size + * @param kind + * @param cvAttributes + * @return + */ + public static CompoundType create(final String structName, final SizeThunk size, final CompoundTypeKind kind, final int cvAttributes) + { + final CompoundType res; switch (kind) { case STRUCT: - return new StructType(name, size, cvAttributes); + res = new StructType(null, size, cvAttributes, structName); + break; case UNION: - return new UnionType(name, size, cvAttributes); + res = new UnionType(null, size, cvAttributes, structName); + break; default: throw new RuntimeException("OO relation "+kind+" / Compount not yet supported"); } + return res; } @Override @@ -81,34 +119,31 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable } @Override - public int hashCode() { - if (computedHashcode) { - return hashcode; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = 31 + ( null != structName ? structName.hashCode() : 0 ); + return ((hash << 5) - hash) + TypeComparator.listsHashCode(fields); + } - if (structName != null) { - hashcode = structName.hashCode(); - } else if (getName() != null) { - hashcode = getName().hashCode(); - } else { - hashcode = 0; - } + @Override + protected boolean equalsImpl(final Type arg) { + final CompoundType ct = (CompoundType) arg; + return ( (structName == null ? ct.structName == null : structName.equals(ct.structName)) || + (structName != null && structName.equals(ct.structName)) + ) && + TypeComparator.listsEqual(fields, ct.fields); + } - computedHashcode = true; - return hashcode; + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + return TypeComparator.listsHashCodeSemantics(fields); } @Override - public boolean equals(final Object arg) { - if (arg == this) return true; - if (arg == null || !(arg instanceof CompoundType)) { - return false; - } - final CompoundType t = (CompoundType) arg; - return super.equals(arg) && - ((structName == null ? t.structName == null : structName.equals(t.structName)) || - (structName != null && structName.equals(t.structName))) && - listsEqual(fields, t.fields); + protected boolean equalSemanticsImpl(final Type arg) { + final CompoundType ct = (CompoundType) arg; + return TypeComparator.listsEqualSemantics(fields, ct.fields); } /** Returns the struct name of this CompoundType, i.e. the "foo" in @@ -117,12 +152,6 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable return structName; } - /** Sets the struct name of this CompoundType, i.e. the "foo" in the - construct "struct foo { ... };". */ - public void setStructName(final String structName) { - this.structName = structName; - } - @Override public void setSize(final SizeThunk size) { super.setSize(size); @@ -131,8 +160,17 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable @Override public CompoundType asCompound() { return this; } + @Override + public String getCName(final boolean includeCVAttrs) { + if( hasTypedefName() ) { + return getName(includeCVAttrs); + } else { + return (isStruct() ? "struct " : "union ")+getName(includeCVAttrs); + } + } + ArrayList<Field> getFields() { return fields; } - void setFields(final ArrayList<Field> fields) { this.fields = fields; } + void setFields(final ArrayList<Field> fields) { this.fields = fields; clearCache(); } /** Returns the number of fields in this type. */ public int getNumFields() { @@ -147,18 +185,42 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable /** Adds a field to this type. */ public void addField(final Field f) { if (bodyParsed) { - throw new RuntimeException("Body of this CompoundType has already been parsed; should not be adding more fields"); + throw new IllegalStateException("Body of this CompoundType has been already closed"); } if (fields == null) { fields = new ArrayList<Field>(); } fields.add(f); + clearCache(); } - /** Indicates to this CompoundType that its body has been parsed and - that no more {@link #addField} operations will be made. */ - public void setBodyParsed() { + /** + * Indicates to this CompoundType that its body has been parsed and + * that no more {@link #addField} operations will be made. + * <p> + * If {@code evalStructTypeName} is {@code true}, {@link #evalStructTypeName()} is performed. + * </p> + * @throws IllegalStateException If called twice. + */ + public void setBodyParsed(final boolean evalStructTypeName) throws IllegalStateException { + if (bodyParsed) { + throw new IllegalStateException("Body of this CompoundType has been already closed"); + } bodyParsed = true; + if( evalStructTypeName ) { + evalStructTypeName(); + } + } + public boolean isBodyParsed() { return bodyParsed; } + /** + * {@link #getName() name} is set to {@link #getStructName() struct-name}, + * which promotes this instance for emission by its struct-name. + */ + public Type evalStructTypeName() { + if( null == getName() ) { + setName(structName); + } + return this; } /** Indicates whether this type was declared as a struct. */ @@ -169,8 +231,9 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable @Override public String toString() { final String cvAttributesString = getCVAttributesString(); - if (getName() != null) { - return cvAttributesString + getName(); + final String cname = getCName(); + if ( null != cname ) { + return cvAttributesString + cname; } else if (getStructName() != null) { return cvAttributesString + "struct " + getStructName(); } else { diff --git a/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java b/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java index de42522..1e13701 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java @@ -47,19 +47,28 @@ public class DoubleType extends PrimitiveType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof DoubleType))) { - return false; - } - return super.equals(arg); + public DoubleType asDouble() { + return this; } @Override - public DoubleType asDouble() { - return this; + protected int hashCodeImpl() { + return 0; + } + + @Override + protected boolean equalsImpl(final Type t) { + return true; + } + + @Override + protected int hashCodeSemanticsImpl() { + return 0; + } + + @Override + protected boolean equalSemanticsImpl(final Type t) { + return true; } @Override diff --git a/src/java/com/jogamp/gluegen/cgram/types/EnumType.java b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java index 0b1193b..f0e71dc 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/EnumType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java @@ -42,6 +42,8 @@ package com.jogamp.gluegen.cgram.types; import java.util.ArrayList; import java.util.NoSuchElementException; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; + /** Describes enumerated types. Enumerations are like ints except that they have a set of named values. */ @@ -49,10 +51,9 @@ public class EnumType extends IntType implements Cloneable { private IntType underlyingType; - private static class Enum { - - String name; - long value; + private static class Enum implements TypeComparator.SemanticEqualityOp { + final String name; + final long value; Enum(final String name, final long value) { this.name = name; @@ -66,6 +67,37 @@ public class EnumType extends IntType implements Cloneable { long getValue() { return value; } + + @Override + public int hashCode() { + // 31 * x == (x << 5) - x + final int hash = name.hashCode(); + return ((hash << 5) - hash) + (int)(value ^ (value >>> 32)); + } + + @Override + public boolean equals(final Object arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof Enum) ) { + return false; + } + final Enum t = (Enum) arg; + return name.equals(t.name) && + value == t.value; + } + + @Override + public int hashCodeSemantics() { + return hashCode(); + } + + @Override + public boolean equalSemantics(final SemanticEqualityOp arg) { + return equals(arg); + } + + public String toString() { return name+" = "+value; } } private ArrayList<Enum> enums; @@ -98,17 +130,31 @@ public class EnumType extends IntType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof EnumType))) { - return false; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = underlyingType.hashCode(); + return ((hash << 5) - hash) + TypeComparator.listsHashCode(enums); + } + + @Override + protected boolean equalsImpl(final Type arg) { final EnumType t = (EnumType) arg; - return (super.equals(arg) - && underlyingType.equals(t.underlyingType) - && listsEqual(enums, t.enums)); + return underlyingType.equals(t.underlyingType) && + TypeComparator.listsEqual(enums, t.enums); + } + + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + final int hash = underlyingType.hashCodeSemantics(); + return ((hash << 5) - hash) + TypeComparator.listsHashCodeSemantics(enums); + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { + final EnumType t = (EnumType) arg; + return underlyingType.equalSemantics(t.underlyingType) && + TypeComparator.listsEqualSemantics(enums, t.enums); } @Override @@ -116,11 +162,14 @@ public class EnumType extends IntType implements Cloneable { return this; } + public Type getUnderlyingType() { return this.underlyingType; } + public void addEnum(final String name, final long val) { if (enums == null) { enums = new ArrayList<Enum>(); } enums.add(new Enum(name, val)); + clearCache(); } /** Number of enumerates defined in this enum. */ @@ -169,12 +218,24 @@ public class EnumType extends IntType implements Cloneable { final Enum e = enums.get(i); if (e.getName().equals(name)) { enums.remove(e); + clearCache(); return true; } } return false; } + public StringBuilder appendEnums(final StringBuilder sb, final boolean cr) { + for(int i=0; i<enums.size(); i++) { + sb.append(enums.get(i)).append(", "); + if( cr ) { + sb.append(String.format("%n")); + } + } + sb.append("}"); + return sb; + } + @Override public void visit(final TypeVisitor arg) { super.visit(arg); diff --git a/src/java/com/jogamp/gluegen/cgram/types/Field.java b/src/java/com/jogamp/gluegen/cgram/types/Field.java index 858d81a..a8fc599 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/Field.java +++ b/src/java/com/jogamp/gluegen/cgram/types/Field.java @@ -40,10 +40,11 @@ package com.jogamp.gluegen.cgram.types; import com.jogamp.common.os.MachineDataInfo; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; /** Represents a field in a struct or union. */ -public class Field { +public class Field implements SemanticEqualityOp { private final String name; private final Type type; private SizeThunk offset; @@ -56,21 +57,41 @@ public class Field { @Override public int hashCode() { - return name.hashCode(); + // 31 * x == (x << 5) - x + final int hash = 31 + ( null != name ? name.hashCode() : 0 ); + return ((hash << 5) - hash) + type.hashCode(); } @Override public boolean equals(final Object arg) { - if (arg == null || (!(arg instanceof Field))) { + if ( !(arg instanceof Field) ) { return false; } final Field f = (Field) arg; // Note: don't know how to examine offset any more since it's // implemented in terms of code and they're not canonicalized - return (((name != null && name.equals(f.name)) || - (name == null && f.name == null)) && - type.equals(f.type)); + return ( ( name != null && name.equals(f.name) ) || + ( name == null && f.name == null ) + ) && + type.equals(f.type); + } + + @Override + public int hashCodeSemantics() { + return type.hashCodeSemantics(); + } + + @Override + public boolean equalSemantics(final SemanticEqualityOp arg) { + if ( !(arg instanceof Field) ) { + return false; + } + + final Field f = (Field) arg; + // Note: don't know how to examine offset any more since it's + // implemented in terms of code and they're not canonicalized + return type.equalSemantics(f.type); } /** Name of this field in the containing data structure. */ diff --git a/src/java/com/jogamp/gluegen/cgram/types/FloatType.java b/src/java/com/jogamp/gluegen/cgram/types/FloatType.java index d8b0b13..0428543 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/FloatType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/FloatType.java @@ -48,18 +48,27 @@ public class FloatType extends PrimitiveType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { + public FloatType asFloat() { return this; } + + @Override + protected int hashCodeImpl() { + return 0; + } + + @Override + protected boolean equalsImpl(final Type t) { return true; - } - if (arg == null || (!(arg instanceof FloatType))) { - return false; - } - return super.equals(arg); } @Override - public FloatType asFloat() { return this; } + protected int hashCodeSemanticsImpl() { + return 0; + } + + @Override + protected boolean equalSemanticsImpl(final Type t) { + return true; + } @Override Type newCVVariant(final int cvAttributes) { diff --git a/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java index d41f2fd..ee68b68 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java +++ b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java @@ -38,6 +38,12 @@ */ package com.jogamp.gluegen.cgram.types; +import java.util.List; + +import com.jogamp.gluegen.cgram.types.AliasedSymbol.AliasedSymbolImpl; +import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; + /** * Describes a function symbol, which includes the name and @@ -51,20 +57,15 @@ package com.jogamp.gluegen.cgram.types; * Deep comparison can be performed via {@link #isCompletelyEqual(Object o)}; * </p> **/ -public class FunctionSymbol { +public class FunctionSymbol extends AliasedSymbolImpl implements AliasedSemanticSymbol { - private final String name; private final FunctionType type; public FunctionSymbol(final String name, final FunctionType type) { - this.name = name; + super(name); this.type = type; } - public String getName() { - return name; - } - /** Returns the type of this function. Do not add arguments to it directly; use addArgument instead. */ public FunctionType getType() { @@ -109,10 +110,10 @@ public class FunctionSymbol { @Override public int hashCode() { - if (name == null) { + if (getName() == null) { return 0; } - return name.hashCode(); + return getName().hashCode(); } @Override @@ -120,25 +121,54 @@ public class FunctionSymbol { if (arg == this) { return true; } - - if (arg == null || (!(arg instanceof FunctionSymbol))) { + if ( !(arg instanceof FunctionSymbol) ) { return false; } - final FunctionSymbol other = (FunctionSymbol) arg; - if (getName() == null && other.getName() != null) { return false; } - return getName().equals(other.getName()); } + @Override + public int hashCodeSemantics() { + return type.hashCodeSemantics(); + } + @Override + public final boolean equalSemantics(final SemanticEqualityOp arg) { + if (arg == this) { + return true; + } + if ( !(arg instanceof FunctionSymbol) ) { + return false; + } + final FunctionSymbol other = (FunctionSymbol) arg; + return type.equalSemantics(other.type); + } + + + public static boolean containsExactly(final List<FunctionSymbol> l, final FunctionSymbol s) { + return exactIndexOf(l, s) >= 0; + } + + public static int exactIndexOf(final List<FunctionSymbol> l, final FunctionSymbol s) { + final int size = l.size(); + for (int i = 0; i < size; i++) { + final FunctionSymbol e = l.get(i); + if( null == s && null == e || + s.equals( e ) && s.type.equals(e.type) ) { + return i; + } + } + return -1; + } + /** * Compares the function type as well, since {@link #equals(Object)} * and {@link #hashCode()} won't. */ - public boolean isCompletelyEqual(final Object arg) { + public boolean exactlyEqual(final Object arg) { if( !this.equals(arg) ) { return false; } diff --git a/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java b/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java index 4b39a34..b0d16e1 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java @@ -41,6 +41,8 @@ package com.jogamp.gluegen.cgram.types; import java.util.*; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; + /** Describes a function type, used to model both function declarations and (via PointerType) function pointers. */ public class FunctionType extends Type implements Cloneable { @@ -67,17 +69,31 @@ public class FunctionType extends Type implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof FunctionType))) { - return false; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = returnType.hashCode(); + return ((hash << 5) - hash) + TypeComparator.listsHashCode(argumentTypes); + } + + @Override + protected boolean equalsImpl(final Type arg) { + final FunctionType t = (FunctionType) arg; + return returnType.equals(t.returnType) && + TypeComparator.listsEqual(argumentTypes, t.argumentTypes); + } + + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + final int hash = returnType.hashCodeSemantics(); + return ((hash << 5) - hash) + TypeComparator.listsHashCodeSemantics(argumentTypes); + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { final FunctionType t = (FunctionType) arg; - return (super.equals(arg) - && returnType.equals(t.returnType) - && listsEqual(argumentTypes, t.argumentTypes)); + return returnType.equalSemantics(t.returnType) && + TypeComparator.listsEqualSemantics(argumentTypes, t.argumentTypes); } @Override @@ -115,10 +131,12 @@ public class FunctionType extends Type implements Cloneable { } argumentTypes.add(argumentType); argumentNames.add(argumentName); + clearCache(); } public void setArgumentName(final int i, final String name) { argumentNames.set(i, name); + clearCache(); } @Override @@ -136,7 +154,7 @@ public class FunctionType extends Type implements Cloneable { String toString(final String functionName, final String callingConvention, final boolean emitNativeTag, final boolean isPointer) { final StringBuilder res = new StringBuilder(); - res.append(getReturnType()); + res.append(getReturnType().getCName(true)); res.append(" "); if (isPointer) { res.append("("); @@ -169,7 +187,7 @@ public class FunctionType extends Type implements Cloneable { } else if (t.isArray()) { res.append(t.asArray().toString(getArgumentName(i))); } else { - res.append(t); + res.append(t.getCName(true)); final String argumentName = getArgumentName(i); if (argumentName != null) { res.append(" "); diff --git a/src/java/com/jogamp/gluegen/cgram/types/IntType.java b/src/java/com/jogamp/gluegen/cgram/types/IntType.java index 3f8dddc..502fe2a 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/IntType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/IntType.java @@ -55,20 +55,36 @@ public class IntType extends PrimitiveType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof IntType))) { - return false; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = 31 + ( unsigned ? 1 : 0 ); + return ((hash << 5) - hash) + ( typedefedUnsigned ? 1 : 0 ); + } + + @Override + protected boolean equalsImpl(final Type arg) { + final IntType t = (IntType) arg; + return unsigned == t.unsigned && + typedefedUnsigned == t.typedefedUnsigned; + } + + @Override + protected int hashCodeSemanticsImpl() { + return hashCodeImpl(); + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { final IntType t = (IntType) arg; - return (super.equals(arg) && (unsigned == t.unsigned)); + return relaxedEqSem || + ( unsigned == t.unsigned && + typedefedUnsigned == t.typedefedUnsigned + ); } @Override - public void setName(final String name) { - super.setName(name); + public void setTypedefName(final String name) { + super.setTypedefName(name); typedefedUnsigned = unsigned; } @@ -89,7 +105,7 @@ public class IntType extends PrimitiveType implements Cloneable { @Override public String toString() { - return getCVAttributesString() + ((isUnsigned() & (!typedefedUnsigned)) ? "unsigned " : "") + getName(); + return getCVAttributesString() + ((isUnsigned() & (!typedefedUnsigned)) ? "unsigned " : "") + getCName(); } @Override diff --git a/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java b/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java index 25d2d1d..fb8c86b 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java @@ -36,6 +36,8 @@ public abstract class MemoryLayoutType extends Type { } public boolean isLayouted() { return isLayouted; } - public void setLayouted() { isLayouted = true; } + public void setLayouted() { + isLayouted = true; + } } diff --git a/src/java/com/jogamp/gluegen/cgram/types/PointerType.java b/src/java/com/jogamp/gluegen/cgram/types/PointerType.java index d1dfb17..c6496bb 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/PointerType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/PointerType.java @@ -42,72 +42,68 @@ package com.jogamp.gluegen.cgram.types; public class PointerType extends Type implements Cloneable { private final Type targetType; - private String computedName; - private boolean hasTypedefedName; - public PointerType(final SizeThunk size, final Type targetType, final int cvAttributes) { + public PointerType(final SizeThunk size, final Type targetType, final int cvAttributes, final String typedefedName) { // can pass null for the final name parameter because the PointerType's getName() // completely replaces superclass behavior - this(size, targetType, cvAttributes, false, null); - } - - private PointerType(final SizeThunk size, final Type targetType, final int cvAttributes, final boolean hasTypedefedName, final String typedefedName) { super(targetType.getName() + " *", size, cvAttributes); - this.hasTypedefedName = false; this.targetType = targetType; - if (hasTypedefedName) { - setName(typedefedName); + if (null != typedefedName) { + setTypedefName(typedefedName); } } @Override - public int hashCode() { - return targetType.hashCode(); + protected int hashCodeImpl() { + return targetType.hashCode(); } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof PointerType))) { - return false; - } + protected boolean equalsImpl(final Type arg) { final PointerType t = (PointerType) arg; - // Note we ignore the name of this type (which might be a typedef - // name) for comparison purposes because this is what allows - // e.g. a newly-fabricated type "PIXELFORMATDESCRIPTOR *" to be - // canonicalized to e.g. "LPPIXELFORMATDESCRIPTOR" - return ((getSize() == t.getSize()) - && (getCVAttributes() == t.getCVAttributes()) - && targetType.equals(t.targetType)); + return targetType.equals(t.targetType); + } + + @Override + protected int hashCodeSemanticsImpl() { + return targetType.hashCodeSemantics(); + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { + final PointerType pt = (PointerType) arg; + return targetType.equalSemantics(pt.targetType); } @Override - public void setName(final String name) { - super.setName(name); - hasTypedefedName = true; + public boolean hasName() { + if ( hasTypedefName() ) { + return super.hasName(); + } else { + return targetType.hasName(); + } } @Override public String getName(final boolean includeCVAttrs) { - if (hasTypedefedName) { + if ( hasTypedefName() ) { return super.getName(includeCVAttrs); + } else if (!includeCVAttrs) { + return targetType.getName(includeCVAttrs) + " *"; } else { - // Lazy computation of name due to lazy setting of compound type - // names during parsing - if (computedName == null) { - computedName = (targetType.getName(includeCVAttrs) + " *").intern(); - } - if (!includeCVAttrs) { - return computedName; - } return targetType.getName(includeCVAttrs) + " * " + getCVAttributesString(); } } - public boolean hasTypedefedName() { - return hasTypedefedName; + @Override + public String getCName(final boolean includeCVAttrs) { + if ( hasTypedefName() ) { + return super.getCName(includeCVAttrs); + } else if (!includeCVAttrs) { + return targetType.getCName(includeCVAttrs) + " *"; + } else { + return targetType.getCName(includeCVAttrs) + " * " + getCVAttributesString(); + } } @Override @@ -115,6 +111,7 @@ public class PointerType extends Type implements Cloneable { return this; } + @Override public Type getTargetType() { return targetType; } @@ -137,13 +134,18 @@ public class PointerType extends Type implements Cloneable { @Override public String toString() { - if (hasTypedefedName) { - return super.getName(true); + if ( hasTypedefName() ) { + return super.getCName(true); + } else { + return toStringInt(); + } + } + private String toStringInt() { + if (!targetType.isFunction()) { + return targetType.getCName(true) + " * " + getCVAttributesString(); } else { - if (!targetType.isFunction()) { - return targetType.toString() + " * " + getCVAttributesString(); - } - return toString(null, null); // this is a pointer to an unnamed function + // return toString(null, null); // this is a pointer to an unnamed function + return ((FunctionType) targetType).toString(null /* functionName */, null /* callingConvention */, false, true); } } @@ -165,6 +167,6 @@ public class PointerType extends Type implements Cloneable { @Override Type newCVVariant(final int cvAttributes) { - return new PointerType(getSize(), targetType, cvAttributes, hasTypedefedName, (hasTypedefedName ? getName() : null)); + return new PointerType(getSize(), targetType, cvAttributes, (hasTypedefName() ? getName() : null)); } } diff --git a/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java b/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java index 9843d6b..7a9c62a 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java +++ b/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java @@ -41,17 +41,25 @@ package com.jogamp.gluegen.cgram.types; import com.jogamp.common.os.MachineDataInfo; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; /** Provides a level of indirection between the definition of a type's size and the absolute value of this size. Necessary when generating glue code for two different CPU architectures (e.g., 32-bit and 64-bit) from the same internal representation of the various types involved. */ -public abstract class SizeThunk implements Cloneable { +public abstract class SizeThunk implements Cloneable, SemanticEqualityOp { + /* pp */ static boolean relaxedEqSem = false; private final boolean fixedNativeSize; + public static void setRelaxedEqualSemanticsTest(final boolean v) { + relaxedEqSem = v; + } + // Private constructor because there are only a few of these - private SizeThunk(final boolean fixedNativeSize) { this.fixedNativeSize = fixedNativeSize; } + private SizeThunk(final boolean fixedNativeSize) { + this.fixedNativeSize = fixedNativeSize; + } @Override public Object clone() { @@ -67,6 +75,55 @@ public abstract class SizeThunk implements Cloneable { public abstract long computeSize(MachineDataInfo machDesc); public abstract long computeAlignment(MachineDataInfo machDesc); + @Override + public final int hashCode() { + final int hash = 0x02DEAD6F; // magic hash start + return ((hash << 5) - hash) + hashCodeImpl(); + } + /* pp */ abstract int hashCodeImpl(); + + @Override + public final boolean equals(final Object arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof SizeThunk) ) { + return false; + } else { + final SizeThunk t = (SizeThunk) arg; + return hashCodeImpl() == t.hashCodeImpl(); + } + } + + @Override + public final int hashCodeSemantics() { + final int hash = 0x01DEAD5F; // magic hash start + return ((hash << 5) - hash) + hashCodeSemanticsImpl(); + } + /* pp */ abstract int hashCodeSemanticsImpl(); + + @Override + public final boolean equalSemantics(final SemanticEqualityOp arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof SizeThunk) ) { + return false; + } else { + final SizeThunk t = (SizeThunk) arg; + return hashCodeSemanticsImpl() == t.hashCodeSemanticsImpl(); + } + } + + static final int magic_int08 = 0x00000010; + static final int magic_int16 = 0x00000012; + static final int magic_int32 = 0x00000014; + static final int magic_intxx = 0x00000016; + static final int magic_long64 = 0x00000020; + static final int magic_longxx = 0x00000022; + static final int magic_float32 = 0x00000030; + static final int magic_float64 = 0x00000032; + static final int magic_aptr64 = 0x00000040; + static final int magic_ops = 0x00010000; + public static final SizeThunk INT8 = new SizeThunk(true) { @Override public long computeSize(final MachineDataInfo machDesc) { @@ -76,6 +133,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.int8AlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 1; } + @Override + protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_int32 : magic_int08; } }; public static final SizeThunk INT16 = new SizeThunk(true) { @@ -87,6 +148,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.int16AlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 2; } + @Override + protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_int32 : magic_int16; } }; public static final SizeThunk INT32 = new SizeThunk(true) { @@ -98,6 +163,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.int32AlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 3; } + @Override + protected int hashCodeSemanticsImpl() { return magic_int32; } }; public static final SizeThunk INTxx = new SizeThunk(false) { @@ -109,6 +178,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.intAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 4; } + @Override + protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_int32 : magic_intxx; } }; public static final SizeThunk LONG = new SizeThunk(false) { @@ -120,6 +193,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.longAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 5; } + @Override + protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_long64 : magic_longxx; } }; public static final SizeThunk INT64 = new SizeThunk(true) { @@ -131,6 +208,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.int64AlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 6; } + @Override + protected int hashCodeSemanticsImpl() { return magic_long64; } }; public static final SizeThunk FLOAT = new SizeThunk(true) { @@ -142,6 +223,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.floatAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 7; } + @Override + protected int hashCodeSemanticsImpl() { return magic_float32; } }; public static final SizeThunk DOUBLE = new SizeThunk(true) { @@ -153,6 +238,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.doubleAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 8; } + @Override + protected int hashCodeSemanticsImpl() { return magic_float64; } }; public static final SizeThunk POINTER = new SizeThunk(false) { @@ -164,6 +253,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.pointerAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 9; } + @Override + protected int hashCodeSemanticsImpl() { return magic_aptr64; } }; // Factory methods for performing certain limited kinds of @@ -181,6 +274,15 @@ public abstract class SizeThunk implements Cloneable { final long thunk2A = thunk2.computeAlignment(machDesc); return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ; } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + 10; + hash = ((hash << 5) - hash) + ( null != thunk1 ? thunk1.hashCode() : 0 ); + return ((hash << 5) - hash) + ( null != thunk2 ? thunk2.hashCode() : 0 ); + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 1; } }; } @@ -197,6 +299,15 @@ public abstract class SizeThunk implements Cloneable { final long thunk2A = thunk2.computeAlignment(machDesc); return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ; } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + 11; + hash = ((hash << 5) - hash) + ( null != thunk1 ? thunk1.hashCode() : 0 ); + return ((hash << 5) - hash) + ( null != thunk2 ? thunk2.hashCode() : 0 ); + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 2; } }; } @@ -239,6 +350,15 @@ public abstract class SizeThunk implements Cloneable { final long thunk2A = alignmentThunk.computeAlignment(machDesc); return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ; } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + 12; + hash = ((hash << 5) - hash) + ( null != offsetThunk ? offsetThunk.hashCode() : 0 ); + return ((hash << 5) - hash) + ( null != alignmentThunk ? alignmentThunk.hashCode() : 0 ); + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 3; } }; } @@ -255,6 +375,15 @@ public abstract class SizeThunk implements Cloneable { final long thunk2A = thunk2.computeAlignment(machDesc); return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ; } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + 13; + hash = ((hash << 5) - hash) + ( null != thunk1 ? thunk1.hashCode() : 0 ); + return ((hash << 5) - hash) + ( null != thunk2 ? thunk2.hashCode() : 0 ); + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 4; } }; } @@ -268,6 +397,14 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return 1; // no alignment for constants } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = 31 + 14; + return ((hash << 5) - hash) + constant; + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 5; } }; } } diff --git a/src/java/com/jogamp/gluegen/cgram/types/StructType.java b/src/java/com/jogamp/gluegen/cgram/types/StructType.java index 27099e9..4998484 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/StructType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/StructType.java @@ -38,14 +38,6 @@ public class StructType extends CompoundType { } @Override - public boolean equals(final Object arg) { - if (arg == null || !(arg instanceof StructType)) { - return false; - } - return super.equals(arg); - } - - @Override public final boolean isStruct() { return true; } @Override public final boolean isUnion() { return false; } @@ -54,6 +46,9 @@ public class StructType extends CompoundType { Type newCVVariant(final int cvAttributes) { final StructType t = new StructType(getName(), getSize(), cvAttributes, getStructName()); t.setFields(getFields()); + if( hasTypedefName() ) { + t.setTypedefName( getName() ); + } return t; } diff --git a/src/java/com/jogamp/gluegen/cgram/types/Type.java b/src/java/com/jogamp/gluegen/cgram/types/Type.java index 28ba6b4..cd48aa0 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/Type.java +++ b/src/java/com/jogamp/gluegen/cgram/types/Type.java @@ -40,27 +40,45 @@ package com.jogamp.gluegen.cgram.types; -import java.util.List; - import com.jogamp.common.os.MachineDataInfo; +import com.jogamp.gluegen.GlueGen; +import com.jogamp.gluegen.TypeConfig; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; /** Models a C type. Primitive types include int, float, and double. All types have an associated name. Structs and unions are modeled as "compound" types -- composed of fields of primitive or other types. */ -public abstract class Type implements Cloneable { - +public abstract class Type implements Cloneable, SemanticEqualityOp { + public final boolean relaxedEqSem; + private final int cvAttributes; private String name; private SizeThunk size; - private final int cvAttributes; private int typedefedCVAttributes; private boolean hasTypedefName; + private boolean hasCachedHash; + private int cachedHash; + private boolean hasCachedSemanticHash; + private int cachedSemanticHash; protected Type(final String name, final SizeThunk size, final int cvAttributes) { setName(name); - this.size = size; + this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest(); this.cvAttributes = cvAttributes; - hasTypedefName = false; + this.size = size; + this.typedefedCVAttributes = 0; + this.hasTypedefName = false; + this.hasCachedHash = false; + this.cachedHash = 0; + this.hasCachedSemanticHash = false; + this.cachedSemanticHash = 0; + } + + protected final void clearCache() { + cachedHash = 0; + hasCachedHash = false; + cachedSemanticHash = 0; + hasCachedHash = false; } @Override @@ -72,14 +90,28 @@ public abstract class Type implements Cloneable { } } + public final boolean isAnonymous() { return null == name; } + + public boolean hasName() { return null != name; } + + /** Returns the name of this type. The returned string is suitable + for use as a type specifier for native C. Does not include any const/volatile + attributes. */ + public final String getCName() { return getCName(false); } + + /** Returns the name of this type, optionally including + const/volatile attributes. The returned string is suitable for + use as a type specifier for native C. */ + public String getCName(final boolean includeCVAttrs) { return getName(includeCVAttrs); } + /** Returns the name of this type. The returned string is suitable - for use as a type specifier. Does not include any const/volatile + for use as a type specifier for Java. Does not include any const/volatile attributes. */ public final String getName() { return getName(false); } /** Returns the name of this type, optionally including const/volatile attributes. The returned string is suitable for - use as a type specifier. */ + use as a type specifier for Java. */ public String getName(final boolean includeCVAttrs) { if (!includeCVAttrs) { return name; @@ -87,6 +119,18 @@ public abstract class Type implements Cloneable { return getCVAttributesString() + name; } + /** + * Returns a string representation of this type. + * The returned string is suitable for use as a type specifier for native C. + * It does contain an expanded description of structs/unions, + * hence may not be suitable for type declarations. + */ + @Override + public String toString() { + return getCName(true); + } + + private void append(final StringBuilder sb, final String val, final boolean prepComma) { if( prepComma ) { sb.append(", "); @@ -98,15 +142,30 @@ public abstract class Type implements Cloneable { final StringBuilder sb = new StringBuilder(); boolean prepComma = false; sb.append("CType["); + sb.append("(").append(getClass().getSimpleName()).append(") "); + if( hasTypedefName() ) { + sb.append("typedef "); + } if( null != name ) { - append(sb, "'"+name+"'", prepComma); prepComma=true; + sb.append("'").append(name).append("'"); } else { - append(sb, "ANON", prepComma); prepComma=true; + sb.append("ANON"); } - if( hasTypedefName() ) { - sb.append(" (typedef)"); + final Type targetType = getTargetType(); + if( null != targetType && this != targetType ) { + sb.append(" -> "); + if (!targetType.isFunction()) { + sb.append(targetType.toString() + " * " + getCVAttributesString()); + } else { + sb.append(((FunctionType) targetType).toString(null /* functionName */, null /* callingConvention */, false, true)); + } + } + if( GlueGen.debug() ) { + // sb.append(", o=0x"+Integer.toHexString(objHash())+" h=0x"+Integer.toHexString(hashCode())); + sb.append(", o=0x"+Integer.toHexString(objHash())); } - append(sb, "size ", prepComma); prepComma=true; + sb.append(", size "); + prepComma=true; if( null != size ) { final long mdSize; { @@ -137,14 +196,17 @@ public abstract class Type implements Cloneable { append(sb, "bit", prepComma); prepComma=true; } if( isCompound() ) { - sb.append("struct{").append(asCompound().getNumFields()); + sb.append("struct{").append(asCompound().getStructName()).append(": ").append(asCompound().getNumFields()); append(sb, "}", prepComma); prepComma=true; } if( isDouble() ) { append(sb, "double", prepComma); prepComma=true; } if( isEnum() ) { - append(sb, "enum", prepComma); prepComma=true; + final EnumType eT = asEnum(); + sb.append("enum ").append(" [").append(eT.getUnderlyingType()).append("] {").append(eT.getNumEnumerates()).append(": "); + eT.appendEnums(sb, false); + prepComma=true; } if( isFloat() ) { append(sb, "float", prepComma); prepComma=true; @@ -164,20 +226,33 @@ public abstract class Type implements Cloneable { sb.append("]]"); return sb.toString(); } + private final int objHash() { return super.hashCode(); } - /** Set the name of this type; used for handling typedefs. */ - public void setName(final String name) { + + protected final void setName(final String name) { if (name == null) { this.name = name; } else { this.name = name.intern(); } + clearCache(); + } + + /** Set the name of this type; used for handling typedefs. */ + public void setTypedefName(final String name) { + setName(name); // Capture the const/volatile attributes at the time of typedef so // we don't redundantly repeat them in the CV attributes string typedefedCVAttributes = cvAttributes; hasTypedefName = true; } + /** Indicates whether {@link #setTypedefName(String)} has been called on this type, + indicating that it already has a typedef name. */ + public final boolean hasTypedefName() { + return hasTypedefName; + } + /** SizeThunk which computes size of this type in bytes. */ public SizeThunk getSize() { return size; } /** Size of this type in bytes according to the given MachineDataInfo. */ @@ -189,7 +264,10 @@ public abstract class Type implements Cloneable { return thunk.computeSize(machDesc); } /** Set the size of this type; only available for CompoundTypes. */ - void setSize(final SizeThunk size) { this.size = size; } + void setSize(final SizeThunk size) { + this.size = size; + clearCache(); + } /** Casts this to a BitType or returns null if not a BitType. */ public BitType asBit() { return null; } @@ -249,43 +327,92 @@ public abstract class Type implements Cloneable { /** Hashcode for Types. */ @Override - public int hashCode() { - if (name == null) { - return 0; - } - - if (cvAttributes != 0) { - final String nameWithAttribs = name + cvAttributes; - return nameWithAttribs.hashCode(); + public final int hashCode() { + if( !hasCachedHash ) { + // 31 * x == (x << 5) - x + int hash = 31 + ( hasTypedefName ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( null != size ? size.hashCode() : 0 ); + hash = ((hash << 5) - hash) + cvAttributes; + hash = ((hash << 5) - hash) + ( null != name ? name.hashCode() : 0 ); + if( !hasTypedefName ) { + hash = ((hash << 5) - hash) + hashCodeImpl(); + } + cachedHash = hash; + hasCachedHash = true; } - return name.hashCode(); + return cachedHash; } + protected abstract int hashCodeImpl(); /** - * Equality test for Types. + * Equality test for Types inclusive its given {@link #getName() name}. */ @Override - public boolean equals(final Object arg) { + public final boolean equals(final Object arg) { if (arg == this) { - return true; + return true; + } else if ( !getClass().isInstance(arg) ) { // implies null == arg || !(arg instanceof Type) + return false; + } else { + final Type t = (Type)arg; + if( hasTypedefName == t.hasTypedefName && + ( ( null != size && size.equals(t.size) ) || + ( null == size && null == t.size ) + ) && + cvAttributes == t.cvAttributes && + ( null == name ? null == t.name : name.equals(t.name) ) + ) + { + if( !hasTypedefName ) { + return equalsImpl(t); + } else { + return true; + } + } else { + return false; + } } + } + protected abstract boolean equalsImpl(final Type t); - if ( !(arg instanceof Type) ) { - return false; + @Override + public final int hashCodeSemantics() { + if( !hasCachedSemanticHash ) { + // 31 * x == (x << 5) - x + int hash = 31 + ( null != size ? size.hashCodeSemantics() : 0 ); + if( !relaxedEqSem ) { + hash = ((hash << 5) - hash) + cvAttributes; + } + hash = ((hash << 5) - hash) + hashCodeSemanticsImpl(); + cachedSemanticHash = hash; + hasCachedSemanticHash = true; } - - final Type t = (Type)arg; - return size == t.size && cvAttributes == t.cvAttributes && - ( null == name ? null == t.name : name.equals(t.name) ) ; + return cachedSemanticHash; } + protected abstract int hashCodeSemanticsImpl(); - /** Returns a string representation of this type. This string is not - necessarily suitable for use as a type specifier; for example, - it will contain an expanded description of structs/unions. */ @Override - public String toString() { - return getName(true); + public final boolean equalSemantics(final SemanticEqualityOp arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof Type) || + !getClass().isInstance(arg) ) { // implies null == arg + return false; + } else { + final Type t = (Type) arg; + if( ( ( null != size && size.equalSemantics(t.size) ) || + ( null == size && null == t.size ) + ) && + ( relaxedEqSem || cvAttributes == t.cvAttributes ) + ) + { + return equalSemanticsImpl(t); + } else { + return false; + } + } } + protected abstract boolean equalSemanticsImpl(final Type t); /** Visit this type and all of the component types of this one; for example, the return type and argument types of a FunctionType. */ @@ -319,12 +446,6 @@ public abstract class Type implements Cloneable { const/volatile attributes. */ abstract Type newCVVariant(int cvAttributes); - /** Indicates whether setName() has been called on this type, - indicating that it already has a typedef name. */ - public boolean hasTypedefName() { - return hasTypedefName; - } - /** Helper method for determining how many pointer indirections this type represents (i.e., "void **" returns 2). Returns 0 if this type is not a pointer type. */ @@ -358,8 +479,10 @@ public abstract class Type implements Cloneable { return this; } - /** Helper routine for list equality comparison */ - static <C> boolean listsEqual(final List<C> a, final List<C> b) { - return ((a == null && b == null) || (a != null && b != null && a.equals(b))); + /** + * Helper method to returns the target type of this type, in case another type is being referenced. + */ + public Type getTargetType() { + return this; } } diff --git a/src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java b/src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java new file mode 100644 index 0000000..850d953 --- /dev/null +++ b/src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java @@ -0,0 +1,143 @@ +/** + * Copyright 2015 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.gluegen.cgram.types; + +import java.util.List; + +public class TypeComparator { + /** + * Supports semantic equality and hash functions for types. + */ + public static interface SemanticEqualityOp { + /** + * Semantic hashcode for Types exclusive its given {@link #getName() name}. + * @see #equalSemantics(SemanticEqualityOp) + */ + int hashCodeSemantics(); + + /** + * Semantic equality test for Types exclusive its given {@link #getName() name}. + * @see #hashCodeSemantics() + */ + boolean equalSemantics(final SemanticEqualityOp arg); + } + /** + * Supports common interface for {@link SemanticEqualityOp} and {@link AliasedSymbol}. + */ + public static interface AliasedSemanticSymbol extends AliasedSymbol, SemanticEqualityOp { }; + + /** Helper routine for list equality comparison*/ + static <C> boolean listsEqual(final List<C> a, final List<C> b) { + if( a == null ) { + if( null != b ) { + return false; + } else { + return true; // elements equal, i.e. both null + } + } + if( b != null && a.size() == b.size() ) { + final int count = a.size(); + for(int i=0; i<count; i++) { + final C ac = a.get(i); + final C bc = b.get(i); + if( null == ac ) { + if( null != bc ) { + return false; + } else { + continue; // elements equal, i.e. both null + } + } + if( !ac.equals(bc) ) { + return false; + } + } + return true; + } + return false; + } + + /** Helper routine for list hashCode */ + static <C extends SemanticEqualityOp> int listsHashCode(final List<C> a) { + if( a == null ) { + return 0; + } else { + final int count = a.size(); + int hash = 31; + for(int i=0; i<count; i++) { + final C ac = a.get(i); + hash = ((hash << 5) - hash) + ( null != ac ? ac.hashCode() : 0 ); + } + return hash; + } + } + + /** Helper routine for list semantic equality comparison*/ + static <C extends SemanticEqualityOp> boolean listsEqualSemantics(final List<C> a, final List<C> b) { + if( a == null ) { + if( null != b ) { + return false; + } else { + return true; // elements equal, i.e. both null + } + } + if( b != null && a.size() == b.size() ) { + final int count = a.size(); + for(int i=0; i<count; i++) { + final C ac = a.get(i); + final C bc = b.get(i); + if( null == ac ) { + if( null != bc ) { + return false; + } else { + continue; // elements equal, i.e. both null + } + } + if( !ac.equalSemantics(bc) ) { + return false; + } + } + return true; + } + return false; + } + + /** Helper routine for list hashCode */ + static <C extends SemanticEqualityOp> int listsHashCodeSemantics(final List<C> a) { + if( a == null ) { + return 0; + } else { + final int count = a.size(); + int hash = 31; + for(int i=0; i<count; i++) { + final C ac = a.get(i); + hash = ((hash << 5) - hash) + ( null != ac ? ac.hashCodeSemantics() : 0 ); + } + return hash; + } + } +} diff --git a/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java b/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java index cd03388..c1cfcdf 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java +++ b/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java @@ -41,6 +41,9 @@ package com.jogamp.gluegen.cgram.types; import java.util.*; +import com.jogamp.gluegen.GlueGen; +import com.jogamp.gluegen.JavaConfiguration; + /** Utility class for recording names of typedefs and structs. */ @@ -63,6 +66,38 @@ public class TypeDictionary { return map.get(name); } + public List<Type> getEqualSemantics(final Type s, final JavaConfiguration cfg, final boolean skipOpaque) { + final List<Type> res = new ArrayList<Type>(); + if( !skipOpaque || null == cfg.typeInfo(s) ) { + final Set<Map.Entry<String, Type>> entries = entrySet(); + for(final Iterator<Map.Entry<String, Type>> iter = entries.iterator(); iter.hasNext(); ) { + final Map.Entry<String, Type> entry = iter.next(); + final Type t = entry.getValue(); + if( s.equalSemantics(t) ) { + if( !skipOpaque || null == cfg.typeInfo(t) ) { + if( GlueGen.debug() ) { + System.err.println(" tls["+res.size()+"]: -> "+entry.getKey()+" -> "+t.getDebugString()); + } + res.add(t); + } + } + } + } + return res; + } + public Type getEqualSemantics1(final Type s, final JavaConfiguration cfg, final boolean skipOpaque) { + final List<Type> tls = getEqualSemantics(s, cfg, skipOpaque); + if( tls.size() > 0 ) { + final Type res = tls.get(0); + if( GlueGen.debug() ) { + System.err.println(" tls.0: "+res.getDebugString()); + } + return res; + } else { + return null; + } + } + //this method is broken /** * Get the names that correspond to the given type. There will be more than diff --git a/src/java/com/jogamp/gluegen/cgram/types/UnionType.java b/src/java/com/jogamp/gluegen/cgram/types/UnionType.java index 99d2fed..6ccc4a2 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/UnionType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/UnionType.java @@ -38,14 +38,6 @@ public class UnionType extends CompoundType { } @Override - public boolean equals(final Object arg) { - if (arg == null || !(arg instanceof UnionType)) { - return false; - } - return super.equals(arg); - } - - @Override public final boolean isStruct() { return false; } @Override public final boolean isUnion() { return true; } @@ -54,6 +46,9 @@ public class UnionType extends CompoundType { Type newCVVariant(final int cvAttributes) { final UnionType t = new UnionType(getName(), getSize(), cvAttributes, getStructName()); t.setFields(getFields()); + if( hasTypedefName() ) { + t.setTypedefName( getName() ); + } return t; } diff --git a/src/java/com/jogamp/gluegen/cgram/types/VoidType.java b/src/java/com/jogamp/gluegen/cgram/types/VoidType.java index 2e1f069..f6adaac 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/VoidType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/VoidType.java @@ -58,4 +58,24 @@ public class VoidType extends Type implements Cloneable { Type newCVVariant(final int cvAttributes) { return new VoidType(getName(), cvAttributes); } + + @Override + protected int hashCodeImpl() { + return 0; + } + + @Override + protected boolean equalsImpl(final Type t) { + return true; + } + + @Override + protected int hashCodeSemanticsImpl() { + return 0; + } + + @Override + protected boolean equalSemanticsImpl(final Type t) { + return true; + } } diff --git a/src/java/com/jogamp/gluegen/pcpp/PCPP.java b/src/java/com/jogamp/gluegen/pcpp/PCPP.java index aca7b14..72b46a1 100644 --- a/src/java/com/jogamp/gluegen/pcpp/PCPP.java +++ b/src/java/com/jogamp/gluegen/pcpp/PCPP.java @@ -57,6 +57,9 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; + +import com.jogamp.gluegen.Logging; + import static java.util.logging.Level.*; /** A minimal pseudo-C-preprocessor designed in particular to preserve @@ -65,7 +68,7 @@ import static java.util.logging.Level.*; public class PCPP { - private static final Logger LOG = Logger.getLogger(PCPP.class.getPackage().getName()); + private final Logger LOG; /** Map containing the results of #define statements. We must evaluate certain very simple definitions (to properly handle @@ -86,6 +89,7 @@ public class PCPP { private final boolean enableCopyOutput2Stderr; public PCPP(final List<String> includePaths, final boolean debug, final boolean copyOutput2Stderr) { + LOG = Logging.getLogger(PCPP.class.getPackage().getName()); this.includePaths = includePaths; setOut(System.out); enableDebugPrint = debug; diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java index 5c059c9..abbe521 100644 --- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java +++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java @@ -42,7 +42,9 @@ package com.jogamp.gluegen.procaddress; import com.jogamp.gluegen.CMethodBindingEmitter; import com.jogamp.gluegen.MethodBinding; import com.jogamp.gluegen.JavaType; + import java.io.*; + import com.jogamp.gluegen.cgram.types.*; public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter { @@ -55,8 +57,11 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter { private static final String procAddressJavaTypeName = JavaType.createForClass(Long.TYPE).jniTypeName(); private ProcAddressEmitter emitter; - public ProcAddressCMethodBindingEmitter(final CMethodBindingEmitter methodToWrap, final boolean callThroughProcAddress, - final boolean needsLocalTypedef, final String localTypedefCallingConvention, final ProcAddressEmitter emitter) { + public ProcAddressCMethodBindingEmitter(final CMethodBindingEmitter methodToWrap, + final boolean callThroughProcAddress, + final boolean needsLocalTypedef, + final String localTypedefCallingConvention, + final ProcAddressEmitter emitter) { super( new MethodBinding(methodToWrap.getBinding()) { @@ -76,7 +81,8 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter { methodToWrap.getIsJavaMethodStatic(), true, methodToWrap.forIndirectBufferAndArrayImplementation(), - methodToWrap.getMachineDataInfo() + methodToWrap.getMachineDataInfo(), + emitter.getConfiguration() ); if (methodToWrap.getReturnValueCapacityExpression() != null) { @@ -124,7 +130,7 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter { // We (probably) didn't get a typedef for this function // pointer type in the header file; the user requested that we // forcibly generate one. Here we force the emission of one. - final PointerType funcPtrType = new PointerType(null, cSym.getType(), 0); + final PointerType funcPtrType = new PointerType(null, cSym.getType(), 0, null); // Just for safety, emit this name slightly differently than // the mangling would otherwise produce funcPointerTypedefName = "_local_" + funcPointerTypedefName; diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java b/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java index 3b1857d..4564019 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java @@ -80,6 +80,7 @@ public class BaseClass extends SingletonJunitCase { int i; final long context = 0; LongBuffer lb=null; + ByteBuffer bb=null; final IntBuffer ib=null; final long[] larray = null; final int larray_offset = 0; @@ -89,10 +90,38 @@ public class BaseClass extends SingletonJunitCase { final int iarray_offset = 0; long result = 0; long l = result; + ShortBlob sb = null; + Int32Struct i32s = null; + AnonBlob ab = null; + PointerBuffer pb=null; { - final ByteBuffer bb = binding.createAPtrBlob(); - PointerBuffer pb = safeByteBuffer2PointerBuffer(bb, 1); + l = binding.testXID(l); + l = binding.testXID_2(l); + + bb = binding.testAnonBuffer(bb); + + sb = binding.testShortBlob0(sb); + sb = binding.testShortBlob1(sb); + sb = binding.testShortBlob2(sb); + sb = binding.testShortBlob3(sb); + sb = binding.testShortBlob4(sb); + + i32s = binding.testInt32Struct(i32s); + + ab = binding.testCreateAnonBlob(); + binding.testDestroyAnonBlob(ab); + + l = binding.testCreateAnonBlob2(); + binding.testDestroyAnonBlob2(l); + + lb = binding.testFooPtr(larray, 0); + lb = binding.testFooPtr(lb); + } + + { + bb = binding.createAPtrBlob(); + pb = safeByteBuffer2PointerBuffer(bb, 1); long bb2A = binding.getAPtrAddress(bb); bb2A = bb2A - 0; // avoid warning @@ -119,9 +148,6 @@ public class BaseClass extends SingletonJunitCase { binding.releaseAPtrBlob(bb); } - final ByteBuffer bb=null; - PointerBuffer pb=null; - result = binding.arrayTestInt32(context, ib); result = binding.arrayTestInt32(context, iarray, iarray_offset); @@ -629,6 +655,57 @@ public class BaseClass extends SingletonJunitCase { Assert.assertTrue("Wrong result: 0x"+Long.toHexString(pb.get(i))+"+1 != 0x"+Long.toHexString(pb2.get(i)), (pb.get(i)+1)==pb2.get(i)); } } + + { + final long l0 = 0xAAFFEE; + final long l1 = binding.testXID(l0); + final long l2 = binding.testXID_2(l0); + Assert.assertEquals(l0, l1); + Assert.assertEquals(l0, l2); + + final ByteBuffer bb = Buffers.newDirectByteBuffer(PointerBuffer.ELEMENT_SIZE); + for(int j=0; j<bb.limit(); j++) { + bb.put(j, (byte)(0xAA+j)); + } + final ByteBuffer bbOut = binding.testAnonBuffer(bb); + Assert.assertEquals(bb, bbOut); + + final ShortBlob sb = ShortBlob.create(); + sb.setB1((byte)0xAA); + sb.setB2((byte)0xEE); + final ShortBlob sb0 = binding.testShortBlob0(sb); + final ShortBlob sb1 = binding.testShortBlob1(sb); + final ShortBlob sb2 = binding.testShortBlob2(sb); + final ShortBlob sb3 = binding.testShortBlob3(sb); + final ShortBlob sb4 = binding.testShortBlob4(sb); + Assert.assertEquals(sb.getBuffer(), sb0.getBuffer()); + Assert.assertEquals(sb.getBuffer(), sb1.getBuffer()); + Assert.assertEquals(sb.getBuffer(), sb2.getBuffer()); + Assert.assertEquals(sb.getBuffer(), sb3.getBuffer()); + Assert.assertEquals(sb.getBuffer(), sb4.getBuffer()); + + final Int32Struct i32s = Int32Struct.create(); + i32s.setB1((byte)0x02); + i32s.setB2((byte)0x12); + i32s.setB3((byte)0x22); + i32s.setB4((byte)0x32); + final Int32Struct i32s0 = binding.testInt32Struct(i32s); + Assert.assertEquals(i32s.getBuffer(), i32s0.getBuffer()); + + final AnonBlob ab = binding.testCreateAnonBlob(); + binding.testDestroyAnonBlob(ab); + + final long ab2 = binding.testCreateAnonBlob2(); + binding.testDestroyAnonBlob2(ab2); + + final long[] foo = new long[] { 0x1122334455667788L }; + final LongBuffer fooLB = Buffers.newDirectLongBuffer(foo); + final LongBuffer foo1Out = binding.testFooPtr(fooLB); + Assert.assertEquals(fooLB, foo1Out); + final LongBuffer foo2Out = binding.testFooPtr(foo, 0); + Assert.assertEquals(fooLB, foo2Out); + } + } public void chapter04TestPointerBuffer(final Bindingtest1 binding) throws Exception { @@ -1123,14 +1200,14 @@ public class BaseClass extends SingletonJunitCase { Assert.assertEquals(3, model.getIntxxPointerCustomLenVal()); Assert.assertEquals(3, model.getInt32PointerCustomLenVal()); - Assert.assertEquals(3, model.getInt32ArrayFixedLenArrayLength()); - Assert.assertEquals(3, model.getStructArrayFixedLenArrayLength()); + Assert.assertEquals(3, TK_ModelConst.getInt32ArrayFixedLenArrayLength()); + Assert.assertEquals(3, TK_ModelConst.getStructArrayFixedLenArrayLength()); Assert.assertEquals(3, model.getStructPointerCustomLenVal()); // field: int32ArrayFixedLen // CType['int32_t *', size [fixed false, lnx64 12], [array*1]], with array length of 3 { - final int size = model.getInt32ArrayFixedLenArrayLength(); + final int size = TK_ModelConst.getInt32ArrayFixedLenArrayLength(); final int[] all = model.getInt32ArrayFixedLen(0, new int[size]); final IntBuffer allB = model.getInt32ArrayFixedLen(); Assert.assertEquals(size, allB.limit()); @@ -1170,7 +1247,7 @@ public class BaseClass extends SingletonJunitCase { // field: mat4x4 // CType['float * *', size [fixed false, lnx64 64], [array*2]], with array length of <code>4*4</code> */ { - Assert.assertEquals(4*4, model.getMat4x4ArrayLength()); + Assert.assertEquals(4*4, TK_ModelConst.getMat4x4ArrayLength()); final FloatBuffer mat4x4 = model.getMat4x4(); Assert.assertEquals(4*4, mat4x4.limit()); for(int i=0; i<4; i++) { @@ -1185,7 +1262,7 @@ public class BaseClass extends SingletonJunitCase { // field: structArrayFixedLen // field: CType['TK_Dimension *', size [fixed false, lnx64 48], [array*1]], with array length of 3 { - final int size = model.getStructArrayFixedLenArrayLength(); + final int size = TK_ModelConst.getStructArrayFixedLenArrayLength(); final TK_Dimension[] all = model.getStructArrayFixedLen(0, new TK_Dimension[size]); for(int i=0; i<size; i++) { Assert.assertEquals(51 + i * 10, all[i].getX()); @@ -1236,7 +1313,7 @@ public class BaseClass extends SingletonJunitCase { assertAPTR(surfaceContext, model.getCtx()); { - Assert.assertEquals(12, model.getModelNameArrayFixedLenArrayLength()); + Assert.assertEquals(12, TK_ModelConst.getModelNameArrayFixedLenArrayLength()); final ByteBuffer bb = model.getModelNameArrayFixedLen(); Assert.assertEquals(12, bb.limit()); @@ -1296,14 +1373,14 @@ public class BaseClass extends SingletonJunitCase { Assert.assertEquals(3, model.getIntxxPointerCustomLenVal()); Assert.assertEquals(3, model.getInt32PointerCustomLenVal()); - Assert.assertEquals(3, model.getInt32ArrayFixedLenArrayLength()); - Assert.assertEquals(3, model.getStructArrayFixedLenArrayLength()); + Assert.assertEquals(3, TK_ModelMutable.getInt32ArrayFixedLenArrayLength()); + Assert.assertEquals(3, TK_ModelMutable.getStructArrayFixedLenArrayLength()); Assert.assertEquals(3, model.getStructPointerCustomLenVal()); // field: int32ArrayFixedLen // CType['int32_t *', size [fixed false, lnx64 12], [array*1]], with array length of 3 { - final int size = model.getInt32ArrayFixedLenArrayLength(); + final int size = TK_ModelMutable.getInt32ArrayFixedLenArrayLength(); { final int[] values = new int[] { 1, 2, 3 }; model.setInt32ArrayFixedLen(0, values); @@ -1385,7 +1462,7 @@ public class BaseClass extends SingletonJunitCase { model.setMat4x4(2*4, new float[] { 31, 32, 33, 34 } ); model.setMat4x4(3*4, new float[] { 41, 42, 43, 44 } ); - Assert.assertEquals(4*4, model.getMat4x4ArrayLength()); + Assert.assertEquals(4*4, TK_ModelMutable.getMat4x4ArrayLength()); final FloatBuffer mat4x4 = model.getMat4x4(); Assert.assertEquals(4*4, mat4x4.limit()); for(int i=0; i<4; i++) { @@ -1400,7 +1477,7 @@ public class BaseClass extends SingletonJunitCase { // field: structArrayFixedLen // field: CType['TK_Dimension *', size [fixed false, lnx64 48], [array*1]], with array length of 3 { - final int size = model.getStructArrayFixedLenArrayLength(); + final int size = TK_ModelMutable.getStructArrayFixedLenArrayLength(); { for(int i=0; i<size; i++) { final TK_Dimension d = TK_Dimension.create(); diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg index 8e41aae..7210940 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg @@ -32,10 +32,17 @@ ReturnValueCapacity typeTestAnonPointer ARRAY_SIZE * sizeof(MYAPIConfig) Opaque long MYAPIConfig Opaque boolean Bool +Opaque long XID +# For 'struct _AnonBlob2*', we need to drop 'struct' +Opaque long _AnonBlob2* + CustomCCode #include "test1.h" Opaque long TK_Context +RenameJavaSymbol DEFINE_01_EXT DEFINE_01 +RenameJavaSymbol testXID_EXT testXID + StructPackage TK_Dimension com.jogamp.gluegen.test.junit.generation EmitStruct TK_Dimension StructPackage TK_DimensionPair com.jogamp.gluegen.test.junit.generation @@ -96,6 +103,9 @@ Import java.nio.* Import java.util.* Import com.jogamp.common.os.* Import com.jogamp.common.nio.* +Import com.jogamp.gluegen.test.junit.generation.ShortBlob +Import com.jogamp.gluegen.test.junit.generation.Int32Struct +Import com.jogamp.gluegen.test.junit.generation.AnonBlob Import com.jogamp.gluegen.test.junit.generation.TK_Surface Import com.jogamp.gluegen.test.junit.generation.TK_Dimension Import com.jogamp.gluegen.test.junit.generation.TK_DimensionPair diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c index 9999274..894dc10 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c @@ -8,6 +8,52 @@ #define DEBUG 1 +MYAPI XID MYAPIENTRY testXID(XID v) { + return v; +} +MYAPI XID_2 MYAPIENTRY testXID_2(XID_2 v) { + return v; +} +MYAPI AnonBuffer MYAPIENTRY testAnonBuffer(AnonBuffer v) { + return v; +} +MYAPI const ShortBlob * MYAPIENTRY testShortBlob0(const ShortBlob *v) { + return v; +} +MYAPI LPShortBlob1 MYAPIENTRY testShortBlob1(LPShortBlob1 v) { + return v; +} +MYAPI LPShortBlob2 MYAPIENTRY testShortBlob2(LPShortBlob2 v) { + return v; +} +MYAPI LPShortBlob3 MYAPIENTRY testShortBlob3(LPShortBlob3 v) { + return v; +} +MYAPI LPShortBlob4 MYAPIENTRY testShortBlob4(LPShortBlob4 v) { + return v; +} +MYAPI struct Int32Struct * MYAPIENTRY testInt32Struct(struct Int32Struct * v) { + return v; +} + +MYAPI AnonBlob MYAPIENTRY testCreateAnonBlob() { + return (AnonBlob) calloc(1, sizeof(char)); +} +MYAPI void MYAPIENTRY testDestroyAnonBlob(AnonBlob v) { + free(v); +} + +MYAPI struct _AnonBlob2 * MYAPIENTRY testCreateAnonBlob2() { + return (struct _AnonBlob2 *) calloc(1, sizeof(char)); +} +MYAPI void MYAPIENTRY testDestroyAnonBlob2(struct _AnonBlob2 * v) { + free(v); +} + +MYAPI foo_ptr MYAPIENTRY testFooPtr(foo_ptr v) { + return v; +} + MYAPI foo MYAPIENTRY nopTest() { return 42; } diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h index 67a8050..50f43b7 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h @@ -28,9 +28,78 @@ typedef int Bool; typedef uint64_t foo; +typedef foo * foo_ptr; typedef void * APtr1Type; typedef intptr_t APtr2Type; +typedef void * XID; // Opaque +typedef XID XID_2; // Opaque, due to XID +typedef void * AnonBuffer; // Non Opaque + +typedef XID XID_2; // Duplicate w/ compatible type (ignored) +// typedef int XID_2; // Duplicate w/ incompatible type ERROR + +#define DEFINE_01 1234 +#define DEFINE_01 1234 // Duplicate w/ same value (ignored) +// #define DEFINE_01 1235 // Duplicate w/ diff value ERROR +#define DEFINE_01_EXT 1234 // Renamed Duplicate w/ same value (ignored) +// #define DEFINE_01_EXT 1235 // Renamed Duplicate w/ diff value ERROR + +#define DEFINE_02 ( (int ) 3 ) +// #define DEFINE_02 ( (int ) 3 ) // Duplicate w/ same value ERROR (PCPP redefine) +// #define DEFINE_02 ( (int) 3 ) // Duplicate w/ diff value ERROR (PCPP redefine, then GlueGen) + +enum Lala { LI=1, LU, LO }; +// enum Lala { LI=1, LU, LO }; // Duplicate w/ same value (ignored, ERROR in native compilation) +// enum Lala { LI=1, LU=3, LO }; // Duplicate w/ diff value ERROR +// enum Lala { LI=1, LU, LO, LERROR }; // Duplicate w/ diff value ERROR + +typedef enum { MI=1, MU, MO } Momo; +// typedef enum { MI=1, MU, MO } Momo; // Duplicate w/ same value (ignored, ERROR in native compilation) +// typedef enum { MI=1, MU=3, MO } Momo; // Duplicate w/ diff value ERROR +// typedef enum { MI=1, MU, MO, MERR } Momo; // Duplicate w/ diff value ERROR + +typedef struct _ShortBlob { + uint8_t b1; + uint8_t b2; +} ShortBlob, ShortBlob2, *LPShortBlob1; // Aliased to 'ShortBlob' +typedef ShortBlob2 * LPShortBlob2; // Aliased to 'ShortBlob' +typedef ShortBlob * LPShortBlob3; // Aliased to 'ShortBlob' +typedef LPShortBlob1 LPShortBlob4; // Aliased to 'ShortBlob' + +struct Int32Struct { + uint8_t b1; + uint8_t b2; + uint8_t b3; + uint8_t b4; +}; + +typedef struct _AnonBlob * AnonBlob; // Anonymous-Struct, Non Opaque + +struct _AnonBlob2; // opaque: struct _AnonBlob2* + +MYAPI XID MYAPIENTRY testXID(XID v); +MYAPI XID MYAPIENTRY testXID(XID_2 v); // duplicate: shall be dropped +// MYAPI XID MYAPIENTRY testXID(int v); // duplicate w/ diff value ERROR +MYAPI XID MYAPIENTRY testXID_EXT(XID v); // renamed duplicate w/ compat value: shall be dropped +// MYAPI XID MYAPIENTRY testXID_EXT(int v); // renamed duplicate w/ diff value ERROR +MYAPI XID_2 MYAPIENTRY testXID_2(XID_2 v); +MYAPI AnonBuffer MYAPIENTRY testAnonBuffer(AnonBuffer v); +MYAPI const ShortBlob * MYAPIENTRY testShortBlob0(const ShortBlob *v); +MYAPI LPShortBlob1 MYAPIENTRY testShortBlob1(LPShortBlob1 v); +MYAPI LPShortBlob2 MYAPIENTRY testShortBlob2(LPShortBlob2 v); +MYAPI LPShortBlob3 MYAPIENTRY testShortBlob3(LPShortBlob3 v); +MYAPI LPShortBlob4 MYAPIENTRY testShortBlob4(LPShortBlob4 v); +MYAPI struct Int32Struct * MYAPIENTRY testInt32Struct(struct Int32Struct * v); + +MYAPI AnonBlob MYAPIENTRY testCreateAnonBlob(); +MYAPI void MYAPIENTRY testDestroyAnonBlob(AnonBlob v); + +MYAPI struct _AnonBlob2 * MYAPIENTRY testCreateAnonBlob2(); +MYAPI void MYAPIENTRY testDestroyAnonBlob2(struct _AnonBlob2 * v); + +MYAPI foo_ptr MYAPIENTRY testFooPtr(foo_ptr v); + /** Returns 42 */ MYAPI foo MYAPIENTRY nopTest(); @@ -131,7 +200,7 @@ MYAPI int MYAPIENTRY intArrayCopy(int * dest, const int * src, int num); /** Increases the elements by 1, and returns the sum MYAPI int MYAPIENTRY intArrayWrite(int * * ints, int num); */ -typedef struct __MYAPIConfig * MYAPIConfig; +typedef struct __MYAPIConfig * MYAPIConfig; // anonymous-struct opaque /** Returns the passed MYAPIConfig incremented by 1 */ MYAPI MYAPIConfig MYAPIENTRY typeTestAnonSingle(const MYAPIConfig a); @@ -172,7 +241,7 @@ typedef struct { int32_t height; } TK_Dimension; -typedef struct _TK_Context * TK_Context; // anonymous +typedef struct _TK_Context * TK_Context; // anonymous-struct opaque typedef struct { TK_Context ctx; diff --git a/src/junit/com/jogamp/gluegen/test/junit/internals/TestType.java b/src/junit/com/jogamp/gluegen/test/junit/internals/TestType.java new file mode 100644 index 0000000..1b83d0c --- /dev/null +++ b/src/junit/com/jogamp/gluegen/test/junit/internals/TestType.java @@ -0,0 +1,85 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.gluegen.test.junit.internals; + +import org.junit.Assert; +import org.junit.Test; + +import com.jogamp.gluegen.cgram.types.FloatType; +import com.jogamp.gluegen.cgram.types.IntType; +import com.jogamp.junit.util.SingletonJunitCase; + +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestType extends SingletonJunitCase { + + @Test + public void test01Equals() { + final FloatType f1 = new FloatType("GLfloat", null, 0); + final FloatType f2 = new FloatType("float", null, 0); + final IntType i1 = new IntType("GLint", null, false, 0); + final IntType i2 = new IntType("int", null, false, 0); + final int f1H = f1.hashCode(); + final int f2H = f2.hashCode(); + final int i1H = i1.hashCode(); + final int i2H = i2.hashCode(); + + final int f1HS = f1.hashCodeSemantics(); + final int f2HS = f2.hashCodeSemantics(); + final int i1HS = i1.hashCodeSemantics(); + final int i2HS = i2.hashCodeSemantics(); + + Assert.assertFalse(f1.getClass().isInstance(null)); + Assert.assertTrue(f1.getClass().isInstance(f2)); + Assert.assertTrue(i1.getClass().isInstance(i2)); + Assert.assertFalse(f1.getClass().isInstance(i2)); + + Assert.assertFalse(f1.equals(f2)); + Assert.assertFalse(i1.equals(i2)); + Assert.assertFalse(f1.equals(i2)); + Assert.assertNotEquals(f1H, f2H); + Assert.assertNotEquals(i1H, i2H); + Assert.assertNotEquals(f1H, i2H); + + Assert.assertTrue(f1.equalSemantics(f2)); + Assert.assertTrue(i1.equalSemantics(i2)); + Assert.assertFalse(f1.equalSemantics(i2)); + Assert.assertEquals(f1HS, f2HS); + Assert.assertEquals(i1HS, i2HS); + Assert.assertNotEquals(f1HS, i2HS); + } + + public static void main(final String args[]) { + final String tstname = TestType.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} |