diff options
author | Sven Gothel <[email protected]> | 2015-03-05 07:14:04 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-03-05 07:14:04 +0100 |
commit | 72d3635279ffc8ad88e47dff9bbe95d211226d11 (patch) | |
tree | 62b3735680dfc5980a94afa14c56045bd082af24 | |
parent | dd2440cbadc642a561d8f92c502fe822b2f11762 (diff) |
Bug 1134 - Enhance GlueGen Compiler: Minimal GL Header Changes _and_ Typesafety
- We shall be able to import 'most' vanilla GL header,
i.e. only change the typedef part using our GlueGen types
- Type Safety:
- GlueGen now detects '#define' and 'enum' redefines
and throw an exception in this case.
This helps detecting wrongly renamed GL extensions into core!
- GlueGen now detects function redefines (overloading)
and throw an exception in this case.
Hence the semantics of duplicate functions has to be equal!
This helps detecting wrongly renamed GL extensions into core!
- Semantic equality for all types is provided
via interface TypeComparator.SemanticEqualityOp, i.e. 'boolean equalSemantics(..)'
implemented by com.jogamp.gluegen.cgram.types.Type.
Semantic equality can be relaxed via config "RelaxedEqualSemanticsTest true",
i.e. ignoring integer size, and const / volatile qualifiers.
- All equality/hash methods of 'com.jogamp.gluegen.cgram.types.*'
are restructured.
- Track and simplify renamed 'symbol', i.e. use a common
sub-interface for all renamed symbols (ConstantDefinition, FunctionSymbol, ..)
- This is provided in a unified manner
via interface com.jogamp.gluegen.cgram.types.AliasedSymbol
and its common implementation AliasedSymbolImpl
- All JavaConfiguration.shouldIgnore* methods operate w/
'AliasedSymbol' trying to match all aliases.
- Support 'struct NAME [ { ... } ]' w/o typedef's
- New GL / CL headers do not use typedef's for anonymous opaque types
- Opaque Type handling
- JavaConfiguration.typeInfo(..), identifying opaque types,
no more back references from target-type -> typedef.
Hence the following is possible now:
typedef void * Opaque01; // Opaque
typedef void * APointerBuffer; // A Buffer
- All Logger instances are no more static
and derive their warning level from the package's root Logger
via Logging.getLogger(..).
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); + } + +} |