summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g3
-rw-r--r--src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g577
-rw-r--r--src/antlr/com/jogamp/gluegen/cgram/StdCParser.g15
-rw-r--r--src/antlr/com/jogamp/gluegen/jgram/JavaParser.g1509
-rw-r--r--src/java/com/jogamp/common/ExceptionUtils.java96
-rw-r--r--src/java/com/jogamp/common/JogampRuntimeException.java7
-rw-r--r--src/java/com/jogamp/common/jvm/JNILibLoaderBase.java130
-rw-r--r--src/java/com/jogamp/common/net/AssetURLContext.java6
-rw-r--r--src/java/com/jogamp/common/net/Uri.java12
-rw-r--r--src/java/com/jogamp/common/nio/Buffers.java71
-rw-r--r--src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java98
-rw-r--r--src/java/com/jogamp/common/nio/StructAccessor.java23
-rw-r--r--src/java/com/jogamp/common/os/DynamicLibraryBundle.java19
-rw-r--r--src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java15
-rw-r--r--src/java/com/jogamp/common/os/NativeLibrary.java162
-rw-r--r--src/java/com/jogamp/common/util/ArrayHashMap.java305
-rw-r--r--src/java/com/jogamp/common/util/ArrayHashSet.java190
-rw-r--r--src/java/com/jogamp/common/util/Bitfield.java208
-rw-r--r--src/java/com/jogamp/common/util/CustomCompress.java167
-rw-r--r--src/java/com/jogamp/common/util/FunctionTask.java81
-rw-r--r--src/java/com/jogamp/common/util/IOUtil.java414
-rw-r--r--src/java/com/jogamp/common/util/IntBitfield.java170
-rw-r--r--src/java/com/jogamp/common/util/InterruptSource.java157
-rw-r--r--src/java/com/jogamp/common/util/InterruptedRuntimeException.java80
-rw-r--r--src/java/com/jogamp/common/util/JarUtil.java20
-rw-r--r--src/java/com/jogamp/common/util/JogampVersion.java24
-rw-r--r--src/java/com/jogamp/common/util/RunnableTask.java98
-rw-r--r--src/java/com/jogamp/common/util/SourcedInterruptedException.java166
-rw-r--r--src/java/com/jogamp/common/util/TaskBase.java43
-rw-r--r--src/java/com/jogamp/common/util/bin/exe-windows-i386.deflbin0 -> 300 bytes
-rw-r--r--src/java/com/jogamp/common/util/bin/exe-windows-i586-268b.binbin268 -> 0 bytes
-rw-r--r--src/java/com/jogamp/common/util/bin/exe-windows-x86_64.deflbin0 -> 345 bytes
-rw-r--r--src/java/com/jogamp/common/util/cache/TempFileCache.java5
-rw-r--r--src/java/com/jogamp/common/util/cache/TempJarCache.java21
-rw-r--r--src/java/com/jogamp/gluegen/ASTLocusTag.java99
-rw-r--r--src/java/com/jogamp/gluegen/CMethodBindingEmitter.java255
-rw-r--r--src/java/com/jogamp/gluegen/ConstantDefinition.java986
-rw-r--r--src/java/com/jogamp/gluegen/DebugEmitter.java27
-rw-r--r--src/java/com/jogamp/gluegen/FunctionEmitter.java40
-rw-r--r--src/java/com/jogamp/gluegen/GenericCPP.java63
-rw-r--r--src/java/com/jogamp/gluegen/GlueEmitter.java7
-rw-r--r--src/java/com/jogamp/gluegen/GlueGen.java210
-rw-r--r--src/java/com/jogamp/gluegen/GlueGenException.java92
-rw-r--r--src/java/com/jogamp/gluegen/JavaConfiguration.java612
-rw-r--r--src/java/com/jogamp/gluegen/JavaEmitter.java1117
-rw-r--r--src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java130
-rw-r--r--src/java/com/jogamp/gluegen/JavaType.java79
-rw-r--r--src/java/com/jogamp/gluegen/Logging.java349
-rw-r--r--src/java/com/jogamp/gluegen/MethodBinding.java98
-rw-r--r--src/java/com/jogamp/gluegen/ReferencedStructs.java56
-rw-r--r--src/java/com/jogamp/gluegen/TypeConfig.java52
-rw-r--r--src/java/com/jogamp/gluegen/TypeInfo.java2
-rw-r--r--src/java/com/jogamp/gluegen/ant/GlueGenTask.java23
-rw-r--r--src/java/com/jogamp/gluegen/cgram/Define.java16
-rw-r--r--src/java/com/jogamp/gluegen/cgram/TNode.java107
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java185
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/ArrayType.java86
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/BitType.java65
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/CompoundType.java161
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/DoubleType.java39
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/EnumType.java182
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/Field.java33
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/FloatType.java39
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java82
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/FunctionType.java89
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/IntType.java111
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java14
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/PointerType.java130
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/PrimitiveType.java10
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java141
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/StructType.java25
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/Type.java504
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java143
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java35
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/TypeVisitor.java6
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/UnionType.java25
-rw-r--r--src/java/com/jogamp/gluegen/cgram/types/VoidType.java38
-rw-r--r--src/java/com/jogamp/gluegen/pcpp/PCPP.java158
-rw-r--r--src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java90
-rw-r--r--src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java46
-rw-r--r--src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java111
-rw-r--r--src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java13
-rw-r--r--src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java9
-rw-r--r--src/java/jogamp/android/launcher/MainLauncher.java8
-rw-r--r--src/java/jogamp/common/os/PlatformPropsImpl.java6
-rw-r--r--src/java/jogamp/common/util/Int32ArrayBitfield.java207
-rw-r--r--src/java/jogamp/common/util/Int32Bitfield.java163
-rw-r--r--src/java/jogamp/common/util/SyncedBitfield.java96
-rw-r--r--src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java4
-rw-r--r--src/java/jogamp/common/util/locks/RecursiveThreadGroupLockImpl01Unfairish.java34
-rw-r--r--src/java/jogamp/common/util/locks/SingletonInstanceFileLock.java4
-rw-r--r--src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java129
-rw-r--r--src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java2
-rw-r--r--src/junit/com/jogamp/common/net/TestUri01.java32
-rw-r--r--src/junit/com/jogamp/common/nio/BuffersTest.java75
-rw-r--r--src/junit/com/jogamp/common/nio/TestByteBufferCopyStream.java31
-rw-r--r--src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java32
-rw-r--r--src/junit/com/jogamp/common/nio/TestByteBufferOutputStream.java7
-rw-r--r--src/junit/com/jogamp/common/util/BitDemoData.java (renamed from src/junit/com/jogamp/common/util/BitstreamData.java)63
-rw-r--r--src/junit/com/jogamp/common/util/CustomDeflate.java115
-rw-r--r--src/junit/com/jogamp/common/util/CustomInflate.java68
-rw-r--r--src/junit/com/jogamp/common/util/TestArrayHashMap01.java186
-rw-r--r--src/junit/com/jogamp/common/util/TestArrayHashSet01.java123
-rw-r--r--src/junit/com/jogamp/common/util/TestBitfield00.java431
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream00.java2
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream01.java2
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream02.java2
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream03.java2
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream04.java2
-rw-r--r--src/junit/com/jogamp/common/util/TestIOUtil01.java96
-rw-r--r--src/junit/com/jogamp/common/util/TestPlatform01.java2
-rw-r--r--src/junit/com/jogamp/common/util/TestRunnableTask01.java4
-rw-r--r--src/junit/com/jogamp/common/util/TestVersionSemantics.java46
-rw-r--r--src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java7
-rw-r--r--src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java11
-rw-r--r--src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java6
-rw-r--r--src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java3
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java312
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/Test1p1JavaEmitter.java16
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2LoadJNIAndImplLib.java11
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2ProcAddressEmitter.java19
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test1-CustomJavaCode.cfg7
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg17
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test1.c57
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test1.h172
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg2
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg2
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/internals/TestType.java85
-rw-r--r--src/junit/com/jogamp/junit/sec/Applet01.java2
-rw-r--r--src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java2
-rw-r--r--src/junit/com/jogamp/junit/util/SingletonJunitCase.java40
-rw-r--r--src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java16
-rwxr-xr-xsrc/native/tinype/make.sh15
-rw-r--r--src/native/tinype/tiny.c13
-rw-r--r--src/native/tinype/tiny2.c15
135 files changed, 11037 insertions, 3649 deletions
diff --git a/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g b/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g
index e8ca8c5..bf01b12 100644
--- a/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g
+++ b/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g
@@ -23,6 +23,7 @@ header {
import antlr.CommonAST;
import antlr.DumpASTVisitor;
+ import com.jogamp.gluegen.ASTLocusTag;
}
@@ -715,7 +716,7 @@ tokens {
public void addDefine(String name, String value)
{
- defines.add(new Define(name, value));
+ defines.add(new Define(name, value, new ASTLocusTag(lineObject.getSource(), lineObject.getLine()+deferredLineCount, -1, name)));
}
/** Returns a list of Define objects corresponding to the
diff --git a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g
index 01f10c3..59eaca3 100644
--- a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g
+++ b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g
@@ -45,7 +45,14 @@ header {
import java.util.*;
import antlr.CommonAST;
+ import com.jogamp.gluegen.ASTLocusTag;
+ import com.jogamp.gluegen.ConstantDefinition;
+ import com.jogamp.gluegen.ConstantDefinition.CNumber;
+ import com.jogamp.gluegen.GlueGenException;
+ import com.jogamp.gluegen.JavaConfiguration;
import com.jogamp.gluegen.cgram.types.*;
+ import com.jogamp.gluegen.cgram.types.EnumType;
+ import com.jogamp.gluegen.cgram.types.EnumType.Enumerator;
}
class HeaderParser extends GnuCTreeParser;
@@ -67,6 +74,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 +118,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,22 +138,25 @@ options {
return functions;
}
- private CompoundType lookupInStructDictionary(String typeName,
+ private CompoundType lookupInStructDictionary(String structName,
CompoundTypeKind kind,
- int cvAttrs) {
- CompoundType t = (CompoundType) structDictionary.get(typeName);
+ int cvAttrs, final ASTLocusTag locusTag)
+ {
+ 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, locusTag);
+ structDictionary.put(structName, t);
+ debugPrintln("Adding compound mapping: [" + structName + "] -> "+getDebugTypeString(t)+" @ "+locusTag);
+ debugPrintln(t.getStructString());
}
return t;
}
- private Type lookupInTypedefDictionary(String typeName) {
+ private Type lookupInTypedefDictionary(final AST _t, String typeName) {
Type t = typedefDictionary.get(typeName);
if (t == null) {
- throw new RuntimeException("Undefined reference to typedef name " + typeName);
+ throwGlueGenException(_t,
+ "Undefined reference to typedef name " + typeName);
}
return t;
}
@@ -153,8 +169,10 @@ 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()+"]"; }
}
// A box for a Type. Allows type to be passed down to be modified by recursive rules.
@@ -207,22 +225,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 +259,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 +281,41 @@ 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 ASTLocusTag funcLocusTag;
- private void doDeclaration() {
- doDeclaration = true;
+ private void resetFuncDeclaration() {
+ isFuncDeclaration = false;
+ funcDeclName = null;
+ funcDeclParams = null;
+ funcLocusTag = null;
+ }
+ private void setFuncDeclaration(final String name, final List<ParameterDeclaration> p, final ASTLocusTag locusTag) {
+ isFuncDeclaration = true;
+ funcDeclName = name;
+ funcDeclParams = p;
+ funcLocusTag = locusTag;
}
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, returnType, 0, funcLocusTag),
+ funcLocusTag);
+ debugPrintln("Function ... "+sym.toString()+" @ "+funcLocusTag);
+ 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(pd.type());
+ debugPrintln(" add "+pd.toString());
sym.addArgument(pd.type(), pd.id());
}
- }
+ }
+ debugPrintln("Function Added "+sym.toString());
functions.add(sym);
+ resetFuncDeclaration();
}
}
@@ -294,19 +332,18 @@ options {
/** Helper routine which handles creating a pointer or array type
for [] expressions */
- private void handleArrayExpr(TypeBox tb, AST t) {
+ private void handleArrayExpr(TypeBox tb, AST t, ASTLocusTag locusTag) {
if (t != null) {
try {
final int len = parseIntConstExpr(t);
- tb.setType(canonicalize(new ArrayType(tb.type(), SizeThunk.mul(SizeThunk.constant(len), tb.type().getSize()), len, 0)));
+ tb.setType(canonicalize(new ArrayType(tb.type(), SizeThunk.mul(SizeThunk.constant(len), tb.type().getSize()), len, 0, locusTag)));
return;
} catch (RecognitionException e) {
// Fall through
}
}
tb.setType(canonicalize(new PointerType(SizeThunk.POINTER,
- tb.type(),
- 0)));
+ tb.type(), 0, locusTag)));
}
private int parseIntConstExpr(AST t) throws RecognitionException {
@@ -315,49 +352,104 @@ 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, ASTLocusTag locusTag) {
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.
- enumType = new EnumType(enumTypeName, SizeThunk.INT32);
+ // 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, locusTag);
}
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;
+ }
+ }
+
+ private void throwGlueGenException(final AST t, final String message) throws GlueGenException {
+ // dumpASTTree("XXX", t);
+ throw new GlueGenException(message, findASTLocusTag(t));
+ }
+ private void throwGlueGenException(final ASTLocusTag locusTag, final String message) throws GlueGenException {
+ // dumpASTTree("XXX", t);
+ throw new GlueGenException(message, locusTag);
+ }
+
+ /**
+ * Return ASTLocusTag in tree, or null if not found.
+ */
+ private ASTLocusTag findASTLocusTag(final AST astIn) {
+ AST ast = astIn;
+ while(null != ast) {
+ if( ast instanceof TNode ) {
+ final TNode tn = (TNode) ast;
+ final ASTLocusTag tag = tn.getASTLocusTag();
+ if( null != tag ) {
+ return tag;
+ }
+ }
+ ast = ast.getFirstChild();
+ }
+ return null;
+ }
+ private void dumpASTTree(final String pre, final AST t) {
+ int i=0;
+ AST it = t;
+ while( null != it ) {
+ it = dumpAST(pre+"."+i, it);
+ i++;
+ }
+ }
+ private AST dumpAST(final String pre, final AST ast) {
+ if( null == ast ) {
+ System.err.println(pre+".0: AST NULL");
+ return null;
+ } else {
+ System.err.println(pre+".0: AST Type: "+ast.getClass().getName());
+ System.err.println(pre+".1: line:col "+ast.getLine()+":"+ast.getColumn()+" -> "+ast.getText());
+ if( ast instanceof TNode ) {
+ final TNode tn = (TNode) ast;
+ final ASTLocusTag tag = tn.getASTLocusTag();
+ System.err.println(pre+".TN.1: "+tag);
+ final Hashtable<String, Object> attributes = tn.getAttributesTable();
+ System.err.println(pre+".TN.2: "+attributes);
+ }
+ return ast.getFirstChild();
}
- 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;
+ final ASTLocusTag locusTag = findASTLocusTag(declarator_AST_in);
}
: #( NDeclarator
( pointerGroup[tb] )?
@@ -374,32 +466,29 @@ 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, locusTag);
} else if ( funcPointerName != null ) {
/* TypeBox becomes function pointer in this case */
- FunctionType ft = new FunctionType(null, null, tb.type(), 0);
+ final FunctionType ft = new FunctionType(null, null, tb.type(), 0, locusTag);
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, locusTag), "/*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, locusTag)));
s = funcPointerName;
}
}
- | LBRACKET ( e:expr )? RBRACKET { handleArrayExpr(tb, e); }
+ | LBRACKET ( e:expr )? RBRACKET { handleArrayExpr(tb, e, locusTag); }
)*
)
;
@@ -422,8 +511,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] {
@@ -435,7 +524,13 @@ parameterDeclaration returns [ParameterDeclaration pd] {
: #( NParameterDeclaration
tb = declSpecifiers
(decl = declarator[tb] | nonemptyAbstractDeclarator[tb])?
- ) { pd = new ParameterDeclaration(decl, tb.type()); }
+ ) {
+ if( null == tb ) {
+ throwGlueGenException(parameterDeclaration_AST_in,
+ String.format("Undefined type for declaration '%s'", decl));
+ }
+ pd = new ParameterDeclaration(decl, tb.type());
+ }
;
functionDef {
@@ -462,7 +557,10 @@ declSpecifiers returns [TypeBox tb] {
{
if (t == null &&
(x & (SIGNED | UNSIGNED)) != 0) {
- t = new IntType("int", SizeThunk.INTxx, ((x & UNSIGNED) != 0), attrs2CVAttrs(x));
+ t = new IntType("int", SizeThunk.INTxx,
+ ((x & UNSIGNED) != 0),
+ attrs2CVAttrs(x),
+ findASTLocusTag(declSpecifiers_AST_in));
}
tb = new TypeBox(t, ((x & TYPEDEF) != 0));
}
@@ -493,30 +591,35 @@ typeQualifier returns [int x] { x = 0; }
typeSpecifier[int attributes] returns [Type t] {
t = null;
int cvAttrs = attrs2CVAttrs(attributes);
- boolean unsigned = ((attributes & UNSIGNED) != 0);
+ boolean unsig = ((attributes & UNSIGNED) != 0);
+ final ASTLocusTag locusTag = findASTLocusTag(typeSpecifier_AST_in);
}
- : "void" { t = new VoidType(cvAttrs); }
- | "char" { t = new IntType("char" , SizeThunk.INT8, unsigned, cvAttrs); }
- | "short" { t = new IntType("short", SizeThunk.INT16, unsigned, cvAttrs); }
- | "int" { t = new IntType("int" , SizeThunk.INTxx, unsigned, cvAttrs); }
- | "long" { t = new IntType("long" , SizeThunk.LONG, unsigned, cvAttrs); }
- | "float" { t = new FloatType("float", SizeThunk.FLOAT, cvAttrs); }
- | "double" { t = new DoubleType("double", SizeThunk.DOUBLE, cvAttrs); }
- | "__int32" { t = new IntType("__int32", SizeThunk.INT32, unsigned, cvAttrs); }
- | "__int64" { t = new IntType("__int64", SizeThunk.INT64, unsigned, cvAttrs); }
- | "int8_t" { t = new IntType("int8_t", SizeThunk.INT8, false, cvAttrs); /* TS: always signed */ }
- | "uint8_t" { t = new IntType("uint8_t", SizeThunk.INT8, true, cvAttrs); /* TS: always unsigned */ }
- | "int16_t" { t = new IntType("int16_t", SizeThunk.INT16, false, cvAttrs); /* TS: always signed */ }
- | "uint16_t" { t = new IntType("uint16_t", SizeThunk.INT16, true, cvAttrs); /* TS: always unsigned */ }
- | "int32_t" { t = new IntType("int32_t", SizeThunk.INT32, false, cvAttrs); /* TS: always signed */ }
- | "wchar_t" { t = new IntType("wchar_t", SizeThunk.INT32, false, cvAttrs); /* TS: always signed */ }
- | "uint32_t" { t = new IntType("uint32_t", SizeThunk.INT32, true, cvAttrs, true); /* TS: always unsigned */ }
- | "int64_t" { t = new IntType("int64_t", SizeThunk.INT64, false, cvAttrs); /* TS: always signed */ }
- | "uint64_t" { t = new IntType("uint64_t", SizeThunk.INT64, true, cvAttrs, true); /* TS: always unsigned */ }
- | "ptrdiff_t" { t = new IntType("ptrdiff_t", SizeThunk.POINTER, false, cvAttrs); /* TS: always signed */ }
- | "intptr_t" { t = new IntType("intptr_t", SizeThunk.POINTER, false, cvAttrs); /* TS: always signed */ }
- | "size_t" { t = new IntType("size_t", SizeThunk.POINTER, true, cvAttrs, true); /* TS: always unsigned */ }
- | "uintptr_t" { t = new IntType("uintptr_t", SizeThunk.POINTER, true, cvAttrs, true); /* TS: always unsigned */ }
+ // TYPEDEF
+ // | TYPEDEF-UNSIGNED
+ // UNSIGNED | |
+ // TOKEN TYPE NAME SIZE | ATTRIBS | | LOCUS
+ : "void" { t = new VoidType( cvAttrs, locusTag); }
+ | "char" { t = new IntType("char" , SizeThunk.INT8, unsig, cvAttrs, false, false, locusTag); }
+ | "short" { t = new IntType("short", SizeThunk.INT16, unsig, cvAttrs, false, false, locusTag); }
+ | "int" { t = new IntType("int" , SizeThunk.INTxx, unsig, cvAttrs, false, false, locusTag); }
+ | "long" { t = new IntType("long" , SizeThunk.LONG, unsig, cvAttrs, false, false, locusTag); }
+ | "float" { t = new FloatType("float", SizeThunk.FLOAT, cvAttrs, locusTag); }
+ | "double" { t = new DoubleType("double", SizeThunk.DOUBLE, cvAttrs, locusTag); }
+ | "__int32" { t = new IntType("__int32", SizeThunk.INT32, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */
+ | "__int64" { t = new IntType("__int64", SizeThunk.INT64, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */
+ | "int8_t" { t = new IntType("int8_t", SizeThunk.INT8, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */
+ | "uint8_t" { t = new IntType("uint8_t", SizeThunk.INT8, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */
+ | "int16_t" { t = new IntType("int16_t", SizeThunk.INT16, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */
+ | "uint16_t" { t = new IntType("uint16_t", SizeThunk.INT16, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */
+ | "int32_t" { t = new IntType("int32_t", SizeThunk.INT32, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */
+ | "wchar_t" { t = new IntType("wchar_t", SizeThunk.INT32, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */
+ | "uint32_t" { t = new IntType("uint32_t", SizeThunk.INT32, unsig, cvAttrs, true, true, locusTag); } /* TS: unsigned */
+ | "int64_t" { t = new IntType("int64_t", SizeThunk.INT64, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */
+ | "uint64_t" { t = new IntType("uint64_t", SizeThunk.INT64, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */
+ | "ptrdiff_t" { t = new IntType("ptrdiff_t", SizeThunk.POINTER, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */
+ | "intptr_t" { t = new IntType("intptr_t", SizeThunk.POINTER, unsig, cvAttrs, true, false, locusTag); } /* TD: signed */
+ | "size_t" { t = new IntType("size_t", SizeThunk.POINTER, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */
+ | "uintptr_t" { t = new IntType("uintptr_t", SizeThunk.POINTER, unsig, cvAttrs, true, true, locusTag); } /* TD: unsigned */
| t = structSpecifier[cvAttrs] ( attributeDecl )*
| t = unionSpecifier [cvAttrs] ( attributeDecl )*
| t = enumSpecifier [cvAttrs]
@@ -533,9 +636,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(typedefName_AST_in, id.getText());
+ debugPrint("Adding typedef lookup: [" + id.getText() + "] -> "+getDebugTypeString(t0));
+ final Type t1 = t0.newCVVariant(cvAttrs);
+ debugPrintln(" - cvvar -> "+getDebugTypeString(t1));
+ t = canonicalize(t1);
+ debugPrintln(" - canon -> "+getDebugTypeString(t));
}
;
@@ -549,31 +655,50 @@ unionSpecifier[int cvAttrs] returns [Type t] { t = null; }
structOrUnionBody[CompoundTypeKind kind, int cvAttrs] returns [CompoundType t] {
t = null;
+ boolean addedAny = false;
+ final ASTLocusTag locusTag = findASTLocusTag(structOrUnionBody_AST_in);
}
: ( (ID LCURLY) => id:ID LCURLY {
- t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs));
- } ( structDeclarationList[t] )?
+ // fully declared struct, i.e. not anonymous
+ t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs, locusTag));
+ } ( addedAny = structDeclarationList[t] )?
RCURLY { t.setBodyParsed(); }
- | LCURLY { t = CompoundType.create(null, null, kind, cvAttrs); }
- ( structDeclarationList[t] )?
+ | LCURLY {
+ // anonymous declared struct
+ t = CompoundType.create(null, null, kind, cvAttrs, locusTag);
+ } ( structDeclarationList[t] )?
RCURLY { t.setBodyParsed(); }
- | id2:ID { t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs)); }
- )
+ | id2:ID {
+ // anonymous struct
+ t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs, locusTag));
+ }
+ ) {
+ debugPrintln("Adding compound body: [" + t.getName() + "] -> "+getDebugTypeString(t)+" @ "+locusTag);
+ debugPrintln(t.getStructString());
+ }
;
-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) {
if (t != null) {
CompoundType ct = t.asCompound();
- if (ct.isUnion()) {
+ if( null == ct ) {
+ throwGlueGenException(structDeclaration_AST_in,
+ String.format("Anonymous compound, w/ NULL type:%n containing '%s'",
+ getTypeString(containingType)));
+ }
+ if ( ct.isUnion() ) {
// Anonymous union
containingType.addField(new Field(null, t, null));
}
@@ -591,7 +716,8 @@ specifierQualifierList returns [Type t] {
)+ {
if (t == null &&
(x & (SIGNED | UNSIGNED)) != 0) {
- t = new IntType("int", SizeThunk.INTxx, ((x & UNSIGNED) != 0), attrs2CVAttrs(x));
+ t = new IntType("int", SizeThunk.INTxx, ((x & UNSIGNED) != 0), attrs2CVAttrs(x),
+ findASTLocusTag(specifierQualifierList_AST_in));
}
}
;
@@ -616,7 +742,7 @@ structDeclarator[CompoundType containingType, Type t] returns [boolean addedAny]
)
;
-// FIXME: this will not correctly set the name of the enumeration when
+// This will not correctly set the name of the enumeration when
// encountering a declaration like this:
//
// typedef enum { } enumName;
@@ -625,65 +751,88 @@ structDeclarator[CompoundType containingType, Type t] returns [boolean addedAny]
// incorrectly return HeaderParser.ANONYMOUS_ENUM_NAME instead of
// "enumName"
//
-// I haven't implemented it yet because I'm not sure how to get the
-// "enumName" *before* executing the enumList rule.
+// The followup typedef, see 'initDecl', will alias this name,
+// hence correct the issue!
enumSpecifier [int cvAttrs] returns [Type t] {
t = null;
+ EnumType e = null;
+ ASTLocusTag locusTag = findASTLocusTag(enumSpecifier_AST_in);
}
: #( "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(), locusTag))] RCURLY
+ | LCURLY enumList[(EnumType)(e = getEnumType(ANONYMOUS_ENUM_NAME, locusTag))] RCURLY
+ | ID { e = getEnumType(i.getText(), locusTag); }
+ ) {
+ 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) ) {
+ throwGlueGenException(enumSpecifier_AST_in,
+ String.format("Duplicate enum w/ incompatible type:%n this '%s',%n have '%s',%n %s: previous definition is here",
+ getTypeString(e), getTypeString(dupE), dupE.getASTLocusTag().toString(new StringBuilder(), "note", true)));
+ }
+ enumMap.put(eName, (EnumType)e.clone(locusTag));
+ }
+ }
+ t = e; // return val
+ }
+ )
;
enumList[EnumType enumeration] {
- long defaultEnumerantValue = 0;
+ ConstantDefinition defEnumerant = new ConstantDefinition("def", "0", new CNumber(true, false, 0), findASTLocusTag(enumList_AST_in));
}
- : ( defaultEnumerantValue = enumerator[enumeration, defaultEnumerantValue] )+
+ : ( defEnumerant = enumerator[enumeration, defEnumerant] )+
;
-enumerator[EnumType enumeration, long defaultValue] returns [long newDefaultValue] {
+enumerator[EnumType enumeration, ConstantDefinition defaultValue] returns [ConstantDefinition newDefaultValue] {
newDefaultValue = defaultValue;
}
: eName:ID ( ASSIGN eVal:expr )? {
- long value = 0;
+ final String eTxt = eName.getText();
+ final Enumerator newEnum;
if (eVal != null) {
- String vTxt = eVal.getAllChildrenText();
+ String vTxt = eVal.getAllChildrenText(eTxt);
if (enumHash.containsKey(vTxt)) {
EnumType oldEnumType = enumHash.get(vTxt);
- value = oldEnumType.getEnumValue(vTxt);
+ Enumerator oldEnum = oldEnumType.getEnum(vTxt);
+ newEnum = oldEnum;
} else {
- try {
- value = Long.decode(vTxt).longValue();
- } catch (NumberFormatException e) {
- System.err.println("NumberFormatException: ID[" + eName.getText() + "], VALUE=[" + vTxt + "]");
- throw e;
- }
+ newEnum = new Enumerator(eTxt, vTxt);
}
+ } else if( defaultValue.hasNumber() ) {
+ newEnum = new Enumerator(eTxt, defaultValue.getNumber());
} else {
- value = defaultValue;
+ newEnum = new Enumerator(eTxt, defaultValue.getNativeExpr());
}
-
- 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 + ")");
- }
+ final ASTLocusTag locus = findASTLocusTag(enumerator_AST_in);
+ final CNumber newEnumNum = newEnum.getNumber();
+ if( null != newEnumNum && newEnumNum.isInteger ) {
+ final long n = newEnumNum.i+1;
+ newDefaultValue = new ConstantDefinition("def", String.valueOf(n), new CNumber(newEnumNum.isLong, newEnumNum.isUnsigned, n), locus);
+ } else {
+ newDefaultValue = new ConstantDefinition("def", "("+newEnum.getExpr()+")+1", null, locus);
+ }
+ if (enumHash.containsKey(eTxt)) {
+ EnumType oldEnumType = enumHash.get(eTxt);
+ final Enumerator oldEnum = oldEnumType.getEnum(eTxt);
+ final String oldExpr = oldEnum.getExpr();
+ if( !oldExpr.equals(newEnum.getExpr()) ) {
+ throwGlueGenException(enumerator_AST_in,
+ String.format("Duplicate enum value '%s.%s' w/ diff value:%n this %s,%n have %s",
+ oldEnumType.getName(), eTxt, newEnum, oldEnum));
+ }
+ // remove old definition
+ oldEnumType.removeEnumerate(eTxt);
+ }
+ // insert new definition
+ enumeration.addEnum(eTxt, newEnum);
+ enumHash.put(eTxt, enumeration);
+ debugPrintln("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + newEnum +
+ " (new default = " + newDefaultValue + ")");
+ }
;
initDeclList[TypeBox tb]
@@ -692,6 +841,7 @@ initDeclList[TypeBox tb]
initDecl[TypeBox tb] {
String declName = null;
+ final ASTLocusTag locusTag = findASTLocusTag(initDecl_AST_in);
}
: #( NInitDecl
declName = declarator[tb] {
@@ -705,23 +855,99 @@ initDecl[TypeBox tb] {
{
if ((declName != null) && (tb != null) && tb.isTypedef()) {
Type t = tb.type();
- debugPrint("Adding typedef mapping: [" + declName + "] -> "+getTypeString(t));
- if (!t.hasTypedefName()) {
- t.setName(declName);
- debugPrint(" - declName -> "+getTypeString(t));
+ debugPrintln("Adding typedef mapping: [" + declName + "] -> "+getDebugTypeString(t));
+ final Type tg;
+ if( t.isPointer() ) {
+ tg = t.getTargetType();
+ debugPrintln(" - has target: "+getDebugTypeString(tg));
} else {
- // copy type to preserve declName !
- t = (Type) t.clone();
- t.setName(declName);
- debugPrint(" - copy -> "+getTypeString(t));
+ tg = null;
+ }
+ // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser)
+ // Also see NOTE below.
+ if (!t.isTypedef()) {
+ if( t.isCompound() || t.isEnum() ) {
+ // This aliases '_a' -> 'A' for 'typedef struct _a { } A;' in-place
+ // This aliases '_a' -> 'A' for 'typedef enum _a { } A;' in-place
+ t.setTypedefName(declName);
+ debugPrintln(" - alias.11 -> "+getDebugTypeString(t));
+ } else {
+ // Use new typedef, using a copy to preserve canonicalized base type
+ t = t.clone(locusTag);
+ t.setTypedefName(declName);
+ debugPrintln(" - newdefine.12 -> "+getDebugTypeString(t));
+ }
+ } else {
+ // Adds typeInfo alias w/ t's typeInfo, if exists
+ cfg.addTypeInfo(declName, t);
+ final Type alias;
+ if( t.isCompound() ) {
+ // This aliases 'D' -> 'A' for 'typedef struct _a { } A, D;' in-place
+ debugPrintln(" - alias.21 -> "+getDebugTypeString(t));
+ } else {
+ // copy to preserve canonicalized base type
+ t = t.clone(locusTag);
+ t.setTypedefName(declName);
+ debugPrintln(" - copy.22 -> "+getDebugTypeString(t));
+ }
+ }
+ final Type dupT = typedefDictionary.get(declName);
+ if( null != dupT && !dupT.equalSemantics(t) ) {
+ throwGlueGenException(locusTag,
+ String.format("Duplicate typedef w/ incompatible type:%n this '%s',%n have '%s',%n %s: previous definition is here",
+ getTypeString(t), getTypeString(dupT), dupT.getASTLocusTag().toString(new StringBuilder(), "note", true)));
}
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();
}
}
+ /*
+ // Below just shows a different handling using copying
+ // and enforcing aliased names, which is not desired.
+ // Keeping it in here for documentation.
+ // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser)
+ if ( !t.isTypedef() ) {
+ if( t.isCompound() ) {
+ // This aliases '_a' -> 'A' for 'typedef struct _a { } A;'
+ t.setTypedefName(declName);
+ debugPrintln(" - alias.10 -> "+getDebugTypeString(t));
+ } else if( null != tg && tg.isCompound() ) {
+ if( !tg.isTypedef() ) {
+ // This aliases '_a *' -> 'A*' for 'typedef struct _a { } *A;'
+ t.setTypedefName(declName);
+ debugPrintln(" - alias.11 -> "+getDebugTypeString(t));
+ } else {
+ // This aliases 'B' -> 'A*' for 'typedef struct _a { } A, *B;' and 'typedef A * B;'
+ t = new PointerType(SizeThunk.POINTER, tg, 0, locusTag); // name: 'A*'
+ t.setTypedefName(t.getName()); // make typedef
+ debugPrintln(" - alias.12 -> "+getDebugTypeString(t));
+ }
+ } else {
+ // Use new typedef, using a copy to preserve canonicalized base type
+ t = t.clone(locusTag);
+ t.setTypedefName(declName);
+ debugPrintln(" - newdefine.13 -> "+getDebugTypeString(t));
+ }
+ } else {
+ // Adds typeInfo alias w/ t's typeInfo, if exists
+ cfg.addTypeInfo(declName, t);
+ if( t.isCompound() ) {
+ // This aliases 'D' -> 'A' for 'typedef struct _a { } A, D;'
+ debugPrintln(" - alias.20 -> "+getDebugTypeString(t));
+ } else if( null != tg && tg.isCompound() ) {
+ // This aliases 'B' -> 'A' for 'typedef A B;', where A is pointer to compound
+ debugPrintln(" - alias.21 -> "+getDebugTypeString(t));
+ } else {
+ // copy to preserve canonicalized base type
+ t = t.clone(locusTag);
+ t.setTypedefName(declName);
+ debugPrintln(" - copy.22 -> "+getDebugTypeString(t));
+ }
+ }
+*/
;
pointerGroup[TypeBox tb] { int x = 0; int y = 0; }
@@ -731,7 +957,8 @@ 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),
+ findASTLocusTag(pointerGroup_AST_in))));
}
}
)+ )
@@ -756,7 +983,9 @@ typeName {
/* FIXME: the handling of types in this rule has not been well thought
out and is known to be incomplete. Currently it is only used to handle
pointerGroups for unnamed parameters. */
-nonemptyAbstractDeclarator[TypeBox tb]
+nonemptyAbstractDeclarator[TypeBox tb] {
+ final ASTLocusTag locusTag = findASTLocusTag(nonemptyAbstractDeclarator_AST_in);
+}
: #( NNonemptyAbstractDeclarator
( pointerGroup[tb]
( (LPAREN
@@ -764,7 +993,7 @@ nonemptyAbstractDeclarator[TypeBox tb]
| parameterTypeList
)?
RPAREN)
- | (LBRACKET (e1:expr)? RBRACKET) { handleArrayExpr(tb, e1); }
+ | (LBRACKET (e1:expr)? RBRACKET) { handleArrayExpr(tb, e1, locusTag); }
)*
| ( (LPAREN
@@ -772,7 +1001,7 @@ nonemptyAbstractDeclarator[TypeBox tb]
| parameterTypeList
)?
RPAREN)
- | (LBRACKET (e2:expr)? RBRACKET) { handleArrayExpr(tb, e2); }
+ | (LBRACKET (e2:expr)? RBRACKET) { handleArrayExpr(tb, e2, locusTag); }
)+
)
)
@@ -786,13 +1015,17 @@ intConstExpr returns [int i] { i = -1; }
final String enumName = e.getText();
final EnumType enumType = enumHash.get(enumName);
if( null == enumType ) {
- throw new IllegalArgumentException("Error: intConstExpr ID "+enumName+" recognized, but no containing enum-type found");
+ throwGlueGenException(intConstExpr_AST_in,
+ "Error: intConstExpr ID "+enumName+" recognized, but no containing enum-type found");
}
- final long enumValue = enumType.getEnumValue(enumName);
- System.err.println("INFO: intConstExpr: enum[Type "+enumType.getName()+", name "+enumName+", value "+enumValue+"]");
- if( (long)Integer.MIN_VALUE > enumValue || (long)Integer.MAX_VALUE < enumValue ) {
- throw new IndexOutOfBoundsException("Error: intConstExpr ID "+enumName+" enum-value "+enumValue+" out of int range");
+ final Enumerator enumerator = enumType.getEnum(enumName);
+ final CNumber number = enumerator.getNumber();
+ if( null != number && number.isInteger && !number.isLong ) {
+ debugPrintln("INFO: intConstExpr: enum[Type "+enumType.getName()+", "+enumerator+"]");
+ } else {
+ throwGlueGenException(intConstExpr_AST_in,
+ "Error: intConstExpr ID "+enumName+" enum "+enumerator+" not an int32_t");
}
- return (int)enumValue;
+ return (int)number.i;
}
;
diff --git a/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g b/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g
index 7b34656..26da996 100644
--- a/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g
+++ b/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g
@@ -1131,11 +1131,12 @@ options {
nw:NonWhitespace
("\r\n" | "\r" | "\n") ) {
if (n != null) {
- //System.out.println("addDefine: #define " + i.getText() + " " + n.getText());
+ // System.out.println("addDefine: #define " + i.getText() + " " + n.getText()+" @ "+lineObject.getSource()+":"+(lineObject.line+deferredLineCount));
addDefine(i.getText(), n.getText());
} else {
setPreprocessingDirective("#define " + i.getText() + " " + nw.getText());
}
+ deferredNewline();
}
| (~'\n')* { setPreprocessingDirective(getText()); }
)
@@ -1165,15 +1166,19 @@ protected LineDirective
}
:
{
- lineObject = new LineObject();
- deferredLineCount = 0;
+ lineObject = new LineObject();
+ deferredLineCount = 0;
}
("line")? //this would be for if the directive started "#line", but not there for GNU directives
(Space)+
- n:Number { lineObject.setLine(Integer.parseInt(n.getText())); }
+ n:Number {
+ lineObject.setLine(Integer.parseInt(n.getText()));
+ }
(Space)+
( fn:StringLiteral { try {
- lineObject.setSource(fn.getText().substring(1,fn.getText().length()-1));
+ final String newSource = fn.getText().substring(1,fn.getText().length()-1);
+ // System.out.println("line: "+lineObject.getSource()+" -> "+newSource+", line "+(lineObject.line+deferredLineCount));
+ lineObject.setSource(newSource);
}
catch (StringIndexOutOfBoundsException e) { /*not possible*/ }
}
diff --git a/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g b/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g
index f67579e..1c06bfd 100644
--- a/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g
+++ b/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g
@@ -8,105 +8,105 @@
* Run 'java Main <directory full of java files>'
*
* Contributing authors:
- * John Mitchell [email protected]
- * Terence Parr [email protected]
- * John Lilley [email protected]
- * Scott Stanchfield [email protected]
- * Markus Mohnen [email protected]
+ * John Mitchell [email protected]
+ * Terence Parr [email protected]
+ * John Lilley [email protected]
+ * Scott Stanchfield [email protected]
+ * Markus Mohnen [email protected]
* Peter Williams [email protected]
* Allan Jacobs [email protected]
* Steve Messick [email protected]
- * John Pybus [email protected]
+ * John Pybus [email protected]
*
* Version 1.00 December 9, 1997 -- initial release
* Version 1.01 December 10, 1997
- * fixed bug in octal def (0..7 not 0..8)
+ * fixed bug in octal def (0..7 not 0..8)
* Version 1.10 August 1998 (parrt)
- * added tree construction
- * fixed definition of WS,comments for mac,pc,unix newlines
- * added unary plus
+ * added tree construction
+ * fixed definition of WS,comments for mac,pc,unix newlines
+ * added unary plus
* Version 1.11 (Nov 20, 1998)
- * Added "shutup" option to turn off last ambig warning.
- * Fixed inner class def to allow named class defs as statements
- * synchronized requires compound not simple statement
- * add [] after builtInType DOT class in primaryExpression
- * "const" is reserved but not valid..removed from modifiers
+ * Added "shutup" option to turn off last ambig warning.
+ * Fixed inner class def to allow named class defs as statements
+ * synchronized requires compound not simple statement
+ * add [] after builtInType DOT class in primaryExpression
+ * "const" is reserved but not valid..removed from modifiers
* Version 1.12 (Feb 2, 1999)
- * Changed LITERAL_xxx to xxx in tree grammar.
- * Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ * Changed LITERAL_xxx to xxx in tree grammar.
+ * Updated java.g to use tokens {...} now for 2.6.0 (new feature).
*
* Version 1.13 (Apr 23, 1999)
- * Didn't have (stat)? for else clause in tree parser.
- * Didn't gen ASTs for interface extends. Updated tree parser too.
- * Updated to 2.6.0.
+ * Didn't have (stat)? for else clause in tree parser.
+ * Didn't gen ASTs for interface extends. Updated tree parser too.
+ * Updated to 2.6.0.
* Version 1.14 (Jun 20, 1999)
- * Allowed final/abstract on local classes.
- * Removed local interfaces from methods
- * Put instanceof precedence where it belongs...in relationalExpr
- * It also had expr not type as arg; fixed it.
- * Missing ! on SEMI in classBlock
- * fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
- * fixed: didn't like Object[].class in parser or tree parser
+ * Allowed final/abstract on local classes.
+ * Removed local interfaces from methods
+ * Put instanceof precedence where it belongs...in relationalExpr
+ * It also had expr not type as arg; fixed it.
+ * Missing ! on SEMI in classBlock
+ * fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ * fixed: didn't like Object[].class in parser or tree parser
* Version 1.15 (Jun 26, 1999)
- * Screwed up rule with instanceof in it. :( Fixed.
- * Tree parser didn't like (expr).something; fixed.
- * Allowed multiple inheritance in tree grammar. oops.
+ * Screwed up rule with instanceof in it. :( Fixed.
+ * Tree parser didn't like (expr).something; fixed.
+ * Allowed multiple inheritance in tree grammar. oops.
* Version 1.16 (August 22, 1999)
- * Extending an interface built a wacky tree: had extra EXTENDS.
- * Tree grammar didn't allow multiple superinterfaces.
- * Tree grammar didn't allow empty var initializer: {}
+ * Extending an interface built a wacky tree: had extra EXTENDS.
+ * Tree grammar didn't allow multiple superinterfaces.
+ * Tree grammar didn't allow empty var initializer: {}
* Version 1.17 (October 12, 1999)
- * ESC lexer rule allowed 399 max not 377 max.
- * java.tree.g didn't handle the expression of synchronized
- * statements.
+ * ESC lexer rule allowed 399 max not 377 max.
+ * java.tree.g didn't handle the expression of synchronized
+ * statements.
* Version 1.18 (August 12, 2001)
- * Terence updated to Java 2 Version 1.3 by
- * observing/combining work of Allan Jacobs and Steve
- * Messick. Handles 1.3 src. Summary:
- * o primary didn't include boolean.class kind of thing
- * o constructor calls parsed explicitly now:
- * see explicitConstructorInvocation
- * o add strictfp modifier
- * o missing objBlock after new expression in tree grammar
- * o merged local class definition alternatives, moved after declaration
- * o fixed problem with ClassName.super.field
- * o reordered some alternatives to make things more efficient
- * o long and double constants were not differentiated from int/float
- * o whitespace rule was inefficient: matched only one char
- * o add an examples directory with some nasty 1.3 cases
- * o made Main.java use buffered IO and a Reader for Unicode support
- * o supports UNICODE?
- * Using Unicode charVocabulay makes code file big, but only
- * in the bitsets at the end. I need to make ANTLR generate
- * unicode bitsets more efficiently.
+ * Terence updated to Java 2 Version 1.3 by
+ * observing/combining work of Allan Jacobs and Steve
+ * Messick. Handles 1.3 src. Summary:
+ * o primary didn't include boolean.class kind of thing
+ * o constructor calls parsed explicitly now:
+ * see explicitConstructorInvocation
+ * o add strictfp modifier
+ * o missing objBlock after new expression in tree grammar
+ * o merged local class definition alternatives, moved after declaration
+ * o fixed problem with ClassName.super.field
+ * o reordered some alternatives to make things more efficient
+ * o long and double constants were not differentiated from int/float
+ * o whitespace rule was inefficient: matched only one char
+ * o add an examples directory with some nasty 1.3 cases
+ * o made Main.java use buffered IO and a Reader for Unicode support
+ * o supports UNICODE?
+ * Using Unicode charVocabulay makes code file big, but only
+ * in the bitsets at the end. I need to make ANTLR generate
+ * unicode bitsets more efficiently.
* Version 1.19 (April 25, 2002)
- * Terence added in nice fixes by John Pybus concerning floating
- * constants and problems with super() calls. John did a nice
- * reorg of the primary/postfix expression stuff to read better
- * and makes f.g.super() parse properly (it was METHOD_CALL not
- * a SUPER_CTOR_CALL). Also:
+ * Terence added in nice fixes by John Pybus concerning floating
+ * constants and problems with super() calls. John did a nice
+ * reorg of the primary/postfix expression stuff to read better
+ * and makes f.g.super() parse properly (it was METHOD_CALL not
+ * a SUPER_CTOR_CALL). Also:
*
- * o "finally" clause was a root...made it a child of "try"
- * o Added stuff for asserts too for Java 1.4, but *commented out*
- * as it is not backward compatible.
+ * o "finally" clause was a root...made it a child of "try"
+ * o Added stuff for asserts too for Java 1.4, but *commented out*
+ * as it is not backward compatible.
*
* Version 1.20 (October 27, 2002)
*
* Terence ended up reorging John Pybus' stuff to
* remove some nondeterminisms and some syntactic predicates.
* Note that the grammar is stricter now; e.g., this(...) must
- * be the first statement.
+ * be the first statement.
*
* Trinary ?: operator wasn't working as array name:
* (isBig ? bigDigits : digits)[i];
*
* Checked parser/tree parser on source for
* Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
- * and the 110k-line jGuru server source.
+ * and the 110k-line jGuru server source.
*
* Version 1.21 (October 17, 2003)
- * Fixed lots of problems including:
- * Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
+ * Fixed lots of problems including:
+ * Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
* He found a problem/fix with floating point that start with 0
* Ray also fixed problem that (int.class) was not recognized.
* Thorsten van Ellen noticed that \n are allowed incorrectly in strings.
@@ -129,24 +129,24 @@ header {
class JavaParser extends Parser;
options {
- k = 2; // two token lookahead
- exportVocab=Java; // Call its vocabulary "Java"
- codeGenMakeSwitchThreshold = 2; // Some optimizations
- codeGenBitsetTestThreshold = 3;
- defaultErrorHandler = false; // Don't generate parser error handlers
- buildAST = true;
- //buildAST = false;
+ k = 2; // two token lookahead
+ exportVocab=Java; // Call its vocabulary "Java"
+ codeGenMakeSwitchThreshold = 2; // Some optimizations
+ codeGenBitsetTestThreshold = 3;
+ defaultErrorHandler = false; // Don't generate parser error handlers
+ buildAST = true;
+ //buildAST = false;
}
tokens {
- BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF;
- INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
- PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
- PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
- POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT;
- IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
- FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
- STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL;
+ BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF;
+ INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
+ PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+ PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
+ POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT;
+ IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
+ FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+ STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL;
}
{
@@ -181,250 +181,250 @@ tokens {
// Compilation Unit: In Java, this is a single file. This is the start
// rule for this parser
compilationUnit
- : // A compilation unit starts with an optional package definition
- ( packageDefinition
- | /* nothing */
- )
+ : // A compilation unit starts with an optional package definition
+ ( packageDefinition
+ | /* nothing */
+ )
- // Next we have a series of zero or more import statements
- ( importDefinition )*
+ // Next we have a series of zero or more import statements
+ ( importDefinition )*
- // Wrapping things up with any number of class or interface
- // definitions
- ( typeDefinition )*
+ // Wrapping things up with any number of class or interface
+ // definitions
+ ( typeDefinition )*
- EOF!
- ;
+ EOF!
+ ;
// Package statement: "package" followed by an identifier.
packageDefinition
- options {defaultErrorHandler = true;} // let ANTLR handle errors
- : p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI!
- ;
+ options {defaultErrorHandler = true;} // let ANTLR handle errors
+ : p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI!
+ ;
// Import statement: import followed by a package or class name
importDefinition
- options {defaultErrorHandler = true;}
- : i:"import"^ {#i.setType(IMPORT);} identifierStar SEMI!
- ;
+ options {defaultErrorHandler = true;}
+ : i:"import"^ {#i.setType(IMPORT);} identifierStar SEMI!
+ ;
// A type definition in a file is either a class or interface definition.
typeDefinition
- options {defaultErrorHandler = true;}
- : m:modifiers!
- ( classDefinition[#m]
- | interfaceDefinition[#m]
- )
- | SEMI!
- ;
+ options {defaultErrorHandler = true;}
+ : m:modifiers!
+ ( classDefinition[#m]
+ | interfaceDefinition[#m]
+ )
+ | SEMI!
+ ;
/** A declaration is the creation of a reference or primitive-type variable
* Create a separate Type/Var tree for each var in the var list.
*/
declaration!
- : m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
- {#declaration = #v;}
- ;
+ : m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
+ {#declaration = #v;}
+ ;
// A type specification is a type name with possible brackets afterwards
// (which would make it an array type).
typeSpec[boolean addImagNode]
- : classTypeSpec[addImagNode]
- | builtInTypeSpec[addImagNode]
- ;
+ : classTypeSpec[addImagNode]
+ | builtInTypeSpec[addImagNode]
+ ;
// A class type specification is a class type with possible brackets afterwards
// (which would make it an array type).
classTypeSpec[boolean addImagNode]
- : identifier (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
- {
- if ( addImagNode ) {
- #classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec);
- }
- }
- ;
+ : identifier (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ {
+ if ( addImagNode ) {
+ #classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec);
+ }
+ }
+ ;
// A builtin type specification is a builtin type with possible brackets
// afterwards (which would make it an array type).
builtInTypeSpec[boolean addImagNode]
- : builtInType (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
- {
- if ( addImagNode ) {
- #builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
- }
- }
- ;
+ : builtInType (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ {
+ if ( addImagNode ) {
+ #builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
+ }
+ }
+ ;
// A type name. which is either a (possibly qualified) class name or
// a primitive (builtin) type
type
- : identifier
- | builtInType
- ;
+ : identifier
+ | builtInType
+ ;
// The primitive types.
builtInType
- : "void"
- | "boolean"
- | "byte"
- | "char"
- | "short"
- | "int"
- | "float"
- | "long"
- | "double"
- ;
+ : "void"
+ | "boolean"
+ | "byte"
+ | "char"
+ | "short"
+ | "int"
+ | "float"
+ | "long"
+ | "double"
+ ;
// A (possibly-qualified) java identifier. We start with the first IDENT
// and expand its name by adding dots and following IDENTS
identifier
- : IDENT ( DOT^ IDENT )*
- ;
+ : IDENT ( DOT^ IDENT )*
+ ;
identifierStar
- : IDENT
- ( DOT^ IDENT )*
- ( DOT^ STAR )?
- ;
+ : IDENT
+ ( DOT^ IDENT )*
+ ( DOT^ STAR )?
+ ;
// A list of zero or more modifiers. We could have used (modifier)* in
// place of a call to modifiers, but I thought it was a good idea to keep
// this rule separate so they can easily be collected in a Vector if
// someone so desires
modifiers
- : ( modifier )*
- {#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);}
- ;
+ : ( modifier )*
+ {#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);}
+ ;
// modifiers for Java classes, interfaces, class/instance vars and methods
modifier
- : "private"
- | "public"
- | "protected"
- | "static"
- | "transient"
- | "final"
- | "abstract"
- | "native"
- | "threadsafe"
- | "synchronized"
-// | "const" // reserved word, but not valid
- | "volatile"
- | "strictfp"
- ;
+ : "private"
+ | "public"
+ | "protected"
+ | "static"
+ | "transient"
+ | "final"
+ | "abstract"
+ | "native"
+ | "threadsafe"
+ | "synchronized"
+// | "const" // reserved word, but not valid
+ | "volatile"
+ | "strictfp"
+ ;
// Definition of a Java class
classDefinition![AST modifiers]
- : "class" IDENT
- // it _might_ have a superclass...
- sc:superClassClause
- // it might implement some interfaces...
- ic:implementsClause
- // now parse the body of the class
- cb:classBlock
- {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
- modifiers,IDENT,sc,ic,cb);}
- ;
+ : "class" IDENT
+ // it _might_ have a superclass...
+ sc:superClassClause
+ // it might implement some interfaces...
+ ic:implementsClause
+ // now parse the body of the class
+ cb:classBlock
+ {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
+ modifiers,IDENT,sc,ic,cb);}
+ ;
superClassClause!
- : ( "extends" id:identifier )?
- {#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],id);}
- ;
+ : ( "extends" id:identifier )?
+ {#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],id);}
+ ;
// Definition of a Java Interface
interfaceDefinition![AST modifiers]
- : "interface" IDENT
- // it might extend some other interfaces
- ie:interfaceExtends
- // now parse the body of the interface (looks like a class...)
- cb:classBlock
- {#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"],
- modifiers,IDENT,ie,cb);}
- ;
+ : "interface" IDENT
+ // it might extend some other interfaces
+ ie:interfaceExtends
+ // now parse the body of the interface (looks like a class...)
+ cb:classBlock
+ {#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"],
+ modifiers,IDENT,ie,cb);}
+ ;
// This is the body of a class. You can have fields and extra semicolons,
// That's about it (until you see what a field is...)
classBlock
- : LCURLY! { blockDepth++; }
- ( field | SEMI! )*
- RCURLY! { blockDepth--; }
- {#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
- ;
+ : LCURLY! { blockDepth++; }
+ ( field | SEMI! )*
+ RCURLY! { blockDepth--; }
+ {#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
+ ;
// An interface can extend several other interfaces...
interfaceExtends
- : (
- e:"extends"!
- identifier ( COMMA! identifier )*
- )?
- {#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],
- #interfaceExtends);}
- ;
+ : (
+ e:"extends"!
+ identifier ( COMMA! identifier )*
+ )?
+ {#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],
+ #interfaceExtends);}
+ ;
// A class can implement several interfaces...
implementsClause
- : (
- i:"implements"! identifier ( COMMA! identifier )*
- )?
- {#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"],
- #implementsClause);}
- ;
+ : (
+ i:"implements"! identifier ( COMMA! identifier )*
+ )?
+ {#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"],
+ #implementsClause);}
+ ;
// Now the various things that can be defined inside a class or interface...
// Note that not all of these are really valid in an interface (constructors,
// for example), and if this grammar were used for a compiler there would
// need to be some semantic checks to make sure we're doing the right thing...
field!
- : // method, constructor, or variable declaration
- mods:modifiers
- ( h:ctorHead s:constructorBody // constructor
- {#field = #(#[CTOR_DEF,"CTOR_DEF"], mods, h, s);}
+ : // method, constructor, or variable declaration
+ mods:modifiers
+ ( h:ctorHead s:constructorBody // constructor
+ {#field = #(#[CTOR_DEF,"CTOR_DEF"], mods, h, s);}
- | cd:classDefinition[#mods] // inner class
- {#field = #cd;}
+ | cd:classDefinition[#mods] // inner class
+ {#field = #cd;}
- | id:interfaceDefinition[#mods] // inner interface
- {#field = #id;}
+ | id:interfaceDefinition[#mods] // inner interface
+ {#field = #id;}
- | t:typeSpec[false] // method or variable declaration(s)
- ( fn:IDENT // the name of the method
+ | t:typeSpec[false] // method or variable declaration(s)
+ ( fn:IDENT // the name of the method
- // parse the formal parameter declarations.
- LPAREN! param:parameterDeclarationList RPAREN!
+ // parse the formal parameter declarations.
+ LPAREN! param:parameterDeclarationList RPAREN!
- rt:declaratorBrackets[#t]
+ rt:declaratorBrackets[#t]
- // get the list of exceptions that this method is
- // declared to throw
- (tc:throwsClause)?
+ // get the list of exceptions that this method is
+ // declared to throw
+ (tc:throwsClause)?
- ( s2:compoundStatement | SEMI )
- {#field = #(#[METHOD_DEF,"METHOD_DEF"],
- mods,
- #(#[TYPE,"TYPE"],rt),
- fn,
- param,
- tc,
- s2);
+ ( s2:compoundStatement | SEMI )
+ {#field = #(#[METHOD_DEF,"METHOD_DEF"],
+ mods,
+ #(#[TYPE,"TYPE"],rt),
+ fn,
+ param,
+ tc,
+ s2);
if(blockDepth==1) {
functionNames.add(fn.getText()); } }
- | v:variableDefinitions[#mods,#t] SEMI
-// {#field = #(#[VARIABLE_DEF,"VARIABLE_DEF"], v);}
- {#field = #v;}
- )
- )
+ | v:variableDefinitions[#mods,#t] SEMI
+// {#field = #(#[VARIABLE_DEF,"VARIABLE_DEF"], v);}
+ {#field = #v;}
+ )
+ )
// "static { ... }" class initializer
- | "static" s3:compoundStatement
- {#field = #(#[STATIC_INIT,"STATIC_INIT"], s3);}
+ | "static" s3:compoundStatement
+ {#field = #(#[STATIC_INIT,"STATIC_INIT"], s3);}
// "{ ... }" instance initializer
- | s4:compoundStatement
- {#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);}
- ;
+ | s4:compoundStatement
+ {#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);}
+ ;
constructorBody
: lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; }
@@ -436,108 +436,108 @@ constructorBody
/** Catch obvious constructor calls, but not the expr.super(...) calls */
explicitConstructorInvocation
: "this"! lp1:LPAREN^ argList RPAREN! SEMI!
- {#lp1.setType(CTOR_CALL);}
+ {#lp1.setType(CTOR_CALL);}
| "super"! lp2:LPAREN^ argList RPAREN! SEMI!
- {#lp2.setType(SUPER_CTOR_CALL);}
+ {#lp2.setType(SUPER_CTOR_CALL);}
;
variableDefinitions[AST mods, AST t]
- : variableDeclarator[getASTFactory().dupTree(mods),
- getASTFactory().dupTree(t)]
- ( COMMA!
- variableDeclarator[getASTFactory().dupTree(mods),
- getASTFactory().dupTree(t)]
- )*
- ;
+ : variableDeclarator[getASTFactory().dupTree(mods),
+ getASTFactory().dupTree(t)]
+ ( COMMA!
+ variableDeclarator[getASTFactory().dupTree(mods),
+ getASTFactory().dupTree(t)]
+ )*
+ ;
/** Declaration of a variable. This can be a class/instance variable,
* or a local variable in a method
* It can also include possible initialization.
*/
variableDeclarator![AST mods, AST t]
- : id:IDENT d:declaratorBrackets[t] v:varInitializer
- {#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v);
+ : id:IDENT d:declaratorBrackets[t] v:varInitializer
+ {#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v);
if(blockDepth==1) {
enumNames.add(id.getText());
}
}
- ;
+ ;
declaratorBrackets[AST typ]
- : {#declaratorBrackets=typ;}
- (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
- ;
+ : {#declaratorBrackets=typ;}
+ (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ ;
varInitializer
- : ( ASSIGN^ initializer )?
- ;
+ : ( ASSIGN^ initializer )?
+ ;
// This is an initializer used to set up an array.
arrayInitializer
- : lc:LCURLY^ {#lc.setType(ARRAY_INIT); blockDepth++; }
- ( initializer
- (
- // CONFLICT: does a COMMA after an initializer start a new
- // initializer or start the option ',' at end?
- // ANTLR generates proper code by matching
- // the comma as soon as possible.
- options {
- warnWhenFollowAmbig = false;
- }
- :
- COMMA! initializer
- )*
- (COMMA!)?
- )?
- RCURLY! { blockDepth--; }
- ;
+ : lc:LCURLY^ {#lc.setType(ARRAY_INIT); blockDepth++; }
+ ( initializer
+ (
+ // CONFLICT: does a COMMA after an initializer start a new
+ // initializer or start the option ',' at end?
+ // ANTLR generates proper code by matching
+ // the comma as soon as possible.
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ COMMA! initializer
+ )*
+ (COMMA!)?
+ )?
+ RCURLY! { blockDepth--; }
+ ;
// The two "things" that can initialize an array element are an expression
// and another (nested) array initializer.
initializer
- : expression
- | arrayInitializer
- ;
+ : expression
+ | arrayInitializer
+ ;
// This is the header of a method. It includes the name and parameters
// for the method.
// This also watches for a list of exception classes in a "throws" clause.
ctorHead
- : IDENT // the name of the method
+ : IDENT // the name of the method
- // parse the formal parameter declarations.
- LPAREN! parameterDeclarationList RPAREN!
+ // parse the formal parameter declarations.
+ LPAREN! parameterDeclarationList RPAREN!
- // get the list of exceptions that this method is declared to throw
- (throwsClause)?
- ;
+ // get the list of exceptions that this method is declared to throw
+ (throwsClause)?
+ ;
// This is a list of exception classes that the method is declared to throw
throwsClause
- : "throws"^ identifier ( COMMA! identifier )*
- ;
+ : "throws"^ identifier ( COMMA! identifier )*
+ ;
// A list of formal parameters
parameterDeclarationList
- : ( parameterDeclaration ( COMMA! parameterDeclaration )* )?
- {#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
- #parameterDeclarationList);}
- ;
+ : ( parameterDeclaration ( COMMA! parameterDeclaration )* )?
+ {#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
+ #parameterDeclarationList);}
+ ;
// A formal parameter.
parameterDeclaration!
- : pm:parameterModifier t:typeSpec[false] id:IDENT
- pd:declaratorBrackets[#t]
- {#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
- pm, #([TYPE,"TYPE"],pd), id);}
- ;
+ : pm:parameterModifier t:typeSpec[false] id:IDENT
+ pd:declaratorBrackets[#t]
+ {#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
+ pm, #([TYPE,"TYPE"],pd), id);}
+ ;
parameterModifier
- : (f:"final")?
- {#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], f);}
- ;
+ : (f:"final")?
+ {#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], f);}
+ ;
// Compound statement. This is used in many contexts:
// Inside a class definition prefixed with "static":
@@ -549,151 +549,151 @@ parameterModifier
// it starts a new scope for variable definitions
compoundStatement
- : lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; }
- // include the (possibly-empty) list of statements
- (statement)*
- RCURLY! { blockDepth--; }
- ;
+ : lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; }
+ // include the (possibly-empty) list of statements
+ (statement)*
+ RCURLY! { blockDepth--; }
+ ;
statement
- // A list of statements in curly braces -- start a new scope!
- : compoundStatement
-
- // declarations are ambiguous with "ID DOT" relative to expression
- // statements. Must backtrack to be sure. Could use a semantic
- // predicate to test symbol table to see what the type was coming
- // up, but that's pretty hard without a symbol table ;)
- | (declaration)=> declaration SEMI!
-
- // An expression statement. This could be a method call,
- // assignment statement, or any other expression evaluated for
- // side-effects.
- | expression SEMI!
-
- // class definition
- | m:modifiers! classDefinition[#m]
-
- // Attach a label to the front of a statement
- | IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
-
- // If-else statement
- | "if"^ LPAREN! expression RPAREN! statement
- (
- // CONFLICT: the old "dangling-else" problem...
- // ANTLR generates proper code matching
- // as soon as possible. Hush warning.
- options {
- warnWhenFollowAmbig = false;
- }
- :
- "else"! statement
- )?
-
- // For statement
- | "for"^
- LPAREN!
- forInit SEMI! // initializer
- forCond SEMI! // condition test
- forIter // updater
- RPAREN!
- statement // statement to loop over
-
- // While statement
- | "while"^ LPAREN! expression RPAREN! statement
-
- // do-while statement
- | "do"^ statement "while"! LPAREN! expression RPAREN! SEMI!
-
- // get out of a loop (or switch)
- | "break"^ (IDENT)? SEMI!
-
- // do next iteration of a loop
- | "continue"^ (IDENT)? SEMI!
-
- // Return an expression
- | "return"^ (expression)? SEMI!
-
- // switch/case statement
- | "switch"^ LPAREN! expression RPAREN! LCURLY! { blockDepth++; }
- ( casesGroup )*
- RCURLY! { blockDepth--; }
-
- // exception try-catch block
- | tryBlock
-
- // throw an exception
- | "throw"^ expression SEMI!
-
- // synchronize a statement
- | "synchronized"^ LPAREN! expression RPAREN! compoundStatement
-
- // asserts (uncomment if you want 1.4 compatibility)
- // | "assert"^ expression ( COLON! expression )? SEMI!
-
- // empty statement
- | s:SEMI {#s.setType(EMPTY_STAT);}
- ;
+ // A list of statements in curly braces -- start a new scope!
+ : compoundStatement
+
+ // declarations are ambiguous with "ID DOT" relative to expression
+ // statements. Must backtrack to be sure. Could use a semantic
+ // predicate to test symbol table to see what the type was coming
+ // up, but that's pretty hard without a symbol table ;)
+ | (declaration)=> declaration SEMI!
+
+ // An expression statement. This could be a method call,
+ // assignment statement, or any other expression evaluated for
+ // side-effects.
+ | expression SEMI!
+
+ // class definition
+ | m:modifiers! classDefinition[#m]
+
+ // Attach a label to the front of a statement
+ | IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
+
+ // If-else statement
+ | "if"^ LPAREN! expression RPAREN! statement
+ (
+ // CONFLICT: the old "dangling-else" problem...
+ // ANTLR generates proper code matching
+ // as soon as possible. Hush warning.
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ "else"! statement
+ )?
+
+ // For statement
+ | "for"^
+ LPAREN!
+ forInit SEMI! // initializer
+ forCond SEMI! // condition test
+ forIter // updater
+ RPAREN!
+ statement // statement to loop over
+
+ // While statement
+ | "while"^ LPAREN! expression RPAREN! statement
+
+ // do-while statement
+ | "do"^ statement "while"! LPAREN! expression RPAREN! SEMI!
+
+ // get out of a loop (or switch)
+ | "break"^ (IDENT)? SEMI!
+
+ // do next iteration of a loop
+ | "continue"^ (IDENT)? SEMI!
+
+ // Return an expression
+ | "return"^ (expression)? SEMI!
+
+ // switch/case statement
+ | "switch"^ LPAREN! expression RPAREN! LCURLY! { blockDepth++; }
+ ( casesGroup )*
+ RCURLY! { blockDepth--; }
+
+ // exception try-catch block
+ | tryBlock
+
+ // throw an exception
+ | "throw"^ expression SEMI!
+
+ // synchronize a statement
+ | "synchronized"^ LPAREN! expression RPAREN! compoundStatement
+
+ // asserts (uncomment if you want 1.4 compatibility)
+ // | "assert"^ expression ( COLON! expression )? SEMI!
+
+ // empty statement
+ | s:SEMI {#s.setType(EMPTY_STAT);}
+ ;
casesGroup
- : ( // CONFLICT: to which case group do the statements bind?
- // ANTLR generates proper code: it groups the
- // many "case"/"default" labels together then
- // follows them with the statements
- options {
- greedy = true;
- }
- :
- aCase
- )+
- caseSList
- {#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
- ;
+ : ( // CONFLICT: to which case group do the statements bind?
+ // ANTLR generates proper code: it groups the
+ // many "case"/"default" labels together then
+ // follows them with the statements
+ options {
+ greedy = true;
+ }
+ :
+ aCase
+ )+
+ caseSList
+ {#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
+ ;
aCase
- : ("case"^ expression | "default") COLON!
- ;
+ : ("case"^ expression | "default") COLON!
+ ;
caseSList
- : (statement)*
- {#caseSList = #(#[SLIST,"SLIST"],#caseSList);}
- ;
+ : (statement)*
+ {#caseSList = #(#[SLIST,"SLIST"],#caseSList);}
+ ;
// The initializer for a for loop
forInit
- // if it looks like a declaration, it is
- : ( (declaration)=> declaration
- // otherwise it could be an expression list...
- | expressionList
- )?
- {#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);}
- ;
+ // if it looks like a declaration, it is
+ : ( (declaration)=> declaration
+ // otherwise it could be an expression list...
+ | expressionList
+ )?
+ {#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);}
+ ;
forCond
- : (expression)?
- {#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);}
- ;
+ : (expression)?
+ {#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);}
+ ;
forIter
- : (expressionList)?
- {#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);}
- ;
+ : (expressionList)?
+ {#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);}
+ ;
// an exception handler try/catch block
tryBlock
- : "try"^ compoundStatement
- (handler)*
- ( finallyClause )?
- ;
+ : "try"^ compoundStatement
+ (handler)*
+ ( finallyClause )?
+ ;
finallyClause
- : "finally"^ compoundStatement
- ;
+ : "finally"^ compoundStatement
+ ;
// an exception handler
handler
- : "catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement
- ;
+ : "catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement
+ ;
// expressions
@@ -732,22 +732,22 @@ handler
// the mother of all expressions
expression
- : assignmentExpression
- {#expression = #(#[EXPR,"EXPR"],#expression);}
- ;
+ : assignmentExpression
+ {#expression = #(#[EXPR,"EXPR"],#expression);}
+ ;
// This is a list of expressions.
expressionList
- : expression (COMMA! expression)*
- {#expressionList = #(#[ELIST,"ELIST"], expressionList);}
- ;
+ : expression (COMMA! expression)*
+ {#expressionList = #(#[ELIST,"ELIST"], expressionList);}
+ ;
// assignment expression (level 13)
assignmentExpression
- : conditionalExpression
- ( ( ASSIGN^
+ : conditionalExpression
+ ( ( ASSIGN^
| PLUS_ASSIGN^
| MINUS_ASSIGN^
| STAR_ASSIGN^
@@ -760,99 +760,99 @@ assignmentExpression
| BXOR_ASSIGN^
| BOR_ASSIGN^
)
- assignmentExpression
- )?
- ;
+ assignmentExpression
+ )?
+ ;
// conditional test (level 12)
conditionalExpression
- : logicalOrExpression
- ( QUESTION^ assignmentExpression COLON! conditionalExpression )?
- ;
+ : logicalOrExpression
+ ( QUESTION^ assignmentExpression COLON! conditionalExpression )?
+ ;
// logical or (||) (level 11)
logicalOrExpression
- : logicalAndExpression (LOR^ logicalAndExpression)*
- ;
+ : logicalAndExpression (LOR^ logicalAndExpression)*
+ ;
// logical and (&&) (level 10)
logicalAndExpression
- : inclusiveOrExpression (LAND^ inclusiveOrExpression)*
- ;
+ : inclusiveOrExpression (LAND^ inclusiveOrExpression)*
+ ;
// bitwise or non-short-circuiting or (|) (level 9)
inclusiveOrExpression
- : exclusiveOrExpression (BOR^ exclusiveOrExpression)*
- ;
+ : exclusiveOrExpression (BOR^ exclusiveOrExpression)*
+ ;
// exclusive or (^) (level 8)
exclusiveOrExpression
- : andExpression (BXOR^ andExpression)*
- ;
+ : andExpression (BXOR^ andExpression)*
+ ;
// bitwise or non-short-circuiting and (&) (level 7)
andExpression
- : equalityExpression (BAND^ equalityExpression)*
- ;
+ : equalityExpression (BAND^ equalityExpression)*
+ ;
// equality/inequality (==/!=) (level 6)
equalityExpression
- : relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
- ;
+ : relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
+ ;
// boolean relational expressions (level 5)
relationalExpression
- : shiftExpression
- ( ( ( LT^
- | GT^
- | LE^
- | GE^
- )
- shiftExpression
- )*
- | "instanceof"^ typeSpec[true]
- )
- ;
+ : shiftExpression
+ ( ( ( LT^
+ | GT^
+ | LE^
+ | GE^
+ )
+ shiftExpression
+ )*
+ | "instanceof"^ typeSpec[true]
+ )
+ ;
// bit shift expressions (level 4)
shiftExpression
- : additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
- ;
+ : additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
+ ;
// binary addition/subtraction (level 3)
additiveExpression
- : multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
- ;
+ : multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
+ ;
// multiplication/division/modulo (level 2)
multiplicativeExpression
- : unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
- ;
+ : unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
+ ;
unaryExpression
- : INC^ unaryExpression
- | DEC^ unaryExpression
- | MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
- | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression
- | unaryExpressionNotPlusMinus
- ;
+ : INC^ unaryExpression
+ | DEC^ unaryExpression
+ | MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
+ | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression
+ | unaryExpressionNotPlusMinus
+ ;
unaryExpressionNotPlusMinus
- : BNOT^ unaryExpression
- | LNOT^ unaryExpression
+ : BNOT^ unaryExpression
+ | LNOT^ unaryExpression
- // use predicate to skip cases like: (int.class)
+ // use predicate to skip cases like: (int.class)
| (LPAREN builtInTypeSpec[true] RPAREN) =>
lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN!
unaryExpression
@@ -860,108 +860,108 @@ unaryExpressionNotPlusMinus
// Have to backtrack to see if operator follows. If no operator
// follows, it's a typecast. No semantic checking needed to parse.
// if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
- | (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
+ | (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN!
unaryExpressionNotPlusMinus
- | postfixExpression
- ;
+ | postfixExpression
+ ;
// qualified names, array expressions, method invocation, post inc/dec
postfixExpression
- :
+ :
/*
"this"! lp1:LPAREN^ argList RPAREN!
- {#lp1.setType(CTOR_CALL);}
+ {#lp1.setType(CTOR_CALL);}
| "super"! lp2:LPAREN^ argList RPAREN!
- {#lp2.setType(SUPER_CTOR_CALL);}
+ {#lp2.setType(SUPER_CTOR_CALL);}
|
*/
primaryExpression
- (
+ (
/*
options {
- // the use of postfixExpression in SUPER_CTOR_CALL adds DOT
- // to the lookahead set, and gives loads of false non-det
- // warnings.
- // shut them off.
- generateAmbigWarnings=false;
- }
- : */
+ // the use of postfixExpression in SUPER_CTOR_CALL adds DOT
+ // to the lookahead set, and gives loads of false non-det
+ // warnings.
+ // shut them off.
+ generateAmbigWarnings=false;
+ }
+ : */
DOT^ IDENT
- ( lp:LPAREN^ {#lp.setType(METHOD_CALL);}
- argList
- RPAREN!
- )?
- | DOT^ "this"
+ ( lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+ argList
+ RPAREN!
+ )?
+ | DOT^ "this"
- | DOT^ "super"
+ | DOT^ "super"
( // (new Outer()).super() (create enclosing instance)
lp3:LPAREN^ argList RPAREN!
{#lp3.setType(SUPER_CTOR_CALL);}
- | DOT^ IDENT
- ( lps:LPAREN^ {#lps.setType(METHOD_CALL);}
+ | DOT^ IDENT
+ ( lps:LPAREN^ {#lps.setType(METHOD_CALL);}
argList
RPAREN!
)?
)
- | DOT^ newExpression
- | lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK!
- )*
+ | DOT^ newExpression
+ | lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK!
+ )*
- ( // possibly add on a post-increment or post-decrement.
+ ( // possibly add on a post-increment or post-decrement.
// allows INC/DEC on too much, but semantics can check
- in:INC^ {#in.setType(POST_INC);}
- | de:DEC^ {#de.setType(POST_DEC);}
- )?
- ;
+ in:INC^ {#in.setType(POST_INC);}
+ | de:DEC^ {#de.setType(POST_DEC);}
+ )?
+ ;
// the basic element of an expression
primaryExpression
- : identPrimary ( options {greedy=true;} : DOT^ "class" )?
+ : identPrimary ( options {greedy=true;} : DOT^ "class" )?
| constant
- | "true"
- | "false"
- | "null"
+ | "true"
+ | "false"
+ | "null"
| newExpression
- | "this"
- | "super"
- | LPAREN! assignmentExpression RPAREN!
- // look for int.class and int[].class
- | builtInType
- ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
- DOT^ "class"
- ;
+ | "this"
+ | "super"
+ | LPAREN! assignmentExpression RPAREN!
+ // look for int.class and int[].class
+ | builtInType
+ ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
+ DOT^ "class"
+ ;
/** Match a, a.b.c refs, a.b.c(...) refs, a.b.c[], a.b.c[].class,
* and a.b.c.class refs. Also this(...) and super(...). Match
* this or super.
*/
identPrimary
- : IDENT
- (
+ : IDENT
+ (
options {
- // .ident could match here or in postfixExpression.
- // We do want to match here. Turn off warning.
- greedy=true;
- }
- : DOT^ IDENT
- )*
- (
+ // .ident could match here or in postfixExpression.
+ // We do want to match here. Turn off warning.
+ greedy=true;
+ }
+ : DOT^ IDENT
+ )*
+ (
options {
- // ARRAY_DECLARATOR here conflicts with INDEX_OP in
- // postfixExpression on LBRACK RBRACK.
- // We want to match [] here, so greedy. This overcomes
+ // ARRAY_DECLARATOR here conflicts with INDEX_OP in
+ // postfixExpression on LBRACK RBRACK.
+ // We want to match [] here, so greedy. This overcomes
// limitation of linear approximate lookahead.
- greedy=true;
- }
- : ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} argList RPAREN! )
- | ( options {greedy=true;} :
+ greedy=true;
+ }
+ : ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} argList RPAREN! )
+ | ( options {greedy=true;} :
lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK!
)+
- )?
+ )?
;
/** object instantiation.
@@ -1014,53 +1014,53 @@ identPrimary
*
*/
newExpression
- : "new"^ type
- ( LPAREN! argList RPAREN! (classBlock)?
-
- //java 1.1
- // Note: This will allow bad constructs like
- // new int[4][][3] {exp,exp}.
- // There needs to be a semantic check here...
- // to make sure:
- // a) [ expr ] and [ ] are not mixed
- // b) [ expr ] and an init are not used together
-
- | newArrayDeclarator (arrayInitializer)?
- )
- ;
+ : "new"^ type
+ ( LPAREN! argList RPAREN! (classBlock)?
+
+ //java 1.1
+ // Note: This will allow bad constructs like
+ // new int[4][][3] {exp,exp}.
+ // There needs to be a semantic check here...
+ // to make sure:
+ // a) [ expr ] and [ ] are not mixed
+ // b) [ expr ] and an init are not used together
+
+ | newArrayDeclarator (arrayInitializer)?
+ )
+ ;
argList
- : ( expressionList
- | /*nothing*/
- {#argList = #[ELIST,"ELIST"];}
- )
- ;
+ : ( expressionList
+ | /*nothing*/
+ {#argList = #[ELIST,"ELIST"];}
+ )
+ ;
newArrayDeclarator
- : (
- // CONFLICT:
- // newExpression is a primaryExpression which can be
- // followed by an array index reference. This is ok,
- // as the generated code will stay in this loop as
- // long as it sees an LBRACK (proper behavior)
- options {
- warnWhenFollowAmbig = false;
- }
- :
- lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
- (expression)?
- RBRACK!
- )+
- ;
+ : (
+ // CONFLICT:
+ // newExpression is a primaryExpression which can be
+ // followed by an array index reference. This is ok,
+ // as the generated code will stay in this loop as
+ // long as it sees an LBRACK (proper behavior)
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
+ (expression)?
+ RBRACK!
+ )+
+ ;
constant
- : NUM_INT
- | CHAR_LITERAL
- | STRING_LITERAL
- | NUM_FLOAT
- | NUM_LONG
- | NUM_DOUBLE
- ;
+ : NUM_INT
+ | CHAR_LITERAL
+ | STRING_LITERAL
+ | NUM_FLOAT
+ | NUM_LONG
+ | NUM_DOUBLE
+ ;
//----------------------------------------------------------------------------
// The Java scanner
@@ -1068,121 +1068,121 @@ constant
class JavaLexer extends Lexer;
options {
- exportVocab=Java; // call the vocabulary "Java"
- testLiterals=false; // don't automatically test for literals
- k=4; // four characters of lookahead
- charVocabulary='\u0003'..'\u7FFE';
- // without inlining some bitset tests, couldn't do unicode;
- // I need to make ANTLR generate smaller bitsets; see
- // bottom of JavaLexer.java
- codeGenBitsetTestThreshold=20;
+ exportVocab=Java; // call the vocabulary "Java"
+ testLiterals=false; // don't automatically test for literals
+ k=4; // four characters of lookahead
+ charVocabulary='\u0003'..'\u7FFE';
+ // without inlining some bitset tests, couldn't do unicode;
+ // I need to make ANTLR generate smaller bitsets; see
+ // bottom of JavaLexer.java
+ codeGenBitsetTestThreshold=20;
}
// OPERATORS
-QUESTION : '?' ;
-LPAREN : '(' ;
-RPAREN : ')' ;
-LBRACK : '[' ;
-RBRACK : ']' ;
-LCURLY : '{' ;
-RCURLY : '}' ;
-COLON : ':' ;
-COMMA : ',' ;
-//DOT : '.' ;
-ASSIGN : '=' ;
-EQUAL : "==" ;
-LNOT : '!' ;
-BNOT : '~' ;
-NOT_EQUAL : "!=" ;
-DIV : '/' ;
-DIV_ASSIGN : "/=" ;
-PLUS : '+' ;
-PLUS_ASSIGN : "+=" ;
-INC : "++" ;
-MINUS : '-' ;
-MINUS_ASSIGN : "-=" ;
-DEC : "--" ;
-STAR : '*' ;
-STAR_ASSIGN : "*=" ;
-MOD : '%' ;
-MOD_ASSIGN : "%=" ;
-SR : ">>" ;
-SR_ASSIGN : ">>=" ;
-BSR : ">>>" ;
-BSR_ASSIGN : ">>>=" ;
-GE : ">=" ;
-GT : ">" ;
-SL : "<<" ;
-SL_ASSIGN : "<<=" ;
-LE : "<=" ;
-LT : '<' ;
-BXOR : '^' ;
-BXOR_ASSIGN : "^=" ;
-BOR : '|' ;
-BOR_ASSIGN : "|=" ;
-LOR : "||" ;
-BAND : '&' ;
-BAND_ASSIGN : "&=" ;
-LAND : "&&" ;
-SEMI : ';' ;
+QUESTION : '?' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+LBRACK : '[' ;
+RBRACK : ']' ;
+LCURLY : '{' ;
+RCURLY : '}' ;
+COLON : ':' ;
+COMMA : ',' ;
+//DOT : '.' ;
+ASSIGN : '=' ;
+EQUAL : "==" ;
+LNOT : '!' ;
+BNOT : '~' ;
+NOT_EQUAL : "!=" ;
+DIV : '/' ;
+DIV_ASSIGN : "/=" ;
+PLUS : '+' ;
+PLUS_ASSIGN : "+=" ;
+INC : "++" ;
+MINUS : '-' ;
+MINUS_ASSIGN : "-=" ;
+DEC : "--" ;
+STAR : '*' ;
+STAR_ASSIGN : "*=" ;
+MOD : '%' ;
+MOD_ASSIGN : "%=" ;
+SR : ">>" ;
+SR_ASSIGN : ">>=" ;
+BSR : ">>>" ;
+BSR_ASSIGN : ">>>=" ;
+GE : ">=" ;
+GT : ">" ;
+SL : "<<" ;
+SL_ASSIGN : "<<=" ;
+LE : "<=" ;
+LT : '<' ;
+BXOR : '^' ;
+BXOR_ASSIGN : "^=" ;
+BOR : '|' ;
+BOR_ASSIGN : "|=" ;
+LOR : "||" ;
+BAND : '&' ;
+BAND_ASSIGN : "&=" ;
+LAND : "&&" ;
+SEMI : ';' ;
// Whitespace -- ignored
-WS : ( ' '
- | '\t'
- | '\f'
- // handle newlines
- | ( options {generateAmbigWarnings=false;}
- : "\r\n" // Evil DOS
- | '\r' // Macintosh
- | '\n' // Unix (the right way)
- )
- { newline(); }
- )+
- { _ttype = Token.SKIP; }
- ;
+WS : ( ' '
+ | '\t'
+ | '\f'
+ // handle newlines
+ | ( options {generateAmbigWarnings=false;}
+ : "\r\n" // Evil DOS
+ | '\r' // Macintosh
+ | '\n' // Unix (the right way)
+ )
+ { newline(); }
+ )+
+ { _ttype = Token.SKIP; }
+ ;
// Single-line comments
SL_COMMENT
- : "//"
- (~('\n'|'\r'))* ('\n'|'\r'('\n')?)?
- {$setType(Token.SKIP); newline();}
- ;
+ : "//"
+ (~('\n'|'\r'))* ('\n'|'\r'('\n')?)?
+ {$setType(Token.SKIP); newline();}
+ ;
// multiple-line comments
ML_COMMENT
- : "/*"
- ( /* '\r' '\n' can be matched in one alternative or by matching
- '\r' in one iteration and '\n' in another. I am trying to
- handle any flavor of newline that comes in, but the language
- that allows both "\r\n" and "\r" and "\n" to all be valid
- newline is ambiguous. Consequently, the resulting grammar
- must be ambiguous. I'm shutting this warning off.
- */
- options {
- generateAmbigWarnings=false;
- }
- :
- { LA(2)!='/' }? '*'
- | '\r' '\n' {newline();}
- | '\r' {newline();}
- | '\n' {newline();}
- | ~('*'|'\n'|'\r')
- )*
- "*/"
- {$setType(Token.SKIP);}
- ;
+ : "/*"
+ ( /* '\r' '\n' can be matched in one alternative or by matching
+ '\r' in one iteration and '\n' in another. I am trying to
+ handle any flavor of newline that comes in, but the language
+ that allows both "\r\n" and "\r" and "\n" to all be valid
+ newline is ambiguous. Consequently, the resulting grammar
+ must be ambiguous. I'm shutting this warning off.
+ */
+ options {
+ generateAmbigWarnings=false;
+ }
+ :
+ { LA(2)!='/' }? '*'
+ | '\r' '\n' {newline();}
+ | '\r' {newline();}
+ | '\n' {newline();}
+ | ~('*'|'\n'|'\r')
+ )*
+ "*/"
+ {$setType(Token.SKIP);}
+ ;
// character literals
CHAR_LITERAL
- : '\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\''
- ;
+ : '\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\''
+ ;
// string literals
STRING_LITERAL
- : '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
- ;
+ : '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
+ ;
// escape sequence -- note that this is protected; it can only be called
@@ -1195,121 +1195,132 @@ STRING_LITERAL
// the FOLLOW ambig warnings.
protected
ESC
- : '\\'
- ( 'n'
- | 'r'
- | 't'
- | 'b'
- | 'f'
- | '"'
- | '\''
- | '\\'
- | ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
- | '0'..'3'
- (
- options {
- warnWhenFollowAmbig = false;
- }
- : '0'..'7'
- (
- options {
- warnWhenFollowAmbig = false;
- }
- : '0'..'7'
- )?
- )?
- | '4'..'7'
- (
- options {
- warnWhenFollowAmbig = false;
- }
- : '0'..'7'
- )?
- )
- ;
+ : '\\'
+ ( 'n'
+ | 'r'
+ | 't'
+ | 'b'
+ | 'f'
+ | '"'
+ | '\''
+ | '\\'
+ | ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+ | '0'..'3'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )?
+ | '4'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )
+ ;
// hexadecimal digit (again, note it's protected!)
protected
HEX_DIGIT
- : ('0'..'9'|'A'..'F'|'a'..'f')
- ;
+ : ('0'..'9'|'A'..'F'|'a'..'f')
+ ;
// an identifier. Note that testLiterals is set to true! This means
// that after we match the rule, we look in the literals table to see
// if it's a literal or really an identifer
IDENT
- options {testLiterals=true;}
- : ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
- ;
+ options {testLiterals=true;}
+ : ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
+ ;
// a numeric literal
NUM_INT
- {boolean isDecimal=false; Token t=null;}
+ {boolean isDecimal=false, isHexadecimal=false; Token t=null;}
: '.' {_ttype = DOT;}
- ( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+ ( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
{
- if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
- _ttype = NUM_FLOAT;
- }
- else {
- _ttype = NUM_DOUBLE; // assume double
- }
- }
+ if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
+ _ttype = NUM_FLOAT;
+ }
+ else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
)?
- | ( '0' {isDecimal = true;} // special case for just '0'
- ( ('x'|'X')
- ( // hex
- // the 'e'|'E' and float suffix stuff look
- // like hex digits, hence the (...)+ doesn't
- // know when to stop: ambig. ANTLR resolves
- // it correctly by matching immediately. It
- // is therefor ok to hush warning.
- options {
- warnWhenFollowAmbig=false;
- }
- : HEX_DIGIT
- )+
-
- | //float or double with leading zero
- (('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
-
- | ('0'..'7')+ // octal
- )?
- | ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
- )
- ( ('l'|'L') { _ttype = NUM_LONG; }
-
- // only check to see if it's a float if looks like decimal so far
- | {isDecimal}?
- ( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
- | EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
- | f4:FLOAT_SUFFIX {t=f4;}
- )
- {
- if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
- _ttype = NUM_FLOAT;
- }
- else {
- _ttype = NUM_DOUBLE; // assume double
- }
- }
+ | ( '0' {isDecimal = true;} // special case for just '0'
+ ( ('x'|'X') { isHexadecimal=true; } // hex
+ (
+ // the 'e'|'E' and float suffix stuff look
+ // like hex digits, hence the (...)+ doesn't
+ // know when to stop: ambig. ANTLR resolves
+ // it correctly by matching immediately. It
+ // is therefor ok to hush warning.
+ options {
+ warnWhenFollowAmbig=false;
+ }
+ : HEX_DIGIT
+ )+
+
+ | //float or double with leading zero
+ (('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
+
+ | ('0'..'7')+ // octal
+ )?
+ | ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
+ )
+ (
+ ('l'|'L') { _ttype = NUM_LONG; }
+
+ // check to see if it's a hexadecimal w/ binary exponent float if looks like hexadecimal so far
+ | {isHexadecimal}?
+ ( '.' ( options { warnWhenFollowAmbig=false; } : HEX_DIGIT )* )?
+ ('p'|'P') ('+'|'-')? ('0'..'9')+ (f5:FLOAT_SUFFIX {t=f5;})?
+ {
+ if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+ _ttype = NUM_FLOAT;
+ } else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
+ // check to see if it's a float if looks like decimal so far
+ | {isDecimal}?
+ ( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
+ | EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
+ | f4:FLOAT_SUFFIX {t=f4;}
+ )
+ {
+ if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+ _ttype = NUM_FLOAT;
+ } else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
)?
- ;
+ ;
// a couple protected methods to assist in matching floating point numbers
protected
EXPONENT
- : ('e'|'E') ('+'|'-')? ('0'..'9')+
- ;
+ : ('e'|'E') (PLUS|MINUS)? ('0'..'9')+
+ ;
protected
FLOAT_SUFFIX
- : 'f'|'F'|'d'|'D'
- ;
+ : 'f'|'F'|'d'|'D'
+ ;
diff --git a/src/java/com/jogamp/common/ExceptionUtils.java b/src/java/com/jogamp/common/ExceptionUtils.java
index c848a99..386f42b 100644
--- a/src/java/com/jogamp/common/ExceptionUtils.java
+++ b/src/java/com/jogamp/common/ExceptionUtils.java
@@ -58,21 +58,97 @@ public class ExceptionUtils {
}
/**
- * Dumps a {@link Throwable} in a decorating message including the current thread name,
+ * Interface allowing {@link Throwable} specializations to provide their custom stack trace presentation.
+ * @since 2.3.2
+ */
+ public static interface CustomStackTrace {
+ /**
+ * Prints this {@link Throwable} as a cause to the output {@link PrintStream} {@code s},
+ * not iterating over all inner causes!
+ * @param s output stream
+ * @param causeStr the cause title
+ * @param causeIdx the cause index over all causes known by caller
+ * @param stackDepth the maximum depth for stack entries, or {@code -1} for all
+ * @since 2.3.2
+ */
+ void printCauseStack(final PrintStream s, final String causeStr, final int causeIdx, final int stackDepth);
+ /**
+ * Custom {@code printStackTrace} method, similar to {@link Throwable#printStackTrace(PrintStream, int, int)}.
+ * @param s output stream
+ * @param causeDepth the maximum depth for causes, or {@code -1} for all
+ * @param stackDepth the maximum depth for stack entries, or {@code -1} for all
+ */
+ void printStackTrace(final PrintStream s, final int causeDepth, final int stackDepth);
+ }
+
+ /**
+ * Prints the given {@link Throwable} cause to the output {@link PrintStream} {@code s}.
+ * @param s output stream
+ * @param causeStr the cause title
+ * @param cause the {@link Throwable} cause for output
+ * @param causeIdx the cause index over all causes known by caller
+ * @param causeDepth the maximum depth for causes, or {@code -1} for all
+ * @param stackDepth the maximum depth for stack entries, or {@code -1} for all
+ * @since 2.3.2
+ */
+ public static int printCause(final PrintStream s, final String causeStr, Throwable cause, final int causeIdx, final int causeDepth, final int stackDepth) {
+ int i=causeIdx;
+ for(; null != cause && ( -1 == causeDepth || i < causeDepth ); cause = cause.getCause()) {
+ if( cause instanceof CustomStackTrace ) {
+ ((CustomStackTrace)cause).printCauseStack(s, causeStr, i, stackDepth);
+ } else {
+ s.println(causeStr+"["+i+"] by "+cause.getClass().getSimpleName()+": "+cause.getMessage()+" on thread "+Thread.currentThread().getName());
+ dumpStack(s, cause.getStackTrace(), 0, stackDepth);
+ }
+ i++;
+ }
+ return i;
+ }
+
+ /**
+ * Prints the given {@link Throwable} to the output {@link PrintStream} {@code s}.
+ * @param s output stream
+ * @param t the {@link Throwable} for output
+ * @param causeDepth the maximum depth for causes, or {@code -1} for all
+ * @param stackDepth the maximum depth for stack entries, or {@code -1} for all
+ * @since 2.3.2
+ */
+ public static void printStackTrace(final PrintStream s, final Throwable t, final int causeDepth, final int stackDepth) {
+ if( t instanceof CustomStackTrace ) {
+ ((CustomStackTrace)t).printStackTrace(s, causeDepth, stackDepth);
+ } else {
+ s.println(t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName());
+ dumpStack(s, t.getStackTrace(), 0, stackDepth);
+ printCause(s, "Caused", t.getCause(), 0, causeDepth, stackDepth);
+ }
+ }
+
+ /**
+ * Dumps a {@link Throwable} to {@link System.err} in a decorating message including the current thread name,
* and its {@link #dumpStack(PrintStream, StackTraceElement[], int, int) stack trace}.
* <p>
* Implementation will iterate through all {@link Throwable#getCause() causes}.
* </p>
+ * @param additionalDescr additional text placed before the {@link Throwable} details.
+ * @param t the {@link Throwable} for output
*/
public static void dumpThrowable(final String additionalDescr, final Throwable t) {
- System.err.println("Caught "+additionalDescr+" "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName());
- dumpStack(System.err, t.getStackTrace(), 0, -1);
- int causeDepth = 1;
- for( Throwable cause = t.getCause(); null != cause; cause = cause.getCause() ) {
- System.err.println("Caused["+causeDepth+"] by "+cause.getClass().getSimpleName()+": "+cause.getMessage()+" on thread "+Thread.currentThread().getName());
- dumpStack(System.err, cause.getStackTrace(), 0, -1);
- causeDepth++;
- }
+ dumpThrowable(additionalDescr, t, -1, -1);
+ }
+ /**
+ * Dumps a {@link Throwable} to {@link System.err} in a decorating message including the current thread name,
+ * and its {@link #dumpStack(PrintStream, StackTraceElement[], int, int) stack trace}.
+ * <p>
+ * Implementation will iterate through all {@link Throwable#getCause() causes}.
+ * </p>
+ * @param additionalDescr additional text placed before the {@link Throwable} details.
+ * @param t the {@link Throwable} for output
+ * @param causeDepth the maximum depth for causes, or {@code -1} for all
+ * @param stackDepth the maximum depth for stack entries, or {@code -1} for all
+ * @since 2.3.2
+ */
+ public static void dumpThrowable(final String additionalDescr, final Throwable t, final int causeDepth, final int stackDepth) {
+ System.err.print("Caught "+additionalDescr+" ");
+ printStackTrace(System.err, t, causeDepth, stackDepth);
}
-
}
diff --git a/src/java/com/jogamp/common/JogampRuntimeException.java b/src/java/com/jogamp/common/JogampRuntimeException.java
index d33d498..524bb93 100644
--- a/src/java/com/jogamp/common/JogampRuntimeException.java
+++ b/src/java/com/jogamp/common/JogampRuntimeException.java
@@ -28,9 +28,10 @@
package com.jogamp.common;
-/** A generic exception for Jogamp errors used throughout the binding
- as a substitute for {@link RuntimeException}. */
-
+/**
+ * A generic <i>unchecked exception</i> for Jogamp errors used throughout the binding
+ * as a substitute for {@link RuntimeException}.
+ */
@SuppressWarnings("serial")
public class JogampRuntimeException extends RuntimeException {
/** Constructs a JogampRuntimeException object. */
diff --git a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
index 9b1865f..3ba8dff 100644
--- a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
+++ b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
@@ -61,7 +61,18 @@ import jogamp.common.Debug;
import jogamp.common.os.PlatformPropsImpl;
public class JNILibLoaderBase {
- public static final boolean DEBUG = Debug.debug("JNILibLoader");
+ public static final boolean DEBUG;
+ protected static final boolean PERF;
+
+ static {
+ Debug.initSingleton();
+ DEBUG = Debug.debug("JNILibLoader");
+ PERF = DEBUG || PropertyAccess.isPropertyDefined("jogamp.debug.JNILibLoader.Perf", true);
+ }
+
+ private static final Object perfSync = new Object();
+ private static long perfTotal = 0;
+ private static long perfCount = 0;
public interface LoaderAction {
/**
@@ -177,6 +188,7 @@ public class JNILibLoaderBase {
msg.append(")");
System.err.println(msg.toString());
}
+ final long t0 = PERF ? System.currentTimeMillis() : 0; // 'Platform.currentTimeMillis()' not yet available!
boolean ok = false;
@@ -195,28 +207,9 @@ public class JNILibLoaderBase {
if (DEBUG) {
System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: nativeLibraryPath: %s%n", nativeLibraryPath);
}
- final ClassLoader cl = classFromJavaJar.getClassLoader();
- final URL nativeLibraryURI = cl.getResource(nativeLibraryPath);
- if (null != nativeLibraryURI) {
- // We probably have one big-fat jar file, containing java classes
- // and all native platform libraries under 'natives/os.and.arch'!
- final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(jarBasename) );
- try {
- if( TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath) ) {
- ok = true;
- if (DEBUG) {
- System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: fat: %s -> %s%n", jarBasename, nativeJarURI);
- }
- }
- } catch(final Exception e) {
- if(DEBUG) {
- System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
- e.printStackTrace();
- }
- }
- }
- if (!ok) {
- // We assume one slim native jar file per 'os.and.arch'!
+ {
+ // Attempt-1 a 'one slim native jar file' per 'os.and.arch' layout
+ // with native platform libraries under 'natives/os.and.arch'!
final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(nativeJarBasename) );
if (DEBUG) {
@@ -224,7 +217,7 @@ public class JNILibLoaderBase {
}
try {
- ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, null /* nativeLibraryPath */);
+ ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath);
} catch(final Exception e) {
if(DEBUG) {
System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
@@ -233,40 +226,75 @@ public class JNILibLoaderBase {
}
}
if (!ok) {
- // Attempt to find via ClassLoader and Native-Jar-Tag,
- // assuming one slim native jar file per 'os.and.arch'!
- final String moduleName;
+ final ClassLoader cl = classFromJavaJar.getClassLoader();
{
- final String packageName = classFromJavaJar.getPackage().getName();
- final int idx = packageName.lastIndexOf('.');
- if( 0 <= idx ) {
- moduleName = packageName.substring(idx+1);
- } else {
- moduleName = packageName;
+ // Attempt-2 a 'one big-fat jar file' layout, containing java classes
+ // and all native platform libraries under 'natives/os.and.arch' per platform!
+ final URL nativeLibraryURI = cl.getResource(nativeLibraryPath);
+ if (null != nativeLibraryURI) {
+ final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(jarBasename) );
+ try {
+ if( TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath) ) {
+ ok = true;
+ if (DEBUG) {
+ System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: fat: %s -> %s%n", jarBasename, nativeJarURI);
+ }
+ }
+ } catch(final Exception e) {
+ if(DEBUG) {
+ System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
+ e.printStackTrace();
+ }
+ }
}
}
- final String os_and_arch_dot = PlatformPropsImpl.os_and_arch.replace('-', '.');
- final String nativeJarTagClassName = nativeJarTagPackage + "." + moduleName + "." + os_and_arch_dot + ".TAG"; // TODO: sync with gluegen-cpptasks-base.xml
- try {
- if(DEBUG) {
- System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: Locating module %s, os.and.arch %s: %s%n",
- moduleName, os_and_arch_dot, nativeJarTagClassName);
- }
- final Uri nativeJarTagClassJarURI = JarUtil.getJarUri(nativeJarTagClassName, cl);
- if (DEBUG) {
- System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: %s -> %s%n", nativeJarTagClassName, nativeJarTagClassJarURI);
+ if (!ok) {
+ // Attempt-3 to find via ClassLoader and Native-Jar-Tag,
+ // assuming one slim native jar file per 'os.and.arch'
+ // and native platform libraries under 'natives/os.and.arch'!
+ final String moduleName;
+ {
+ final String packageName = classFromJavaJar.getPackage().getName();
+ final int idx = packageName.lastIndexOf('.');
+ if( 0 <= idx ) {
+ moduleName = packageName.substring(idx+1);
+ } else {
+ moduleName = packageName;
+ }
}
- ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarTagClassJarURI, null /* nativeLibraryPath */);
- } catch (final Exception e ) {
- if(DEBUG) {
- System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
- e.printStackTrace();
+ final String os_and_arch_dot = PlatformPropsImpl.os_and_arch.replace('-', '.');
+ final String nativeJarTagClassName = nativeJarTagPackage + "." + moduleName + "." + os_and_arch_dot + ".TAG"; // TODO: sync with gluegen-cpptasks-base.xml
+ try {
+ if(DEBUG) {
+ System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: Locating module %s, os.and.arch %s: %s%n",
+ moduleName, os_and_arch_dot, nativeJarTagClassName);
+ }
+ final Uri nativeJarTagClassJarURI = JarUtil.getJarUri(nativeJarTagClassName, cl);
+ if (DEBUG) {
+ System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: %s -> %s%n", nativeJarTagClassName, nativeJarTagClassJarURI);
+ }
+ ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarTagClassJarURI, nativeLibraryPath);
+ } catch (final Exception e ) {
+ if(DEBUG) {
+ System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
+ e.printStackTrace();
+ }
}
}
}
- if (DEBUG) {
- System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: ok: %b%n", ok);
+ if (DEBUG || PERF) {
+ final long tNow = System.currentTimeMillis() - t0;
+ final long tTotal, tCount;
+ synchronized(perfSync) {
+ tCount = perfCount+1;
+ tTotal = perfTotal + tNow;
+ perfTotal = tTotal;
+ perfCount = tCount;
+ }
+ final double tAvrg = tTotal / (double)tCount;
+ System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl.X: %s / %s -> ok: %b; duration: now %d ms, total %d ms (count %d, avrg %.3f ms)%n",
+ jarBasename, nativeJarBasename, ok, tNow, tTotal, tCount, tAvrg);
}
return ok;
}
@@ -585,7 +613,7 @@ public class JNILibLoaderBase {
if(DEBUG) {
System.err.println("ERROR (retry w/ enumLibPath) - "+ex1.getMessage());
}
- final List<String> possiblePaths = NativeLibrary.enumerateLibraryPaths(libraryName, libraryName, libraryName, true, cl);
+ final List<String> possiblePaths = NativeLibrary.enumerateLibraryPaths(libraryName, libraryName, libraryName, cl);
// Iterate down these and see which one if any we can actually find.
for (final Iterator<String> iter = possiblePaths.iterator(); 0 == mode && iter.hasNext(); ) {
final String path = iter.next();
diff --git a/src/java/com/jogamp/common/net/AssetURLContext.java b/src/java/com/jogamp/common/net/AssetURLContext.java
index af90c01..8462a41 100644
--- a/src/java/com/jogamp/common/net/AssetURLContext.java
+++ b/src/java/com/jogamp/common/net/AssetURLContext.java
@@ -164,7 +164,7 @@ public abstract class AssetURLContext implements PiggybackURLContext {
url = new URL(path);
conn = open(url);
type = null != conn ? 1 : -1;
- } catch(final MalformedURLException e1) { if(DEBUG) { System.err.println("ERR(0): "+e1.getMessage()); } }
+ } catch(final MalformedURLException e1) { if(DEBUG) { System.err.println("FAIL(1): "+e1.getMessage()); } }
if(null == conn && null != cl) {
// lookup via ClassLoader .. cleanup leading '/'
@@ -189,7 +189,7 @@ public abstract class AssetURLContext implements PiggybackURLContext {
conn = open(url);
type = null != conn ? 3 : -1;
}
- } catch (final Throwable e) { if(DEBUG) { System.err.println("ERR(1): "+e.getMessage()); } }
+ } catch (final Throwable e) { if(DEBUG) { System.err.println("FAIL(3): "+e.getMessage()); } }
}
if(DEBUG) {
@@ -209,7 +209,7 @@ public abstract class AssetURLContext implements PiggybackURLContext {
final URLConnection c = url.openConnection();
c.connect(); // redundant
return c;
- } catch (final IOException ioe) { if(DEBUG) { System.err.println("ERR: "+ioe.getMessage()); } }
+ } catch (final IOException ioe) { if(DEBUG) { System.err.println("FAIL(2): "+ioe.getMessage()); } }
return null;
}
diff --git a/src/java/com/jogamp/common/net/Uri.java b/src/java/com/jogamp/common/net/Uri.java
index 6bafba2..bca90bf 100644
--- a/src/java/com/jogamp/common/net/Uri.java
+++ b/src/java/com/jogamp/common/net/Uri.java
@@ -1232,7 +1232,15 @@ public class Uri {
/** Returns true, if this instance is a {@code file} {@code scheme}, otherwise false. */
public final boolean isFileScheme() {
- return FILE_SCHEME.equals( scheme.get() );
+ return null != scheme && FILE_SCHEME.equals( scheme.get() );
+ }
+
+ /**
+ * Returns true, if this instance is a {@code jar} {@code scheme}, otherwise false.
+ * @since 2.3.2
+ */
+ public final boolean isJarScheme() {
+ return null != scheme && JAR_SCHEME.equals( scheme.get() );
}
/**
@@ -1386,7 +1394,7 @@ public class Uri {
if( !emptyString(schemeSpecificPart) ) {
final StringBuilder sb = new StringBuilder();
- if( scheme.equals(JAR_SCHEME) ) {
+ if( isJarScheme() ) {
final int idx = schemeSpecificPart.lastIndexOf(JAR_SCHEME_SEPARATOR);
if (0 > idx) {
throw new URISyntaxException(input.get(), "missing jar separator");
diff --git a/src/java/com/jogamp/common/nio/Buffers.java b/src/java/com/jogamp/common/nio/Buffers.java
index aae2be8..fb23627 100644
--- a/src/java/com/jogamp/common/nio/Buffers.java
+++ b/src/java/com/jogamp/common/nio/Buffers.java
@@ -39,6 +39,7 @@
*/
package com.jogamp.common.nio;
+import java.lang.reflect.Method;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -48,9 +49,14 @@ import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.ShortBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import com.jogamp.common.util.ReflectionUtil;
import com.jogamp.common.util.ValueConv;
+import jogamp.common.Debug;
+
/**
* Utility methods allowing easy {@link java.nio.Buffer} manipulations.
*
@@ -60,6 +66,11 @@ import com.jogamp.common.util.ValueConv;
*/
public class Buffers {
+ static final boolean DEBUG;
+ static {
+ DEBUG = Debug.debug("Buffers");
+ }
+
public static final int SIZEOF_BYTE = 1;
public static final int SIZEOF_SHORT = 2;
public static final int SIZEOF_CHAR = 2;
@@ -1150,4 +1161,64 @@ public class Buffers {
return sb;
}
+ /**
+ * Access to NIO {@link sun.misc.Cleaner}, allowing caller to deterministically clean a given {@link sun.nio.ch.DirectBuffer}.
+ */
+ public static class Cleaner {
+ private static final Method mbbCleaner;
+ private static final Method cClean;
+ private static final boolean hasCleaner;
+ /** OK to be lazy on thread synchronization, just for early out **/
+ private static volatile boolean cleanerError;
+ static {
+ final Method[] _mbbCleaner = { null };
+ final Method[] _cClean = { null };
+ if( AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ @Override
+ public Boolean run() {
+ try {
+ _mbbCleaner[0] = ReflectionUtil.getMethod("sun.nio.ch.DirectBuffer", "cleaner", null, Buffers.class.getClassLoader());
+ _mbbCleaner[0].setAccessible(true);
+ _cClean[0] = Class.forName("sun.misc.Cleaner").getMethod("clean");
+ _cClean[0].setAccessible(true);
+ return Boolean.TRUE;
+ } catch(final Throwable t) {
+ if( DEBUG ) {
+ System.err.println("Caught "+t.getMessage());
+ t.printStackTrace();
+ }
+ return Boolean.FALSE;
+ } } } ).booleanValue() ) {
+ mbbCleaner = _mbbCleaner[0];
+ cClean = _cClean[0];
+ hasCleaner = null != mbbCleaner && null != cClean;
+ } else {
+ mbbCleaner = null;
+ cClean = null;
+ hasCleaner = false;
+ }
+ cleanerError = !hasCleaner;
+ }
+ /**
+ * If {@code b} is an direct NIO buffer, i.e {@link sun.nio.ch.DirectBuffer},
+ * calls it's {@link sun.misc.Cleaner} instance {@code clean()} method.
+ * @return {@code true} if successful, otherwise {@code false}.
+ */
+ public static boolean clean(final Buffer b) {
+ if( !hasCleaner || cleanerError || !b.isDirect() ) {
+ return false;
+ }
+ try {
+ cClean.invoke(mbbCleaner.invoke(b));
+ return true;
+ } catch(final Throwable t) {
+ cleanerError = true;
+ if( DEBUG ) {
+ System.err.println("Caught "+t.getMessage());
+ t.printStackTrace();
+ }
+ return false;
+ }
+ }
+ }
}
diff --git a/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java b/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java
index f8d5857..6a56d6e 100644
--- a/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java
+++ b/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java
@@ -33,13 +33,10 @@ import java.io.OutputStream;
import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.lang.ref.WeakReference;
-import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import jogamp.common.Debug;
@@ -163,10 +160,6 @@ public class MappedByteBufferInputStream extends InputStream {
private int refCount;
- private Method mbbCleaner;
- private Method cClean;
- private boolean cleanerInit;
- private boolean hasCleaner;
private CacheMode cmode;
private int sliceIdx;
@@ -191,10 +184,12 @@ public class MappedByteBufferInputStream extends InputStream {
}
}
long fcSz = 0, pos = 0, rem = 0;
- try {
- fcSz = fc.size();
- } catch (final IOException e) {
- e.printStackTrace();
+ if( fc.isOpen() ) {
+ try {
+ fcSz = fc.size();
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
}
if( 0 < refCount ) {
try {
@@ -229,14 +224,16 @@ public class MappedByteBufferInputStream extends InputStream {
notifyLengthChange( totalSize );
this.refCount = 1;
- this.cleanerInit = false;
- this.hasCleaner = false;
this.cmode = cmode;
this.sliceIdx = currSliceIdx;
this.mark = -1;
currentSlice().position(0);
+
+ if( MappedByteBufferInputStream.DEBUG ) {
+ this.dbgDump("CTOR", System.err);
+ }
}
/**
@@ -330,6 +327,9 @@ public class MappedByteBufferInputStream extends InputStream {
}
}
}
+ if( MappedByteBufferInputStream.DEBUG ) {
+ this.dbgDump("Close", System.err);
+ }
}
final FileChannel.MapMode getMapMode() { return mmode; }
@@ -441,10 +441,9 @@ public class MappedByteBufferInputStream extends InputStream {
}
position2( Math.min(prePosition, newTotalSize) ); // -> clipped position (set currSlice and re-map/-pos buffer)
}
- /* if( DEBUG ) {
- System.err.println("notifyLengthChange.X: "+slices[currSlice]);
- dbgDump("notifyLengthChange.X:", System.err);
- } */
+ if( MappedByteBufferInputStream.DEBUG ) {
+ this.dbgDump("NotifyLengthChange", System.err);
+ }
}
/**
@@ -551,6 +550,21 @@ public class MappedByteBufferInputStream extends InputStream {
}
}
+ /**
+ * Releases the mapped {@link ByteBuffer} slices.
+ * @throws IOException if a buffer slice operation failed.
+ */
+ public final synchronized void flushSlices() throws IOException {
+ if( null != slices ) {
+ for(int i=0; i<sliceCount; i++) {
+ flushSlice(i, synchronous);
+ }
+ }
+ if( MappedByteBufferInputStream.DEBUG ) {
+ this.dbgDump("FlushSlices", System.err);
+ }
+ }
+
synchronized void syncSlice(final ByteBuffer s) throws IOException {
syncSlice(s, synchronous);
}
@@ -630,58 +644,16 @@ public class MappedByteBufferInputStream extends InputStream {
}
}
private synchronized boolean cleanBuffer(final ByteBuffer mbb, final boolean syncBuffer) throws IOException {
- if( !cleanerInit ) {
- initCleaner(mbb);
- }
syncSlice(mbb, syncBuffer);
if( !mbb.isDirect() ) {
return false;
}
- boolean res = false;
- if ( hasCleaner ) {
- try {
- cClean.invoke(mbbCleaner.invoke(mbb));
- res = true;
- } catch(final Throwable t) {
- hasCleaner = false;
- if( DEBUG ) {
- System.err.println("Caught "+t.getMessage());
- t.printStackTrace();
- }
- }
- }
- if( !res && CacheMode.FLUSH_PRE_HARD == cmode ) {
+ if( !Buffers.Cleaner.clean(mbb) && CacheMode.FLUSH_PRE_HARD == cmode ) {
cmode = CacheMode.FLUSH_PRE_SOFT;
+ return false;
+ } else {
+ return true;
}
- return res;
- }
- private synchronized void initCleaner(final ByteBuffer bb) {
- final Method[] _mbbCleaner = { null };
- final Method[] _cClean = { null };
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- @Override
- public Object run() {
- try {
- _mbbCleaner[0] = bb.getClass().getMethod("cleaner");
- _mbbCleaner[0].setAccessible(true);
- _cClean[0] = Class.forName("sun.misc.Cleaner").getMethod("clean");
- _cClean[0].setAccessible(true);
- } catch(final Throwable t) {
- if( DEBUG ) {
- System.err.println("Caught "+t.getMessage());
- t.printStackTrace();
- }
- }
- return null;
- } } );
- mbbCleaner = _mbbCleaner[0];
- cClean = _cClean[0];
- final boolean res = null != mbbCleaner && null != cClean;
- if( DEBUG ) {
- System.err.println("initCleaner: Has cleaner: "+res+", mbbCleaner "+mbbCleaner+", cClean "+cClean);
- }
- hasCleaner = res;
- cleanerInit = true;
}
/**
diff --git a/src/java/com/jogamp/common/nio/StructAccessor.java b/src/java/com/jogamp/common/nio/StructAccessor.java
index af7b6d1..8ae0c29 100644
--- a/src/java/com/jogamp/common/nio/StructAccessor.java
+++ b/src/java/com/jogamp/common/nio/StructAccessor.java
@@ -83,6 +83,16 @@ public class StructAccessor {
bb.put(byteOffset, v);
}
+ /** Retrieves the boolean at the specified byteOffset. */
+ public final boolean getBooleanAt(final int byteOffset) {
+ return (byte)0 != bb.get(byteOffset);
+ }
+
+ /** Puts a boolean at the specified byteOffset. */
+ public final void setBooleanAt(final int byteOffset, final boolean v) {
+ bb.put(byteOffset, v?(byte)1:(byte)0);
+ }
+
/** Retrieves the char at the specified byteOffset. */
public final char getCharAt(final int byteOffset) {
return bb.getChar(byteOffset);
@@ -213,6 +223,19 @@ public class StructAccessor {
return v;
}
+ public final void setBooleansAt(int byteOffset, final boolean[] v) {
+ for (int i = 0; i < v.length; i++) {
+ bb.put(byteOffset++, v[i]?(byte)1:(byte)0);
+ }
+ }
+
+ public final boolean[] getBooleansAt(int byteOffset, final boolean[] v) {
+ for (int i = 0; i < v.length; i++) {
+ v[i] = (byte)0 != bb.get(byteOffset++);
+ }
+ return v;
+ }
+
public final void setCharsAt(int byteOffset, final char[] v) {
for (int i = 0; i < v.length; i++, byteOffset+=2) {
bb.putChar(byteOffset, v[i]);
diff --git a/src/java/com/jogamp/common/os/DynamicLibraryBundle.java b/src/java/com/jogamp/common/os/DynamicLibraryBundle.java
index c578565..a3d6198 100644
--- a/src/java/com/jogamp/common/os/DynamicLibraryBundle.java
+++ b/src/java/com/jogamp/common/os/DynamicLibraryBundle.java
@@ -189,7 +189,10 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
* @see DynamicLibraryBundleInfo#getToolLibNames()
*/
public final boolean isToolLibComplete() {
- return toolGetProcAddressComplete && null != dynLinkGlobal && getToolLibNumber() == getToolLibLoadedNumber();
+ final int toolLibNumber = getToolLibNumber();
+ return toolGetProcAddressComplete &&
+ ( 0 == toolLibNumber || null != dynLinkGlobal ) &&
+ toolLibNumber == getToolLibLoadedNumber();
}
public final boolean isToolLibLoaded() {
@@ -246,9 +249,12 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
return aptr;
}
- protected static final NativeLibrary loadFirstAvailable(final List<String> libNames, final ClassLoader loader, final boolean global) throws SecurityException {
+ protected static final NativeLibrary loadFirstAvailable(final List<String> libNames,
+ final boolean searchSystemPath,
+ final boolean searchSystemPathFirst,
+ final ClassLoader loader, final boolean global) throws SecurityException {
for (int i=0; i < libNames.size(); i++) {
- final NativeLibrary lib = NativeLibrary.open(libNames.get(i), loader, global);
+ final NativeLibrary lib = NativeLibrary.open(libNames.get(i), searchSystemPath, searchSystemPathFirst, loader, global);
if (lib != null) {
return lib;
}
@@ -266,7 +272,10 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
for (i=0; i < toolLibNames.size(); i++) {
final List<String> libNames = toolLibNames.get(i);
if( null != libNames && libNames.size() > 0 ) {
- lib = loadFirstAvailable(libNames, cl, info.shallLinkGlobal());
+ lib = loadFirstAvailable(libNames,
+ info.searchToolLibInSystemPath(),
+ info.searchToolLibSystemPathFirst(),
+ cl, info.shallLinkGlobal());
if ( null == lib ) {
if(DEBUG) {
System.err.println("Unable to load any Tool library of: "+libNames);
@@ -358,7 +367,7 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
final long addr = info.toolGetProcAddress(toolGetProcAddressHandle, funcName);
if(DEBUG_LOOKUP) {
if(0!=addr) {
- System.err.println("Lookup-Tool: <"+funcName+"> 0x"+Long.toHexString(addr));
+ System.err.println("Lookup-Tool: <"+funcName+"> 0x"+Long.toHexString(addr)+", via tool 0x"+Long.toHexString(toolGetProcAddressHandle));
}
}
return addr;
diff --git a/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java b/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java
index 7be5f25..01068b4 100644
--- a/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java
+++ b/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java
@@ -37,6 +37,21 @@ public interface DynamicLibraryBundleInfo {
public static final boolean DEBUG = DynamicLibraryBundle.DEBUG;
/**
+ * Returns {@code true} if tool libraries shall be searched in the system path <i>(default)</i>, otherwise {@code false}.
+ * @since 2.4.0
+ */
+ public boolean searchToolLibInSystemPath();
+
+ /**
+ * Returns {@code true} if system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last.
+ * <p>
+ * If {@link #searchToolLibInSystemPath()} is {@code false} the return value is ignored.
+ * </p>
+ * @since 2.4.0
+ */
+ public boolean searchToolLibSystemPathFirst();
+
+ /**
* If a {@link SecurityManager} is installed, user needs link permissions
* for the named libraries.
*
diff --git a/src/java/com/jogamp/common/os/NativeLibrary.java b/src/java/com/jogamp/common/os/NativeLibrary.java
index 747f92d..2ba2581 100644
--- a/src/java/com/jogamp/common/os/NativeLibrary.java
+++ b/src/java/com/jogamp/common/os/NativeLibrary.java
@@ -138,32 +138,47 @@ public final class NativeLibrary implements DynamicLookupHelper {
}
/** Opens the given native library, assuming it has the same base
- name on all platforms, looking first in the system's search
- path, and in the context of the specified ClassLoader, which is
- used to help find the library in the case of e.g. Java Web Start.
- * @throws SecurityException if user is not granted access for the named library.
- */
- public static final NativeLibrary open(final String libName, final ClassLoader loader) throws SecurityException {
- return open(libName, libName, libName, true, loader, true);
- }
-
- /** Opens the given native library, assuming it has the same base
- name on all platforms, looking first in the system's search
- path, and in the context of the specified ClassLoader, which is
- used to help find the library in the case of e.g. Java Web Start.
+ name on all platforms.
+ <p>
+ The {@code searchSystemPath} argument changes the behavior to
+ either use the default system path or not at all.
+ </p>
+ <p>
+ Assuming {@code searchSystemPath} is {@code true},
+ the {@code searchSystemPathFirst} argument changes the behavior to first
+ search the default system path rather than searching it last.
+ </p>
+ * @param libName library name, with or without prefix and suffix
+ * @param searchSystemPath if {@code true} library shall be searched in the system path <i>(default)</i>, otherwise {@code false}.
+ * @param searchSystemPathFirst if {@code true} system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last.
+ * if {@code searchSystemPath} is {@code false} this argument is ignored.
+ * @param loader {@link ClassLoader} to locate the library
+ * @param global if {@code true} allows system wide access of the loaded library, otherwise access is restricted to the process.
+ * @return {@link NativeLibrary} instance or {@code null} if library could not be loaded.
* @throws SecurityException if user is not granted access for the named library.
+ * @since 2.4.0
*/
- public static final NativeLibrary open(final String libName, final ClassLoader loader, final boolean global) throws SecurityException {
- return open(libName, libName, libName, true, loader, global);
+ public static final NativeLibrary open(final String libName,
+ final boolean searchSystemPath,
+ final boolean searchSystemPathFirst,
+ final ClassLoader loader, final boolean global) throws SecurityException {
+ return open(libName, libName, libName, searchSystemPath, searchSystemPathFirst, loader, global);
}
/** Opens the given native library, assuming it has the given base
names (no "lib" prefix or ".dll/.so/.dylib" suffix) on the
Windows, Unix and Mac OS X platforms, respectively, and in the
context of the specified ClassLoader, which is used to help find
- the library in the case of e.g. Java Web Start. The
- searchSystemPathFirst argument changes the behavior to first
+ the library in the case of e.g. Java Web Start.
+ <p>
+ The {@code searchSystemPath} argument changes the behavior to
+ either use the default system path or not at all.
+ </p>
+ <p>
+ Assuming {@code searchSystemPath} is {@code true},
+ the {@code searchSystemPathFirst} argument changes the behavior to first
search the default system path rather than searching it last.
+ </p>
Note that we do not currently handle DSO versioning on Unix.
Experience with JOAL and OpenAL has shown that it is extremely
problematic to rely on a specific .so version (for one thing,
@@ -171,28 +186,27 @@ public final class NativeLibrary implements DynamicLookupHelper {
ending in .so, for example .so.0), and in general if this
dynamic loading facility is used correctly the version number
will be irrelevant.
+ * @param windowsLibName windows library name, with or without prefix and suffix
+ * @param unixLibName unix library name, with or without prefix and suffix
+ * @param macOSXLibName mac-osx library name, with or without prefix and suffix
+ * @param searchSystemPath if {@code true} library shall be searched in the system path <i>(default)</i>, otherwise {@code false}.
+ * @param searchSystemPathFirst if {@code true} system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last.
+ * if {@code searchSystemPath} is {@code false} this argument is ignored.
+ * @param loader {@link ClassLoader} to locate the library
+ * @param global if {@code true} allows system wide access of the loaded library, otherwise access is restricted to the process.
+ * @return {@link NativeLibrary} instance or {@code null} if library could not be loaded.
* @throws SecurityException if user is not granted access for the named library.
*/
public static final NativeLibrary open(final String windowsLibName,
final String unixLibName,
final String macOSXLibName,
- final boolean searchSystemPathFirst,
- final ClassLoader loader) throws SecurityException {
- return open(windowsLibName, unixLibName, macOSXLibName, searchSystemPathFirst, loader, true);
- }
-
- /**
- * @throws SecurityException if user is not granted access for the named library.
- */
- public static final NativeLibrary open(final String windowsLibName,
- final String unixLibName,
- final String macOSXLibName,
+ final boolean searchSystemPath,
final boolean searchSystemPathFirst,
final ClassLoader loader, final boolean global) throws SecurityException {
final List<String> possiblePaths = enumerateLibraryPaths(windowsLibName,
unixLibName,
macOSXLibName,
- searchSystemPathFirst,
+ searchSystemPath, searchSystemPathFirst,
loader);
Platform.initSingleton(); // loads native gluegen-rt library
@@ -367,12 +381,33 @@ public final class NativeLibrary implements DynamicLookupHelper {
/** Given the base library names (no prefixes/suffixes) for the
various platforms, enumerate the possible locations and names of
- the indicated native library on the system. */
+ the indicated native library on the system not using the system path. */
+ public static final List<String> enumerateLibraryPaths(final String windowsLibName,
+ final String unixLibName,
+ final String macOSXLibName,
+ final ClassLoader loader) {
+ return enumerateLibraryPaths(windowsLibName, unixLibName, macOSXLibName,
+ false /* searchSystemPath */, false /* searchSystemPathFirst */,
+ loader);
+ }
+ /** Given the base library names (no prefixes/suffixes) for the
+ various platforms, enumerate the possible locations and names of
+ the indicated native library on the system using the system path. */
public static final List<String> enumerateLibraryPaths(final String windowsLibName,
final String unixLibName,
final String macOSXLibName,
final boolean searchSystemPathFirst,
final ClassLoader loader) {
+ return enumerateLibraryPaths(windowsLibName, unixLibName, macOSXLibName,
+ true /* searchSystemPath */, searchSystemPathFirst,
+ loader);
+ }
+ private static final List<String> enumerateLibraryPaths(final String windowsLibName,
+ final String unixLibName,
+ final String macOSXLibName,
+ final boolean searchSystemPath,
+ final boolean searchSystemPathFirst,
+ final ClassLoader loader) {
final List<String> paths = new ArrayList<String>();
final String libName = selectName(windowsLibName, unixLibName, macOSXLibName);
if (libName == null) {
@@ -388,11 +423,18 @@ public final class NativeLibrary implements DynamicLookupHelper {
final String[] baseNames = buildNames(libName);
- if (searchSystemPathFirst) {
- // Add just the library names to use the OS's search algorithm
- for (int i = 0; i < baseNames.length; i++) {
- paths.add(baseNames[i]);
- }
+ if( searchSystemPath && searchSystemPathFirst ) {
+ // Add just the library names to use the OS's search algorithm
+ for (int i = 0; i < baseNames.length; i++) {
+ paths.add(baseNames[i]);
+ }
+ // Add probable Mac OS X-specific paths
+ if ( isOSX ) {
+ // Add historical location
+ addPaths("/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
+ // Add current location
+ addPaths("/System/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
+ }
}
// The idea to ask the ClassLoader to find the library is borrowed
@@ -412,24 +454,25 @@ public final class NativeLibrary implements DynamicLookupHelper {
if(null != usrPath) {
count++;
}
- final String sysPath = System.getProperty("sun.boot.library.path");
- if(null != sysPath) {
- count++;
+ final String sysPath;
+ if( searchSystemPath ) {
+ sysPath = System.getProperty("sun.boot.library.path");
+ if(null != sysPath) {
+ count++;
+ }
+ } else {
+ sysPath = null;
}
final String[] res = new String[count];
int i=0;
- if (searchSystemPathFirst) {
- if(null != sysPath) {
- res[i++] = sysPath;
- }
+ if( null != sysPath && searchSystemPathFirst ) {
+ res[i++] = sysPath;
}
if(null != usrPath) {
res[i++] = usrPath;
}
- if (!searchSystemPathFirst) {
- if(null != sysPath) {
- res[i++] = sysPath;
- }
+ if( null != sysPath && !searchSystemPathFirst ) {
+ res[i++] = sysPath;
}
return res;
}
@@ -453,19 +496,22 @@ public final class NativeLibrary implements DynamicLookupHelper {
});
addPaths(userDir, baseNames, paths);
- if (!searchSystemPathFirst) {
- // Add just the library names to use the OS's search algorithm
- for (int i = 0; i < baseNames.length; i++) {
- paths.add(baseNames[i]);
- }
- }
+ // Add current working directory + natives/os-arch/ + library names
+ // to handle Bug 1145 cc1 using an unpacked fat-jar
+ addPaths(userDir+File.separator+"natives"+File.separator+PlatformPropsImpl.os_and_arch+File.separator, baseNames, paths);
- // Add probable Mac OS X-specific paths
- if ( isOSX ) {
- // Add historical location
- addPaths("/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
- // Add current location
- addPaths("/System/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
+ if( searchSystemPath && !searchSystemPathFirst ) {
+ // Add just the library names to use the OS's search algorithm
+ for (int i = 0; i < baseNames.length; i++) {
+ paths.add(baseNames[i]);
+ }
+ // Add probable Mac OS X-specific paths
+ if ( isOSX ) {
+ // Add historical location
+ addPaths("/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
+ // Add current location
+ addPaths("/System/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
+ }
}
return paths;
diff --git a/src/java/com/jogamp/common/util/ArrayHashMap.java b/src/java/com/jogamp/common/util/ArrayHashMap.java
new file mode 100644
index 0000000..35a484b
--- /dev/null
+++ b/src/java/com/jogamp/common/util/ArrayHashMap.java
@@ -0,0 +1,305 @@
+/**
+ * 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.common.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * {@link HashMap} implementation backed by an {@link ArrayList} to preserve order of values.
+ *
+ * Implementation properties are:
+ * <ul>
+ * <li> Unique elements utilizing {@link java.lang.Object#hashCode()} for O(1) operations, see below.</li>
+ * <li> Java 1.5 compatible</li>
+ * </ul>
+ *
+ * O(1) operations:
+ * <ul>
+ * <li> put new key-value-pair(s) </li>
+ * <li> test for containment </li>
+ * <li> trying to remove non existent elements </li>
+ * </ul>
+ *
+ * O(n) operations:
+ * <ul>
+ * <li> put existing key-value-pair(s) </li>
+ * <li> removing existing elements</li>
+ * </ul>
+ *
+ * For thread safety, the application shall decorate access to instances via
+ * {@link com.jogamp.common.util.locks.RecursiveLock}.
+ *
+*/
+public class ArrayHashMap<K, V>
+ implements Cloneable, Map<K, V>
+{
+ /**
+ * Default load factor: {@value}
+ */
+ public static final float DEFAULT_LOAD_FACTOR = 0.75f;
+ /**
+ * The default initial capacity: {@value}
+ */
+ public static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+ private final HashMap<K,V> map; // key -> object
+ private final ArrayList<V> data; // list of objects
+ private final boolean supportNullValue;
+
+ /**
+ *
+ * @param supportNullValue Use {@code true} for default behavior, i.e. {@code null} can be a valid value.
+ * Use {@code false} if {@code null} is not a valid value,
+ * here {@link #put(Object, Object)} and {@link #remove(Object)} will be optimized.
+ * @param initialCapacity use {@link #DEFAULT_INITIAL_CAPACITY} for default
+ * @param loadFactor use {@link #DEFAULT_LOAD_FACTOR} for default
+ * @see #supportsNullValue()
+ */
+ public ArrayHashMap(final boolean supportNullValue, final int initialCapacity, final float loadFactor) {
+ this.map = new HashMap<K,V>(initialCapacity, loadFactor);
+ this.data = new ArrayList<V>(initialCapacity);
+ this.supportNullValue = supportNullValue;
+ }
+
+ /**
+ * @return a shallow copy of this ArrayHashMap, elements are not copied.
+ */
+ public ArrayHashMap(final ArrayHashMap<K, V> o) {
+ map = new HashMap<K, V>(o.map);
+ data = new ArrayList<V>(o.data);
+ supportNullValue = o.supportNullValue;
+ }
+
+ /**
+ * Returns {@code true} for default behavior, i.e. {@code null} can be a valid value.
+ * <p>
+ * Returns {@code false} if {@code null} is not a valid value,
+ * here {@link #put(Object, Object)} and {@link #remove(Object)} are optimized operations.
+ * </p>
+ * @see #ArrayHashMap(boolean, int, float)
+ */
+ public final boolean supportsNullValue() { return supportNullValue; }
+
+ //
+ // Cloneable
+ //
+
+ /**
+ * Implementation uses {@link #ArrayHashMap(ArrayHashMap)}.
+ * @return a shallow copy of this ArrayHashMap, elements are not copied.
+ */
+ @Override
+ public final Object clone() {
+ return new ArrayHashMap<K, V>(this);
+ }
+
+ /**
+ * Returns this object ordered ArrayList. Use w/ care, it's not a copy.
+ * @see #toArrayList()
+ */
+ public final ArrayList<V> getData() { return data; }
+
+ /**
+ * @return a shallow copy of this ArrayHashMap's ArrayList, elements are not copied.
+ * @see #getData()
+ */
+ public final ArrayList<V> toArrayList() {
+ return new ArrayList<V>(data);
+ }
+
+ /** Returns this object hash map. Use w/ care, it's not a copy. */
+ public final HashMap<K,V> getMap() { return map; }
+
+ @Override
+ public final String toString() { return data.toString(); }
+
+ //
+ // Map
+ //
+
+ @Override
+ public final void clear() {
+ data.clear();
+ map.clear();
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return map.keySet();
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * See {@link #getData()} and {@link #toArrayList()}.
+ * </p>
+ * @see #getData()
+ * @see #toArrayList()
+ */
+ @Override
+ public Collection<V> values() {
+ return map.values();
+ }
+
+ @Override
+ public Set<java.util.Map.Entry<K, V>> entrySet() {
+ return map.entrySet();
+ }
+
+ @Override
+ public final V get(final Object key) {
+ return map.get(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This is an O(1) operation, in case the key does not exist,
+ * otherwise O(n).
+ * </p>
+ * @throws NullPointerException if {@code value} is {@code null} but {@link #supportsNullValue()} == {@code false}
+ */
+ @Override
+ public final V put(final K key, final V value) throws NullPointerException {
+ final V oldValue;
+ if( supportNullValue ) {
+ // slow path
+ final boolean exists = map.containsKey(key);
+ if(!exists) {
+ // !exists
+ if( null != ( oldValue = map.put(key, value) ) ) {
+ // slips a valid null ..
+ throw new InternalError("Already existing, but checked before: "+key+" -> "+oldValue);
+ }
+ } else {
+ // exists
+ oldValue = map.put(key, value);
+ if( !data.remove(oldValue) ) {
+ throw new InternalError("Already existing, but not in list: "+oldValue);
+ }
+ }
+ } else {
+ checkNullValue(value);
+ // fast path
+ if( null != ( oldValue = map.put(key, value) ) ) {
+ // exists
+ if( !data.remove(oldValue) ) {
+ throw new InternalError("Already existing, but not in list: "+oldValue);
+ }
+ }
+ }
+ if(!data.add(value)) {
+ throw new InternalError("Couldn't add value to list: "+value);
+ }
+ return oldValue;
+ }
+
+ @Override
+ public void putAll(final Map<? extends K, ? extends V> m) {
+ for (final Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
+ final Map.Entry<? extends K, ? extends V> e = i.next();
+ put(e.getKey(), e.getValue());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This is an O(1) operation, in case the key does not exist,
+ * otherwise O(n).
+ * </p>
+ */
+ @Override
+ public final V remove(final Object key) {
+ if( supportNullValue ) {
+ if( map.containsKey(key) ) {
+ // exists
+ final V oldValue = map.remove(key);
+ if ( !data.remove(oldValue) ) {
+ throw new InternalError("Couldn't remove prev mapped pair: "+key+" -> "+oldValue);
+ }
+ return oldValue;
+ }
+ } else {
+ final V oldValue;
+ if ( null != (oldValue = map.remove(key) ) ) {
+ // exists
+ if ( !data.remove(oldValue) ) {
+ throw new InternalError("Couldn't remove prev mapped pair: "+key+" -> "+oldValue);
+ }
+ }
+ return oldValue;
+ }
+ return null;
+ }
+
+ @Override
+ public final boolean containsKey(final Object key) {
+ return map.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(final Object value) {
+ return map.containsValue(value);
+ }
+
+ @Override
+ public final boolean equals(final Object arrayHashMap) {
+ if ( !(arrayHashMap instanceof ArrayHashMap) ) {
+ return false;
+ }
+ return map.equals(((ArrayHashMap<?,?>)arrayHashMap).map);
+ }
+
+ @Override
+ public final int hashCode() {
+ return map.hashCode();
+ }
+
+ @Override
+ public final boolean isEmpty() {
+ return data.isEmpty();
+ }
+
+ @Override
+ public final int size() {
+ return data.size();
+ }
+
+ private static final void checkNullValue(final Object value) throws NullPointerException {
+ if( null == value ) {
+ throw new NullPointerException("Null value not supported");
+ }
+ }
+}
diff --git a/src/java/com/jogamp/common/util/ArrayHashSet.java b/src/java/com/jogamp/common/util/ArrayHashSet.java
index 34e84c4..c0ac2fa 100644
--- a/src/java/com/jogamp/common/util/ArrayHashSet.java
+++ b/src/java/com/jogamp/common/util/ArrayHashSet.java
@@ -68,23 +68,52 @@ import java.util.ListIterator;
public class ArrayHashSet<E>
implements Cloneable, Collection<E>, List<E>
{
+ /**
+ * Default load factor: {@value}
+ */
+ public static final float DEFAULT_LOAD_FACTOR = 0.75f;
+ /**
+ * The default initial capacity: {@value}
+ */
+ public static final int DEFAULT_INITIAL_CAPACITY = 16;
+
private final HashMap<E,E> map; // object -> object
private final ArrayList<E> data; // list of objects
+ private final boolean supportNullValue;
- public ArrayHashSet() {
- map = new HashMap<E,E>();
- data = new ArrayList<E>();
+ /**
+ *
+ * @param supportNullValue Use {@code true} for default behavior, i.e. {@code null} can be a valid value.
+ * Use {@code false} if {@code null} is not a valid value,
+ * here {@link #remove(E)} and {@link #getOrAdd(Object)} will be optimized.
+ * @param initialCapacity use {@link #DEFAULT_INITIAL_CAPACITY} for default
+ * @param loadFactor use {@link #DEFAULT_LOAD_FACTOR} for default
+ * @see #supportsNullValue()
+ */
+ public ArrayHashSet(final boolean supportNullValue, final int initialCapacity, final float loadFactor) {
+ this.map = new HashMap<E,E>(initialCapacity, loadFactor);
+ this.data = new ArrayList<E>(initialCapacity);
+ this.supportNullValue = supportNullValue;
}
- public ArrayHashSet(final int initialCapacity) {
- map = new HashMap<E,E>(initialCapacity);
- data = new ArrayList<E>(initialCapacity);
+ /**
+ * @return a shallow copy of this ArrayHashSet, elements are not copied.
+ */
+ public ArrayHashSet(final ArrayHashSet<E> o) {
+ map = new HashMap<E, E>(o.map);
+ data = new ArrayList<E>(o.data);
+ supportNullValue = o.supportNullValue;
}
- public ArrayHashSet(final int initialCapacity, final float loadFactor) {
- map = new HashMap<E,E>(initialCapacity, loadFactor);
- data = new ArrayList<E>(initialCapacity);
- }
+ /**
+ * Returns {@code true} for default behavior, i.e. {@code null} can be a valid value.
+ * <p>
+ * Returns {@code false} if {@code null} is not a valid value,
+ * here {@link #remove(E)} and {@link #getOrAdd(Object)} are optimized operations.
+ * </p>
+ * @see #ArrayHashSet(boolean, int, float)
+ */
+ public final boolean supportsNullValue() { return supportNullValue; }
//
// Cloneable
@@ -95,12 +124,7 @@ public class ArrayHashSet<E>
*/
@Override
public final Object clone() {
- final ArrayList<E> clonedList = new ArrayList<E>(data);
-
- final ArrayHashSet<E> newObj = new ArrayHashSet<E>();
- newObj.addAll(clonedList);
-
- return newObj;
+ return new ArrayHashSet<E>(this);
}
/** Returns this object ordered ArrayList. Use w/ care, it's not a copy. */
@@ -125,40 +149,66 @@ public class ArrayHashSet<E>
* Add element at the end of this list, if it is not contained yet.
* <br>
* This is an O(1) operation
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return true if the element was added to this list,
* otherwise false (already contained).
+ * @throws NullPointerException if {@code element} is {@code null} but {@link #supportsNullValue()} == {@code false}
*/
@Override
- public final boolean add(final E element) {
- final boolean exists = map.containsKey(element);
- if(!exists) {
+ public final boolean add(final E element) throws NullPointerException {
+ if( !supportNullValue ) {
+ checkNull(element);
+ }
+ if( !map.containsKey(element) ) {
+ // !exists
if(null != map.put(element, element)) {
+ // slips a valid null ..
throw new InternalError("Already existing, but checked before: "+element);
}
if(!data.add(element)) {
throw new InternalError("Couldn't add element: "+element);
}
+ return true;
}
- return !exists;
+ return false;
}
/**
* Remove element from this list.
* <br>
- * This is an O(1) operation, in case it does not exist,
+ * This is an O(1) operation, in case the element does not exist,
* otherwise O(n).
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return true if the element was removed from this list,
* otherwise false (not contained).
+ * @throws NullPointerException if {@code element} is {@code null} but {@link #supportsNullValue()} == {@code false}
*/
@Override
- public final boolean remove(final Object element) {
- if ( null != map.remove(element) ) {
- if ( ! data.remove(element) ) {
- throw new InternalError("Couldn't remove prev mapped element: "+element);
+ public final boolean remove(final Object element) throws NullPointerException {
+ if( supportNullValue ) {
+ if( map.containsKey(element) ) {
+ // exists
+ map.remove(element);
+ if ( !data.remove(element) ) {
+ throw new InternalError("Couldn't remove prev mapped element: "+element);
+ }
+ return true;
+ }
+ } else {
+ checkNull(element);
+ if ( null != map.remove(element) ) {
+ // exists
+ if ( !data.remove(element) ) {
+ throw new InternalError("Couldn't remove prev mapped element: "+element);
+ }
+ return true;
}
- return true;
}
return false;
}
@@ -167,6 +217,9 @@ public class ArrayHashSet<E>
* Add all elements of given {@link java.util.Collection} at the end of this list.
* <br>
* This is an O(n) operation, over the given Collection size.
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return true if at least one element was added to this list,
* otherwise false (completely container).
@@ -184,6 +237,9 @@ public class ArrayHashSet<E>
* Test for containment
* <br>
* This is an O(1) operation.
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return true if the given element is contained by this list using fast hash map,
* otherwise false.
@@ -197,6 +253,9 @@ public class ArrayHashSet<E>
* Test for containment of given {@link java.util.Collection}
* <br>
* This is an O(n) operation, over the given Collection size.
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return true if the given Collection is completly contained by this list using hash map,
* otherwise false.
@@ -215,6 +274,9 @@ public class ArrayHashSet<E>
* Remove all elements of given {@link java.util.Collection} from this list.
* <br>
* This is an O(n) operation.
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return true if at least one element of this list was removed,
* otherwise false.
@@ -233,6 +295,9 @@ public class ArrayHashSet<E>
* remove all elements not contained by the given {@link java.util.Collection} c.
* <br>
* This is an O(n) operation.
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return true if at least one element of this list was removed,
* otherwise false.
@@ -250,6 +315,9 @@ public class ArrayHashSet<E>
/**
* This is an O(n) operation.
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return true if arrayHashSet is of type ArrayHashSet and all entries are equal
* Performance: arrayHashSet(1)
@@ -264,6 +332,9 @@ public class ArrayHashSet<E>
/**
* This is an O(n) operation over the size of this list.
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return the hash code of this list as define in {@link java.util.List#hashCode()},
* ie hashing all elements of this list.
@@ -316,30 +387,44 @@ public class ArrayHashSet<E>
* Add element at the given index in this list, if it is not contained yet.
* <br>
* This is an O(1) operation
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @throws IllegalArgumentException if the given element was already contained
+ * @throws NullPointerException if {@code element} is {@code null} but {@link #supportsNullValue()} == {@code false}
*/
@Override
- public final void add(final int index, final E element) {
+ public final void add(final int index, final E element) throws IllegalArgumentException, NullPointerException {
+ if( !supportNullValue ) {
+ checkNull(element);
+ }
if ( map.containsKey(element) ) {
throw new IllegalArgumentException("Element "+element+" is already contained");
}
if(null != map.put(element, element)) {
+ // slips a valid null ..
throw new InternalError("Already existing, but checked before: "+element);
}
+ // !exists
data.add(index, element);
}
/**
+ * <p>
+ * {@inheritDoc}
+ * </p>
* @throws UnsupportedOperationException
*/
@Override
- public final boolean addAll(final int index, final Collection<? extends E> c) {
+ public final boolean addAll(final int index, final Collection<? extends E> c) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
- * @throws UnsupportedOperationException
+ * <p>
+ * {@inheritDoc}
+ * </p>
*/
@Override
public final E set(final int index, final E element) {
@@ -354,6 +439,9 @@ public class ArrayHashSet<E>
* Remove element at given index from this list.
* <br>
* This is an O(n) operation.
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return the removed object
*/
@@ -370,6 +458,9 @@ public class ArrayHashSet<E>
* Since this list is unique, equivalent to {@link #indexOf(java.lang.Object)}.
* <br>
* This is an O(n) operation.
+ * <p>
+ * {@inheritDoc}
+ * </p>
*
* @return index of element, or -1 if not found
*/
@@ -409,34 +500,44 @@ public class ArrayHashSet<E>
* <br>
* This is an O(1) operation.
*
- * @param key hash source to find the identical Object within this list
+ * @param element hash source to find the identical Object within this list
* @return object from this list, identical to the given <code>key</code> hash code,
* or null if not contained
*/
- public final E get(final Object key) {
- return map.get(key);
+ public final E get(final Object element) {
+ return map.get(element);
}
/**
* Identity method allowing to get the identical object, using the internal hash map.<br>
- * If the <code>key</code> is not yet contained, add it.
+ * If the <code>element</code> is not yet contained, add it.
* <br>
* This is an O(1) operation.
*
- * @param key hash source to find the identical Object within this list
+ * @param element hash source to find the identical Object within this list
* @return object from this list, identical to the given <code>key</code> hash code,
* or add the given <code>key</code> and return it.
+ * @throws NullPointerException if {@code element} is {@code null} but {@link #supportsNullValue()} == {@code false}
*/
- public final E getOrAdd(final E key) {
- final E identity = get(key);
- if(null == identity) {
- // object not contained yet, add it
- if(!this.add(key)) {
- throw new InternalError("Key not mapped, but contained in list: "+key);
+ public final E getOrAdd(final E element) throws NullPointerException {
+ if( supportNullValue ) {
+ if( map.containsKey(element) ) {
+ // existent
+ return map.get(element);
+ }
+ } else {
+ checkNull(element);
+ final E identity = map.get(element);
+ if(null != identity) {
+ // existent
+ return identity;
}
- return key;
}
- return identity;
+ // !existent
+ if(!this.add(element)) {
+ throw new InternalError("Element not mapped, but contained in list: "+element);
+ }
+ return element;
}
/**
@@ -455,4 +556,9 @@ public class ArrayHashSet<E>
return data.contains(element);
}
+ private static final void checkNull(final Object element) throws NullPointerException {
+ if( null == element ) {
+ throw new NullPointerException("Null element not supported");
+ }
+ }
}
diff --git a/src/java/com/jogamp/common/util/Bitfield.java b/src/java/com/jogamp/common/util/Bitfield.java
new file mode 100644
index 0000000..4b2b9d5
--- /dev/null
+++ b/src/java/com/jogamp/common/util/Bitfield.java
@@ -0,0 +1,208 @@
+/**
+ * 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.common.util;
+
+import jogamp.common.util.SyncedBitfield;
+
+/**
+ * Simple bitfield interface for efficient bit storage access in O(1).
+ * @since 2.3.2
+ */
+public interface Bitfield {
+ /** Maximum 32 bit Unsigned Integer Value: {@code 0xffffffff} == {@value}. */
+ public static final int UNSIGNED_INT_MAX_VALUE = 0xffffffff;
+
+ /**
+ * Bit operation utilities (static).
+ */
+ public static class Util {
+ /**
+ * Returns the 32 bit mask of n-bits, i.e. n low order 1’s.
+ * <p>
+ * Implementation handles n == 32.
+ * </p>
+ * @throws IndexOutOfBoundsException if {@code b} is out of bounds, i.e. &gt; 32
+ */
+ public static int getBitMask(final int n) {
+ if( 32 > n ) {
+ return ( 1 << n ) - 1;
+ } else if ( 32 == n ) {
+ return UNSIGNED_INT_MAX_VALUE;
+ } else {
+ throw new IndexOutOfBoundsException("n <= 32 expected, is "+n);
+ }
+ }
+
+ /**
+ * Returns the number of set bits within given 32bit integer in O(1)
+ * using a <i>HAKEM 169 Bit Count</i> inspired implementation:
+ * <pre>
+ * http://www.inwap.com/pdp10/hbaker/hakmem/hakmem.html
+ * http://home.pipeline.com/~hbaker1/hakmem/hacks.html#item169
+ * http://tekpool.wordpress.com/category/bit-count/
+ * http://www.hackersdelight.org/
+ * </pre>
+ */
+ public static final int bitCount(int n) {
+ // Note: Original used 'unsigned int',
+ // hence we use the unsigned right-shift '>>>'
+ /**
+ * Original does not work due to lack of 'unsigned' right-shift and modulo,
+ * we need 2-complementary solution, i.e. 'signed'.
+ int c = n;
+ c -= (n >>> 1) & 033333333333;
+ c -= (n >>> 2) & 011111111111;
+ return ( (c + ( c >>> 3 ) ) & 030707070707 ) & 0x3f; // % 63
+ */
+ // Hackers Delight, Figure 5-2, pop1 of pop.c.txt
+ n = n - ((n >>> 1) & 0x55555555);
+ n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
+ n = (n + (n >>> 4)) & 0x0f0f0f0f;
+ n = n + (n >>> 8);
+ n = n + (n >>> 16);
+ return n & 0x3f;
+ }
+ }
+ /**
+ * Simple {@link Bitfield} factory for returning the efficient implementation.
+ */
+ public static class Factory {
+ /**
+ * Creates am efficient {@link Bitfield} instance based on the requested {@code storageBitSize}.
+ * <p>
+ * Implementation returns a plain 32 bit integer field implementation for
+ * {@code storageBitSize} &le; 32 bits or an 32 bit integer array implementation otherwise.
+ * </p>
+ */
+ public static Bitfield create(final int storageBitSize) {
+ if( 32 >= storageBitSize ) {
+ return new jogamp.common.util.Int32Bitfield();
+ } else {
+ return new jogamp.common.util.Int32ArrayBitfield(storageBitSize);
+ }
+ }
+ /**
+ * Creates a synchronized {@link Bitfield} by wrapping the given {@link Bitfield} instance.
+ */
+ public static Bitfield synchronize(final Bitfield impl) {
+ return new SyncedBitfield(impl);
+ }
+ }
+ /**
+ * Returns the storage size in bit units, e.g. 32 bit for implementations using one {@code int} field.
+ */
+ int size();
+
+
+ /**
+ * Set all bits of this bitfield to the given value {@code bit}.
+ */
+ void clearField(final boolean bit);
+
+ /**
+ * Returns {@code length} bits from this storage,
+ * starting with the lowest bit from the storage position {@code lowBitnum}.
+ * @param lowBitnum storage bit position of the lowest bit, restricted to [0..{@link #size()}-{@code length}].
+ * @param length number of bits to read, constrained to [0..32].
+ * @throws IndexOutOfBoundsException if {@code rightBitnum} is out of bounds
+ * @see #put32(int, int, int)
+ */
+ int get32(final int lowBitnum, final int length) throws IndexOutOfBoundsException;
+
+ /**
+ * Puts {@code length} bits of given {@code data} into this storage,
+ * starting w/ the lowest bit to the storage position {@code lowBitnum}.
+ * @param lowBitnum storage bit position of the lowest bit, restricted to [0..{@link #size()}-{@code length}].
+ * @param length number of bits to write, constrained to [0..32].
+ * @param data the actual bits to be put into this storage
+ * @throws IndexOutOfBoundsException if {@code rightBitnum} is out of bounds
+ * @see #get32(int, int)
+ */
+ void put32(final int lowBitnum, final int length, final int data) throws IndexOutOfBoundsException;
+
+ /**
+ * Copies {@code length} bits at position {@code srcLowBitnum} to position {@code dstLowBitnum}
+ * and returning the bits.
+ * <p>
+ * Implementation shall operate as if invoking {@link #get32(int, int)}
+ * and then {@link #put32(int, int, int)} sequentially.
+ * </p>
+ * @param srcLowBitnum source bit number, restricted to [0..{@link #size()}-1].
+ * @param dstLowBitnum destination bit number, restricted to [0..{@link #size()}-1].
+ * @throws IndexOutOfBoundsException if {@code bitnum} is out of bounds
+ * @see #get32(int, int)
+ * @see #put32(int, int, int)
+ */
+ int copy32(final int srcLowBitnum, final int dstLowBitnum, final int length) throws IndexOutOfBoundsException;
+
+ /**
+ * Return <code>true</code> if the bit at position <code>bitnum</code> is set, otherwise <code>false</code>.
+ * @param bitnum bit number, restricted to [0..{@link #size()}-1].
+ * @throws IndexOutOfBoundsException if {@code bitnum} is out of bounds
+ */
+ boolean get(final int bitnum) throws IndexOutOfBoundsException;
+
+ /**
+ * Set or clear the bit at position <code>bitnum</code> according to <code>bit</code>
+ * and return the previous value.
+ * @param bitnum bit number, restricted to [0..{@link #size()}-1].
+ * @throws IndexOutOfBoundsException if {@code bitnum} is out of bounds
+ */
+ boolean put(final int bitnum, final boolean bit) throws IndexOutOfBoundsException;
+
+ /**
+ * Set the bit at position <code>bitnum</code> according to <code>bit</code>.
+ * @param bitnum bit number, restricted to [0..{@link #size()}-1].
+ * @throws IndexOutOfBoundsException if {@code bitnum} is out of bounds
+ */
+ void set(final int bitnum) throws IndexOutOfBoundsException;
+
+ /**
+ * Clear the bit at position <code>bitnum</code> according to <code>bit</code>.
+ * @param bitnum bit number, restricted to [0..{@link #size()}-1].
+ * @throws IndexOutOfBoundsException if {@code bitnum} is out of bounds
+ */
+ void clear(final int bitnum) throws IndexOutOfBoundsException;
+
+ /**
+ * Copies the bit at position {@code srcBitnum} to position {@code dstBitnum}
+ * and returning <code>true</code> if the bit is set, otherwise <code>false</code>.
+ * @param srcBitnum source bit number, restricted to [0..{@link #size()}-1].
+ * @param dstBitnum destination bit number, restricted to [0..{@link #size()}-1].
+ * @throws IndexOutOfBoundsException if {@code bitnum} is out of bounds
+ */
+ boolean copy(final int srcBitnum, final int dstBitnum) throws IndexOutOfBoundsException;
+
+ /**
+ * Returns the number of one bits within this bitfield.
+ * <p>
+ * Utilizes {#link {@link Bitfield.Util#bitCount(int)}}.
+ * </p>
+ */
+ int bitCount();
+}
diff --git a/src/java/com/jogamp/common/util/CustomCompress.java b/src/java/com/jogamp/common/util/CustomCompress.java
new file mode 100644
index 0000000..6bca095
--- /dev/null
+++ b/src/java/com/jogamp/common/util/CustomCompress.java
@@ -0,0 +1,167 @@
+/**
+ * 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.common.util;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+/**
+ * All in memory inflater / deflator for small chunks using streams
+ * <p>
+ * Stream header of deflated data:
+ * <ul>
+ * <li>4 bytes magic 0xDEF1A7E0 (Big Endian)</li>
+ * <li>4 bytes integer deflated-size (Big Endian)</li>
+ * <li>4 bytes integer inflated-size (Big Endian)</li>
+ * <li>deflated bytes</li>
+ * </ul>
+ * </p>
+ */
+public class CustomCompress {
+ /** Start of stream header for deflated data */
+ public static final int MAGIC = 0xDEF1A7E0;
+
+ /**
+ *
+ * @param in {@link InputStream} at start of stream header, i.e. position {@link #MAGIC}.
+ * @return the inflated bytes from the stream
+ * @throws IOException if an I/O or deflation exception occurs
+ * @throws IllegalArgumentException if {@code inLen} &le; 0 or {@code outLen} &le; 0, as read from header
+ */
+ public static byte[] inflateFromStream(final InputStream in)
+ throws IOException, ArrayIndexOutOfBoundsException, IllegalArgumentException
+ {
+ final int inLen;
+ final int outLen;
+ {
+ final DataInputStream din = new DataInputStream(in);
+ final int _magic = din.readInt();
+ if( _magic != MAGIC ) {
+ throw new IOException("wrong magic: "+Integer.toHexString(_magic)+", expected "+Integer.toHexString(MAGIC));
+ }
+ inLen = din.readInt();
+ outLen = din.readInt();
+ }
+ return inflateFromStream(in, inLen, outLen, new byte[outLen], 0);
+ }
+
+ /**
+ *
+ * @param in {@link InputStream} at start of deflated bytes, i.e. after the stream header.
+ * @param inLen number of deflated bytes in stream {@code in}
+ * @param outLen number of inflated {@code output} bytes at {@code outOff}
+ * @param output sink for deflated bytes
+ * @param outOff offset to {@code output}
+ * @return the inflated bytes from the stream, passing {@code output} for chaining
+ * @throws IOException if an I/O or deflation exception occurs
+ * @throws ArrayIndexOutOfBoundsException if {@code outOff} and {@code outLen} exceeds {@code output}
+ * @throws IllegalArgumentException if {@code inLen} &le; 0 or {@code outLen} &le; 0
+ */
+ public static byte[] inflateFromStream(final InputStream in, final int inLen, final int outLen,
+ final byte[] output, final int outOff)
+ throws IOException, ArrayIndexOutOfBoundsException, IllegalArgumentException
+ {
+ if (inLen <= 0 || outLen <= 0 ) {
+ throw new IllegalArgumentException("Length[input "+inLen+", output "+outLen+"]");
+ }
+ if (outOff < 0 || output.length < outOff + outLen) {
+ throw new ArrayIndexOutOfBoundsException("output.length "+output.length+", offset "+outOff+", length "+outLen);
+ }
+ final byte[] input = new byte[inLen];
+ int numBytes = 0;
+ try {
+ while (true) {
+ final int remBytes = inLen - numBytes;
+ int count;
+ if ( 0 >= remBytes || (count = in.read(input, numBytes, remBytes)) == -1 ) {
+ break;
+ }
+ numBytes += count;
+ }
+ } finally {
+ in.close();
+ }
+ if( inLen != numBytes ) {
+ throw new IOException("Got "+numBytes+" bytes != expected "+inLen);
+ }
+ try {
+ final Inflater inflater = new Inflater();
+ inflater.setInput(input, 0, inLen);
+ final int outSize = inflater.inflate(output, outOff, outLen);
+ inflater.end();
+ if( outLen != outSize ) {
+ throw new IOException("Got inflated "+outSize+" bytes != expected "+outLen);
+ }
+ } catch(final DataFormatException dfe) {
+ throw new IOException(dfe);
+ }
+ return output;
+ }
+
+ /**
+ * @param input raw input bytes
+ * @param inOff offset to {@code input}
+ * @param inLen number of {@code input} bytes at {@code inOff}
+ * @param level compression level 0-9 or {@link Deflater#DEFAULT_COMPRESSION}
+ * @param out sink for deflated bytes
+ * @return number of deflated bytes written, not including the header.
+ * @throws IOException if an I/O or deflation exception occurs
+ * @throws ArrayIndexOutOfBoundsException if {@code inOff} and {@code inLen} exceeds {@code input}
+ * @throws IllegalArgumentException if {@code inLen} &le; 0
+ */
+ public static int deflateToStream(final byte[] input, final int inOff, final int inLen,
+ final int level, final OutputStream out) throws IOException, ArrayIndexOutOfBoundsException, IllegalArgumentException {
+ if (inLen <= 0 ) {
+ throw new IllegalArgumentException("Length[input "+inLen+"]");
+ }
+ if (inOff < 0 || input.length < inOff + inLen) {
+ throw new ArrayIndexOutOfBoundsException("input.length "+input.length+", offset "+inOff+", length "+inLen);
+ }
+ final byte[] output = new byte[inLen];
+ final Deflater deflater = new Deflater(level);
+ deflater.setInput(input, inOff, inLen);
+ deflater.finish();
+ final int outSize = deflater.deflate(output, 0, inLen);
+ deflater.end();
+ {
+ final DataOutputStream dout = new DataOutputStream(out);
+ dout.writeInt(CustomCompress.MAGIC);
+ dout.writeInt(outSize);
+ dout.writeInt(inLen);
+ }
+ out.write(output, 0, outSize);
+ return outSize;
+ }
+
+}
diff --git a/src/java/com/jogamp/common/util/FunctionTask.java b/src/java/com/jogamp/common/util/FunctionTask.java
index 4ac64d3..9eb1ca5 100644
--- a/src/java/com/jogamp/common/util/FunctionTask.java
+++ b/src/java/com/jogamp/common/util/FunctionTask.java
@@ -30,6 +30,8 @@ package com.jogamp.common.util;
import java.io.PrintStream;
+import com.jogamp.common.JogampRuntimeException;
+
/**
* Helper class to provide a Runnable queue implementation with a Runnable wrapper
* which notifies after execution for the <code>invokeAndWait()</code> semantics.
@@ -40,34 +42,67 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> {
protected A[] args;
/**
- * Invokes <code>func</code>.
+ * Invokes <code>func</code> on the current {@link Thread}.
+ * <p>
+ * The result can be retrieved via {@link FunctionTask#getResult()},
+ * using the returned instance.
+ * </p>
+ * @param func the {@link Function} to execute.
+ * @param args the {@link Function} arguments
+ * @return the newly created and invoked {@link FunctionTask}
+ * @since 2.4.0
+ */
+ public static <U,V> FunctionTask<U,V> invokeOnCurrentThread(final Function<U,V> func, final V... args) {
+ final FunctionTask<U,V> rt = new FunctionTask<U,V>( func, null, false, null);
+ rt.args = args;
+ rt.run();
+ return rt;
+ }
+
+ /**
+ * Invokes <code>func</code> on a new {@link InterruptSource.Thread},
+ * see {@link InterruptSource.Thread#Thread(ThreadGroup, Runnable, String)} for details.
+ * <p>
+ * The result can be retrieved via {@link FunctionTask#getResult()},
+ * using the returned instance.
+ * </p>
+ * @param tg the {@link ThreadGroup} for the new thread, maybe <code>null</code>
+ * @param threadName the name for the new thread, maybe <code>null</code>
* @param waitUntilDone if <code>true</code>, waits until <code>func</code> execution is completed, otherwise returns immediately.
* @param func the {@link Function} to execute.
* @param args the {@link Function} arguments
- * @return the {@link Function} return value
+ * @return the newly created and invoked {@link FunctionTask}
+ * @since 2.3.2
*/
- public static <U,V> U invoke(final boolean waitUntilDone, final Function<U,V> func, final V... args) {
- Throwable throwable = null;
- final Object sync = new Object();
- final FunctionTask<U,V> rt = new FunctionTask<U,V>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
- final U res;
- synchronized(sync) {
- res = rt.eval(args);
- if( waitUntilDone ) {
- try {
- sync.wait();
- } catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rt.getThrowable();
- }
- if(null!=throwable) {
- throw new RuntimeException(throwable);
+ public static <U,V> FunctionTask<U,V> invokeOnNewThread(final ThreadGroup tg, final String threadName,
+ final boolean waitUntilDone, final Function<U,V> func, final V... args) {
+ final FunctionTask<U,V> rt;
+ if( !waitUntilDone ) {
+ rt = new FunctionTask<U,V>( func, null, true, System.err );
+ final InterruptSource.Thread t = InterruptSource.Thread.create(tg, rt, threadName);
+ rt.args = args;
+ t.start();
+ } else {
+ final Object sync = new Object();
+ rt = new FunctionTask<U,V>( func, sync, true, null );
+ final InterruptSource.Thread t = InterruptSource.Thread.create(tg, rt, threadName);
+ synchronized(sync) {
+ rt.args = args;
+ t.start();
+ while( rt.isInQueue() ) {
+ try {
+ sync.wait();
+ } catch (final InterruptedException ie) {
+ throw new InterruptedRuntimeException(ie);
+ }
+ final Throwable throwable = rt.getThrowable();
+ if(null!=throwable) {
+ throw new JogampRuntimeException(throwable);
+ }
}
}
}
- return res;
+ return rt;
}
/**
@@ -124,6 +159,8 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> {
*/
@Override
public final void run() {
+ execThread = Thread.currentThread();
+
final A[] args = this.args;
this.args = null;
this.result = null;
@@ -144,6 +181,7 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> {
}
} finally {
tExecuted = System.currentTimeMillis();
+ isExecuted = true;
}
} else {
synchronized (syncObject) {
@@ -161,6 +199,7 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> {
}
} finally {
tExecuted = System.currentTimeMillis();
+ isExecuted = true;
syncObject.notifyAll();
}
}
diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java
index c773b21..0381ebc 100644
--- a/src/java/com/jogamp/common/util/IOUtil.java
+++ b/src/java/com/jogamp/common/util/IOUtil.java
@@ -39,18 +39,25 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
+import java.io.Reader;
+import java.io.SyncFailedException;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.regex.Pattern;
import jogamp.common.Debug;
import jogamp.common.os.AndroidUtils;
import jogamp.common.os.PlatformPropsImpl;
+import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.JogampRuntimeException;
import com.jogamp.common.net.AssetURLContext;
import com.jogamp.common.net.Uri;
import com.jogamp.common.nio.Buffers;
@@ -58,7 +65,61 @@ import com.jogamp.common.os.MachineDataInfo;
import com.jogamp.common.os.Platform;
public class IOUtil {
- public static final boolean DEBUG = Debug.debug("IOUtil");
+ public static final boolean DEBUG;
+ private static final boolean DEBUG_EXE;
+ private static final boolean DEBUG_EXE_NOSTREAM;
+ private static final boolean DEBUG_EXE_EXISTING_FILE;
+ private static final boolean testTempDirExec;
+ private static final Method fileToPathGetter;
+ private static final Method isExecutableQuery;
+ private static final boolean useNativeExeFile;
+
+ static {
+ final boolean _props[] = { false, false, false, false, false, false };
+ final Method[] res = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
+ @Override
+ public Method[] run() {
+ final Method[] res = new Method[] { null, null };
+ try {
+ int i=0;
+ _props[i++] = Debug.debug("IOUtil");
+ _props[i++] = PropertyAccess.isPropertyDefined("jogamp.debug.IOUtil.Exe", true);
+ _props[i++] = PropertyAccess.isPropertyDefined("jogamp.debug.IOUtil.Exe.NoStream", true);
+ // For security reasons, we have to hardcode this, i.e. disable this manual debug feature!
+ _props[i++] = false; // PropertyAccess.isPropertyDefined("jogamp.debug.IOUtil.Exe.ExistingFile", true);
+ _props[i++] = PropertyAccess.getBooleanProperty("jogamp.gluegen.TestTempDirExec", true, true);
+ _props[i++] = PropertyAccess.getBooleanProperty("jogamp.gluegen.UseNativeExeFile", true, false);
+
+ // Java 1.7
+ i=0;
+ res[i] = File.class.getDeclaredMethod("toPath");
+ res[i++].setAccessible(true);
+ final Class<?> nioPathClz = ReflectionUtil.getClass("java.nio.file.Path", false, IOUtil.class.getClassLoader());
+ final Class<?> nioFilesClz = ReflectionUtil.getClass("java.nio.file.Files", false, IOUtil.class.getClassLoader());
+ res[i] = nioFilesClz.getDeclaredMethod("isExecutable", nioPathClz);
+ res[i++].setAccessible(true);
+ } catch (final Throwable t) {
+ if(_props[0]) {
+ ExceptionUtils.dumpThrowable("ioutil-init", t);
+ }
+ }
+ return res;
+ }
+ });
+ {
+ int i=0;
+ DEBUG = _props[i++];
+ DEBUG_EXE = _props[i++];
+ DEBUG_EXE_NOSTREAM = _props[i++];
+ DEBUG_EXE_EXISTING_FILE = _props[i++];
+ testTempDirExec = _props[i++];
+ useNativeExeFile = _props[i++];
+
+ i=0;
+ fileToPathGetter = res[i++];
+ isExecutableQuery = res[i++];
+ }
+ }
/** Std. temporary directory property key <code>java.io.tmpdir</code>. */
private static final String java_io_tmpdir_propkey = "java.io.tmpdir";
@@ -188,6 +249,15 @@ public class IOUtil {
return numBytes;
}
+ public static StringBuilder appendCharStream(final StringBuilder sb, final Reader r) throws IOException {
+ final char[] cbuf = new char[1024];
+ int count;
+ while( 0 < ( count = r.read(cbuf) ) ) {
+ sb.append(cbuf, 0, count);
+ }
+ return sb;
+ }
+
/**
* Copy the specified input stream to a byte array, which is being returned.
*/
@@ -408,7 +478,7 @@ public class IOUtil {
/***
*
- * RESOURCE LOCATION STUFF
+ * RESOURCE LOCATION HELPER
*
*/
@@ -417,7 +487,10 @@ public class IOUtil {
* to be {@link #resolve(int) resolved} at a later time.
*/
public static class ClassResources {
- /** Class instance used to {@link #resolve(int)} the {@link #resourcePaths}. */
+ /** Optional {@link ClassLoader} used to {@link #resolve(int)} {@link #resourcePaths}. */
+ public final ClassLoader classLoader;
+
+ /** Optional class instance used to {@link #resolve(int)} relative {@link #resourcePaths}. */
public final Class<?> contextCL;
/** Resource paths, see {@link #resolve(int)}. */
@@ -427,67 +500,73 @@ public class IOUtil {
public final int resourceCount() { return resourcePaths.length; }
/**
- * @param contextCL class instance to {@link #resolve(int)} {@link #resourcePaths}.
- * @param resourcePaths array of strings denominating multiple resource paths. None shall be null.
+ * @param resourcePaths multiple relative or absolute resource locations
+ * @param classLoader optional {@link ClassLoader}, see {@link IOUtil#getResource(String, ClassLoader, Class)}
+ * @param relContext optional relative context, see {@link IOUtil#getResource(String, ClassLoader, Class)}
*/
- public ClassResources(final Class<?> contextCL, final String[] resourcePaths) {
+ public ClassResources(final String[] resourcePaths, final ClassLoader classLoader, final Class<?> relContext) {
for(int i=resourcePaths.length-1; i>=0; i--) {
if( null == resourcePaths[i] ) {
throw new IllegalArgumentException("resourcePath["+i+"] is null");
}
}
- this.contextCL = contextCL;
+ this.classLoader = classLoader;
+ this.contextCL = relContext;
this.resourcePaths = resourcePaths;
}
/**
- * Resolving one of the {@link #resourcePaths} indexed by <code>uriIndex</code> using {@link #contextCL} and {@link IOUtil#getResource(Class, String)}.
+ * Resolving one of the {@link #resourcePaths} indexed by <code>uriIndex</code> using
+ * {@link #classLoader}, {@link #contextCL} through {@link IOUtil#getResource(String, ClassLoader, Class)}.
* @throws ArrayIndexOutOfBoundsException if <code>uriIndex</code> is < 0 or >= {@link #resourceCount()}.
*/
public URLConnection resolve(final int uriIndex) throws ArrayIndexOutOfBoundsException {
- return getResource(contextCL, resourcePaths[uriIndex]);
+ return getResource(resourcePaths[uriIndex], classLoader, contextCL);
}
}
/**
* Locating a resource using {@link #getResource(String, ClassLoader)}:
* <ul>
- * <li><i>relative</i>: <code>context</code>'s package name-path plus <code>resourcePath</code> via <code>context</code>'s ClassLoader.
+ * <li><i>relative</i>: <code>relContext</code>'s package name-path plus <code>resourcePath</code> via <code>classLoader</code>.
* This allows locations relative to JAR- and other URLs.
- * The <code>resourcePath</code> may start with <code>../</code> to navigate to parent folder.</li>
- * <li><i>absolute</i>: <code>context</code>'s ClassLoader and the <code>resourcePath</code> as is (filesystem)</li>
+ * The <code>resourcePath</code> may start with <code>../</code> to navigate to parent folder.
+ * This attempt is skipped if {@code relContext} is {@code null}.</li>
+ * <li><i>absolute</i>: <code>resourcePath</code> as is via <code>classLoader</code>.
* </ul>
- *
* <p>
* Returns the resolved and open URLConnection or null if not found.
* </p>
*
+ * @param resourcePath the resource path to locate relative or absolute
+ * @param classLoader the optional {@link ClassLoader}, recommended
+ * @param relContext relative context, i.e. position, of the {@code resourcePath},
+ * to perform the relative lookup, if not {@code null}.
* @see #getResource(String, ClassLoader)
* @see ClassLoader#getResource(String)
* @see ClassLoader#getSystemResource(String)
*/
- public static URLConnection getResource(final Class<?> context, final String resourcePath) {
+ public static URLConnection getResource(final String resourcePath, final ClassLoader classLoader, final Class<?> relContext) {
if(null == resourcePath) {
return null;
}
- final ClassLoader contextCL = (null!=context)?context.getClassLoader():IOUtil.class.getClassLoader();
URLConnection conn = null;
- if(null != context) {
+ if(null != relContext) {
// scoping the path within the class's package
- final String className = context.getName().replace('.', '/');
+ final String className = relContext.getName().replace('.', '/');
final int lastSlash = className.lastIndexOf('/');
if (lastSlash >= 0) {
final String pkgName = className.substring(0, lastSlash + 1);
- conn = getResource(pkgName + resourcePath, contextCL);
+ conn = getResource(pkgName + resourcePath, classLoader);
if(DEBUG) {
- System.err.println("IOUtil: found <"+resourcePath+"> within class package <"+pkgName+"> of given class <"+context.getName()+">: "+(null!=conn));
+ System.err.println("IOUtil: found <"+resourcePath+"> within class package <"+pkgName+"> of given class <"+relContext.getName()+">: "+(null!=conn));
}
}
} else if(DEBUG) {
- System.err.println("IOUtil: null context");
+ System.err.println("IOUtil: null context, skip rel. lookup");
}
if(null == conn) {
- conn = getResource(resourcePath, contextCL);
+ conn = getResource(resourcePath, classLoader);
if(DEBUG) {
System.err.println("IOUtil: found <"+resourcePath+"> by classloader: "+(null!=conn));
}
@@ -518,8 +597,7 @@ public class IOUtil {
return AssetURLContext.createURL(resourcePath, cl).openConnection();
} catch (final IOException ioe) {
if(DEBUG) {
- System.err.println("IOUtil: Caught Exception:");
- ioe.printStackTrace();
+ ExceptionUtils.dumpThrowable("IOUtil", ioe);
}
return null;
}
@@ -528,8 +606,7 @@ public class IOUtil {
return AssetURLContext.resolve(resourcePath, cl);
} catch (final IOException ioe) {
if(DEBUG) {
- System.err.println("IOUtil: Caught Exception:");
- ioe.printStackTrace();
+ ExceptionUtils.dumpThrowable("IOUtil", ioe);
}
}
}
@@ -557,7 +634,7 @@ public class IOUtil {
}
/**
- * @param path assuming a slashified path beginning with "/" as it's root directory, either denotes a file or directory.
+ * @param path assuming a slashified path, either denotes a file or directory, either relative or absolute.
* @return parent of path
* @throws URISyntaxException if path is empty or has no parent directory available
*/
@@ -569,11 +646,11 @@ public class IOUtil {
final int e = path.lastIndexOf("/");
if( e < 0 ) {
- throw new URISyntaxException(path, "path contains no '/'");
+ throw new URISyntaxException(path, "path contains no '/': <"+path+">");
}
if( e == 0 ) {
// path is root directory
- throw new URISyntaxException(path, "path has no parents");
+ throw new URISyntaxException(path, "path has no parents: <"+path+">");
}
if( e < pl - 1 ) {
// path is file, return it's parent directory
@@ -583,23 +660,45 @@ public class IOUtil {
// path is a directory ..
final int p = path.lastIndexOf("/", e-1);
if( p >= j) {
+ // parent itself has '/' - post '!' or no '!' at all
return path.substring(0, p+1);
+ } else {
+ // parent itself has no '/'
+ final String parent = path.substring(j, e);
+ if( parent.equals("..") ) {
+ throw new URISyntaxException(path, "parent is unresolved: <"+path+">");
+ } else {
+ // parent is '!' or empty (relative path)
+ return path.substring(0, j);
+ }
}
- throw new URISyntaxException(path, "parent of path contains no '/'");
}
/**
- * @param path assuming a slashified path beginning with "/" as it's root directory, either denotes a file or directory.
- * @return clean path string where <code>../</code> and <code>./</code> is resolved.
+ * @param path assuming a slashified path, either denoting a file or directory, either relative or absolute.
+ * @return clean path string where {@code ./} and {@code ../} is resolved,
+ * while keeping a starting {@code ../} at the beginning of a relative path.
* @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
*/
public static String cleanPathString(String path) throws URISyntaxException {
- int idx;
- while ( ( idx = path.indexOf("../") ) >= 0 ) {
- path = getParentOf(path.substring(0, idx)) + path.substring(idx+3);
+ // Resolve './' before '../' to handle case 'parent/./../a.txt' properly.
+ int idx = path.length() - 1;
+ while ( idx >= 1 && ( idx = path.lastIndexOf("./", idx) ) >= 0 ) {
+ if( 0 < idx && path.charAt(idx-1) == '.' ) {
+ idx-=2; // skip '../' -> idx upfront
+ } else {
+ path = path.substring(0, idx) + path.substring(idx+2);
+ idx--; // idx upfront
+ }
}
- while ( ( idx = path.indexOf("./") ) >= 0 ) {
- path = path.substring(0, idx) + path.substring(idx+2);
+ idx = 0;
+ while ( ( idx = path.indexOf("../", idx) ) >= 0 ) {
+ if( 0 == idx ) {
+ idx += 3; // skip starting '../'
+ } else {
+ path = getParentOf(path.substring(0, idx)) + path.substring(idx+3);
+ idx = 0;
+ }
}
return path;
}
@@ -642,8 +741,7 @@ public class IOUtil {
return c;
} catch (final IOException ioe) {
if(DEBUG) {
- System.err.println("IOUtil: urlExists("+url+") ["+dbgmsg+"] - false - "+ioe.getClass().getSimpleName()+": "+ioe.getMessage());
- ioe.printStackTrace();
+ ExceptionUtils.dumpThrowable("IOUtil: urlExists("+url+") ["+dbgmsg+"] - false -", ioe);
}
}
} else if(DEBUG) {
@@ -656,7 +754,7 @@ public class IOUtil {
private static String getExeTestFileSuffix() {
switch(PlatformPropsImpl.OS_TYPE) {
case WINDOWS:
- if( Platform.CPUFamily.X86 == PlatformPropsImpl.CPU_ARCH.family ) {
+ if( useNativeExeFile && Platform.CPUFamily.X86 == PlatformPropsImpl.CPU_ARCH.family ) {
return ".exe";
} else {
return ".bat";
@@ -670,7 +768,7 @@ public class IOUtil {
case WINDOWS:
return "echo off"+PlatformPropsImpl.NEWLINE;
default:
- return null;
+ return "#!/bin/true"+PlatformPropsImpl.NEWLINE;
}
}
private static String[] getExeTestCommandArgs(final String scriptFile) {
@@ -681,48 +779,50 @@ public class IOUtil {
return new String[] { scriptFile };
}
}
- private static final byte[] getBytesFromRelFile(final byte[] res, final String fname, final int size) throws IOException {
- final URLConnection con = IOUtil.getResource(IOUtil.class, fname);
+
+ private static final byte[] readCode(final String fname) throws IOException {
+ final URLConnection con = IOUtil.getResource(fname, IOUtil.class.getClassLoader(), IOUtil.class);
final InputStream in = con.getInputStream();
- int numBytes = 0;
+ byte[] output = null;
try {
- while (true) {
- final int remBytes = size - numBytes;
- int count;
- if ( 0 >= remBytes || (count = in.read(res, numBytes, remBytes)) == -1 ) {
- break;
- }
- numBytes += count;
- }
+ output = CustomCompress.inflateFromStream(in);
} finally {
in.close();
}
- if( size != numBytes ) {
- throw new IOException("Got "+numBytes+" bytes != expected "+size);
- }
- return res;
+ return output;
}
- private static final Object exeTestBytesLock = new Object();
- private static WeakReference<byte[]> exeTestBytesRef = null;
+ private static final Object exeTestLock = new Object();
+ private static WeakReference<byte[]> exeTestCodeRef = null;
private static void fillExeTestFile(final File exefile) throws IOException {
- if( Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE &&
+ if( useNativeExeFile &&
+ Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE &&
Platform.CPUFamily.X86 == PlatformPropsImpl.CPU_ARCH.family
) {
- final int codeSize = 268;
- final byte[] code;
- synchronized ( exeTestBytesLock ) {
- byte[] _code;
- if( null == exeTestBytesRef || null == ( _code = exeTestBytesRef.get() ) ) {
- code = getBytesFromRelFile(new byte[512], "bin/exe-windows-i586-268b.bin", codeSize);
- exeTestBytesRef = new WeakReference<byte[]>(code);
+ final byte[] exeTestCode;
+ synchronized ( exeTestLock ) {
+ byte[] _exeTestCode = null;
+ if( null == exeTestCodeRef || null == ( _exeTestCode = exeTestCodeRef.get() ) ) {
+ final String fname;
+ if( Platform.CPUType.X86_64 == PlatformPropsImpl.CPU_ARCH ) {
+ fname = "bin/exe-windows-x86_64.defl";
+ } else {
+ fname = "bin/exe-windows-i386.defl";
+ }
+ exeTestCode = readCode(fname);
+ exeTestCodeRef = new WeakReference<byte[]>(exeTestCode);
} else {
- code = _code;
+ exeTestCode = _exeTestCode;
}
}
- final OutputStream out = new FileOutputStream(exefile);
+ final FileOutputStream out = new FileOutputStream(exefile);
try {
- out.write(code, 0, codeSize);
+ out.write(exeTestCode, 0, exeTestCode.length);
+ try {
+ out.getFD().sync();
+ } catch (final SyncFailedException sfe) {
+ ExceptionUtils.dumpThrowable("", sfe);
+ }
} finally {
out.close();
}
@@ -732,6 +832,11 @@ public class IOUtil {
final FileWriter fout = new FileWriter(exefile);
try {
fout.write(shellCode);
+ try {
+ fout.flush();
+ } catch (final IOException sfe) {
+ ExceptionUtils.dumpThrowable("", sfe);
+ }
} finally {
fout.close();
}
@@ -796,50 +901,70 @@ public class IOUtil {
public static class StreamMonitor implements Runnable {
private final InputStream[] istreams;
+ private final boolean[] eos;
private final PrintStream ostream;
private final String prefix;
public StreamMonitor(final InputStream[] streams, final PrintStream ostream, final String prefix) {
this.istreams = streams;
+ this.eos = new boolean[streams.length];
this.ostream = ostream;
this.prefix = prefix;
- new Thread(this, "StreamMonitor-"+Thread.currentThread().getName()).start();
+ final InterruptSource.Thread t = new InterruptSource.Thread(null, this, "StreamMonitor-"+Thread.currentThread().getName());
+ t.setDaemon(true);
+ t.start();
}
+
@Override
public void run()
{
final byte[] buffer = new byte[4096];
try {
- int numRead;
+ final int streamCount = istreams.length;
+ int eosCount = 0;
do {
- numRead = 0;
for(int i=0; i<istreams.length; i++) {
- final int numReadI = istreams[i].read(buffer);
- if (numReadI > 0) {
- if( null != ostream ) {
- if( null != prefix ) {
- ostream.write(prefix.getBytes());
+ if( !eos[i] ) {
+ final int numReadI = istreams[i].read(buffer);
+ if (numReadI > 0) {
+ if( null != ostream ) {
+ if( null != prefix ) {
+ ostream.write(prefix.getBytes());
+ }
+ ostream.write(buffer, 0, numReadI);
}
- ostream.write(buffer, 0, numReadI);
+ } else {
+ // numReadI == -1
+ eosCount++;
+ eos[i] = true;
}
- numRead += numReadI;
}
}
if( null != ostream ) {
ostream.flush();
}
- } while (numRead >= 0);
- }
- catch (final IOException e) {
- for(int i=0; i<istreams.length; i++) {
- try {
- istreams[i].close();
- } catch (final IOException e2) { }
+ } while ( eosCount < streamCount );
+ } catch (final IOException e) {
+ } finally {
+ if( null != ostream ) {
+ ostream.flush();
}
// Should allow clean exit when process shuts down
}
}
}
+ private static final Boolean isNioExecutableFile(final File file) {
+ if( null != fileToPathGetter && null != isExecutableQuery ) {
+ try {
+ return (Boolean) isExecutableQuery.invoke(null, fileToPathGetter.invoke(file));
+ } catch (final Throwable t) {
+ throw new JogampRuntimeException("error invoking Files.isExecutable(file.toPath())", t);
+ }
+ } else {
+ return null;
+ }
+ }
+
/**
* Returns true if the given {@code dir}
* <ol>
@@ -855,65 +980,114 @@ public class IOUtil {
public static boolean testDirExec(final File dir)
throws SecurityException
{
- if (!testFile(dir, true, true)) {
+ final boolean debug = DEBUG_EXE || DEBUG;
+
+ if( !testTempDirExec ) {
if(DEBUG) {
+ System.err.println("IOUtil.testDirExec: <"+dir.getAbsolutePath()+">: Disabled TestTempDirExec");
+ }
+ return false;
+ }
+ if (!testFile(dir, true, true)) {
+ if( debug ) {
System.err.println("IOUtil.testDirExec: <"+dir.getAbsolutePath()+">: Not writeable dir");
}
return false;
}
if(!getOSHasNoexecFS()) {
- if(DEBUG) {
+ if( debug ) {
System.err.println("IOUtil.testDirExec: <"+dir.getAbsolutePath()+">: Always executable");
}
return true;
}
- final long t0 = DEBUG ? System.currentTimeMillis() : 0;
+ final long t0 = debug ? System.currentTimeMillis() : 0;
final File exeTestFile;
+ final boolean existingExe;
try {
- exeTestFile = File.createTempFile("jogamp_exe_tst", getExeTestFileSuffix(), dir);
+ final File permExeTestFile = DEBUG_EXE_EXISTING_FILE ? new File(dir, "jogamp_exe_tst"+getExeTestFileSuffix()) : null;
+ if( null != permExeTestFile && permExeTestFile.exists() ) {
+ exeTestFile = permExeTestFile;
+ existingExe = true;
+ } else {
+ exeTestFile = File.createTempFile("jogamp_exe_tst", getExeTestFileSuffix(), dir);
+ existingExe = false;
+ fillExeTestFile(exeTestFile);
+ }
} catch (final SecurityException se) {
throw se; // fwd Security exception
} catch (final IOException e) {
- if(DEBUG) {
+ if( debug ) {
e.printStackTrace();
}
return false;
}
- final long t1 = DEBUG ? System.currentTimeMillis() : 0;
+ final long t1 = debug ? System.currentTimeMillis() : 0;
+ long t2;
int res = -1;
- if(exeTestFile.setExecutable(true /* exec */, true /* ownerOnly */)) {
- try {
- fillExeTestFile(exeTestFile);
-
- // Using 'Process.exec(String[])' avoids StringTokenizer of 'Process.exec(String)'
- // and hence splitting up command by spaces!
- final Process pr = Runtime.getRuntime().exec( getExeTestCommandArgs( exeTestFile.getCanonicalPath() ) );
- /**
- * Disable StreamMonitor, which throttles exec-test performance a lot!
- *
- * if( isStringSet(shellCode) ) {
- new StreamMonitor(new InputStream[] { pr.getInputStream(), pr.getErrorStream() }, System.err, "Exe-Tst: ");
- }
- */
- pr.waitFor() ;
- res = pr.exitValue();
- } catch (final SecurityException se) {
- throw se; // fwd Security exception
- } catch (final Throwable t) {
- res = -2;
- if(DEBUG) {
- System.err.println("IOUtil.testDirExec: <"+exeTestFile.getAbsolutePath()+">: Caught "+t.getClass().getSimpleName()+": "+t.getMessage());
- t.printStackTrace();
+ int exitValue = -1;
+ Boolean isNioExec = null;
+ if( existingExe || exeTestFile.setExecutable(true /* exec */, true /* ownerOnly */) ) {
+ t2 = debug ? System.currentTimeMillis() : 0;
+ // First soft exec test via NIO's ACL check, if available
+ isNioExec = isNioExecutableFile(exeTestFile);
+ if( null != isNioExec ) {
+ res = isNioExec.booleanValue() ? 0 : -1;
+ }
+ if( null == isNioExec || 0 <= res ) {
+ // Hard exec test via actual execution, if NIO's ACL check succeeded or not available.
+ // Required, since Windows 'Software Restriction Policies (SRP)' won't be triggered merely by NIO's ACL check.
+ Process pr = null;
+ try {
+ // Using 'Process.exec(String[])' avoids StringTokenizer of 'Process.exec(String)'
+ // and hence splitting up command by spaces!
+ // Note: All no-exec cases throw an IOExceptions at ProcessBuilder.start(), i.e. below exec() call!
+ pr = Runtime.getRuntime().exec( getExeTestCommandArgs( exeTestFile.getCanonicalPath() ), null, null );
+ if( DEBUG_EXE && !DEBUG_EXE_NOSTREAM ) {
+ new StreamMonitor(new InputStream[] { pr.getInputStream(), pr.getErrorStream() }, System.err, "Exe-Tst: ");
+ }
+ pr.waitFor();
+ exitValue = pr.exitValue(); // Note: Bug 1219 Comment 50: On reporter's machine exit value 1 is being returned
+ if( 0 == exitValue ) {
+ res++; // file has been executed and exited normally
+ } else {
+ res = -2; // abnormal termination
+ }
+ } catch (final SecurityException se) {
+ throw se; // fwd Security exception
+ } catch (final Throwable t) {
+ t2 = debug ? System.currentTimeMillis() : 0;
+ res = -3;
+ if( debug ) {
+ System.err.println("IOUtil.testDirExec: <"+exeTestFile.getAbsolutePath()+">: Caught "+t.getClass().getSimpleName()+": "+t.getMessage());
+ t.printStackTrace();
+ }
+ } finally {
+ if( null != pr ) {
+ // Bug 1219 Comment 58: Ensure that the launched process gets terminated!
+ // This is Process implementation specific and varies on different platforms,
+ // hence it may be required.
+ try {
+ pr.destroy();
+ } catch (final Throwable t) {
+ ExceptionUtils.dumpThrowable("", t);
+ }
+ }
}
}
+ } else {
+ t2 = debug ? System.currentTimeMillis() : 0;
+ }
+
+ final boolean ok = 0 <= res;
+ if( !DEBUG_EXE && !existingExe ) {
+ exeTestFile.delete();
}
- final boolean ok = 0 == res;
- final long t2 = DEBUG ? System.currentTimeMillis() : 0;
- exeTestFile.delete();
- if( DEBUG) {
- System.err.println("IOUtil.testDirExec(): <"+dir.getAbsolutePath()+">: res "+res+" -> "+ok);
- System.err.println("IOUtil.testDirExec(): total "+(t2-t0)+"ms, create "+(t1-t0)+"ms, execute "+(t2-t1)+"ms");
+ if( debug ) {
+ final long t3 = System.currentTimeMillis();
+ System.err.println("IOUtil.testDirExec(): test-exe <"+exeTestFile.getAbsolutePath()+">, existingFile "+existingExe+", isNioExec "+isNioExec+", returned "+exitValue);
+ System.err.println("IOUtil.testDirExec(): abs-path <"+dir.getAbsolutePath()+">: res "+res+" -> "+ok);
+ System.err.println("IOUtil.testDirExec(): total "+(t3-t0)+"ms, create "+(t1-t0)+"ms, fill "+(t2-t1)+"ms, execute "+(t3-t2)+"ms");
}
return ok;
}
diff --git a/src/java/com/jogamp/common/util/IntBitfield.java b/src/java/com/jogamp/common/util/IntBitfield.java
deleted file mode 100644
index 74e37ac..0000000
--- a/src/java/com/jogamp/common/util/IntBitfield.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/**
- * Copyright 2012 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.common.util;
-
-/**
- * Simple bitfield holder class using an int[] storage.
- * <p>
- * IntBitfield allows convenient access of a wide field of transient bits using efficient storage in O(1).
- * </p>
- * <p>
- * It can be used e.g. to map key-codes to pressed-state etc.
- * </p>
- */
-public class IntBitfield {
- /** Unit size in bits, here 32 bits for one int unit. */
- public static final int UNIT_SIZE = 32;
-
- private static final long UNIT_SHIFT_L = 5L;
- private static final int UNIT_SHIFT_I = 5;
-
- private final int[] storage;
- private final long bitsCountL;
- private final int bitsCountI;
-
- /**
- * @param bitCount
- */
- public IntBitfield(final long bitCount) {
- final int units = (int) Math.max(1L, ( bitCount + 7L ) >>> UNIT_SHIFT_L);
- this.storage = new int[units];
- this.bitsCountL = (long)units << UNIT_SHIFT_L ;
- this.bitsCountI = bitsCountL > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)bitsCountL;
- }
-
- /**
- * @param bitCount
- */
- public IntBitfield(final int bitCount) {
- final int units = Math.max(1, ( bitCount + 7 ) >>> UNIT_SHIFT_I);
- this.storage = new int[units];
- this.bitsCountI = units << UNIT_SHIFT_I;
- this.bitsCountL = bitsCountI;
- }
-
- private final void check(final long bitnum) {
- if( 0 > bitnum || bitnum >= bitsCountL ) {
- throw new ArrayIndexOutOfBoundsException("Bitnum should be within [0.."+(bitsCountL-1)+"], but is "+bitnum);
- }
- }
- private final void check(final int bitnum) {
- if( 0 > bitnum || bitnum >= bitsCountI ) {
- throw new ArrayIndexOutOfBoundsException("Bitnum should be within [0.."+(bitsCountI-1)+"], but is "+bitnum);
- }
- }
-
- /** Return the capacity of this bit field, i.e. the number of bits stored int this field. */
- public final long capacity() { return bitsCountL; }
-
- /** Return <code>true</code> if the bit at position <code>bitnum</code> is set, otherwise <code>false</code>. */
- public final boolean get(final long bitnum) {
- check(bitnum);
- final int u = (int) ( bitnum >>> UNIT_SHIFT_L );
- final int b = (int) ( bitnum - ( (long)u << UNIT_SHIFT_L ) );
- return 0 != ( storage[u] & ( 1 << b ) ) ;
- }
-
- /** Return <code>true</code> if the bit at position <code>bitnum</code> is set, otherwise <code>false</code>. */
- public final boolean get(final int bitnum) {
- check(bitnum);
- final int u = bitnum >>> UNIT_SHIFT_I;
- final int b = bitnum - ( u << UNIT_SHIFT_I );
- return 0 != ( storage[u] & ( 1 << b ) ) ;
- }
-
- /**
- * Set or clear the bit at position <code>bitnum</code> according to <code>bit</code>
- * and return the previous value.
- */
- public final boolean put(final long bitnum, final boolean bit) {
- check(bitnum);
- final int u = (int) ( bitnum >>> UNIT_SHIFT_L );
- final int b = (int) ( bitnum - ( (long)u << UNIT_SHIFT_L ) );
- final int m = 1 << b;
- final boolean prev = 0 != ( storage[u] & m ) ;
- if( prev != bit ) {
- if( bit ) {
- storage[u] |= m;
- } else {
- storage[u] &= ~m;
- }
- }
- return prev;
- }
-
- /**
- * Set or clear the bit at position <code>bitnum</code> according to <code>bit</code>
- * and return the previous value.
- */
- public final boolean put(final int bitnum, final boolean bit) {
- check(bitnum);
- final int u = bitnum >>> UNIT_SHIFT_I;
- final int b = bitnum - ( u << UNIT_SHIFT_I );
- final int m = 1 << b;
- final boolean prev = 0 != ( storage[u] & m ) ;
- if( prev != bit ) {
- if( bit ) {
- storage[u] |= m;
- } else {
- storage[u] &= ~m;
- }
- }
- return prev;
- }
- /**
- * Returns the number of set bits within given 32bit integer in O(1)
- * using <i>HAKEM Bit Count</i>:
- * <pre>
- * http://www.inwap.com/pdp10/hbaker/hakmem/hakmem.html
- * http://home.pipeline.com/~hbaker1/hakmem/hacks.html#item169
- * http://tekpool.wordpress.com/category/bit-count/
- * </pre>
- */
- public static final int getBitCount(final int n) {
- // Note: Original used 'unsigned int',
- // hence we use the unsigned right-shift '>>>'
- int c = n;
- c -= (n >>> 1) & 033333333333;
- c -= (n >>> 2) & 011111111111;
- return ( (c + ( c >>> 3 ) ) & 030707070707 ) % 63;
- }
-
- /**
- * Returns the number of set bits within this bitfield.
- * <p>
- * Utilizes {#link {@link #getBitCount(int)}}.
- * </p>
- */
- public long getBitCount() {
- long c = 0;
- for(int i = storage.length-1; i>=0; i--) {
- c += getBitCount(storage[i]);
- }
- return c;
- }
-}
diff --git a/src/java/com/jogamp/common/util/InterruptSource.java b/src/java/com/jogamp/common/util/InterruptSource.java
new file mode 100644
index 0000000..01fcdb5
--- /dev/null
+++ b/src/java/com/jogamp/common/util/InterruptSource.java
@@ -0,0 +1,157 @@
+/**
+ * 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.common.util;
+
+/**
+ * Interface exposing {@link java.lang.Thread#interrupt()} source,
+ * intended for {@link java.lang.Thread} specializations.
+ * @since 2.3.2
+ */
+public interface InterruptSource {
+ /**
+ * Returns the source of the last {@link #interrupt()} call.
+ * @param clear if true, issues {@link #clearInterruptSource()}
+ */
+ Throwable getInterruptSource(final boolean clear);
+
+ /**
+ * Returns the count of {@link java.lang.Thread#interrupt()} calls.
+ * @param clear if true, issues {@link #clearInterruptSource()}
+ */
+ int getInterruptCounter(final boolean clear);
+
+ /**
+ * Clears source and count of {@link java.lang.Thread#interrupt()} calls, if any.
+ */
+ void clearInterruptSource();
+
+ public static class Util {
+ /**
+ * Casts given {@link java.lang.Thread} to {@link InterruptSource}
+ * if applicable, otherwise returns {@code null}.
+ */
+ public static InterruptSource get(final java.lang.Thread t) {
+ if(t instanceof InterruptSource) {
+ return (InterruptSource)t;
+ } else {
+ return null;
+ }
+ }
+ /**
+ * Casts current {@link java.lang.Thread} to {@link InterruptSource}
+ * if applicable, otherwise returns {@code null}.
+ */
+ public static InterruptSource currentThread() {
+ return get(java.lang.Thread.currentThread());
+ }
+ }
+
+ /**
+ * {@link java.lang.Thread} specialization implementing {@link InterruptSource}
+ * to track {@link java.lang.Thread#interrupt()} calls.
+ * @since 2.3.2
+ */
+ public static class Thread extends java.lang.Thread implements InterruptSource {
+ volatile Throwable interruptSource = null;
+ volatile int interruptCounter = 0;
+ final Object sync = new Object();
+
+ /**
+ * See {@link Thread#Thread(} for details.
+ */
+ public Thread() {
+ super();
+ }
+ /**
+ * See {@link Thread#Thread(ThreadGroup, Runnable)} for details.
+ * @param tg explicit {@link ThreadGroup}, may be {@code null}
+ * @param target explicit {@link Runnable}, may be {@code null}
+ */
+ public Thread(final ThreadGroup tg, final Runnable target) {
+ super(tg, target);
+ }
+ /**
+ * See {@link Thread#Thread(ThreadGroup, Runnable, String)} for details.
+ * @param tg explicit {@link ThreadGroup}, may be {@code null}
+ * @param target explicit {@link Runnable}, may be {@code null}
+ * @param name explicit name of thread, must not be {@code null}
+ */
+ public Thread(final ThreadGroup tg, final Runnable target, final String name) {
+ super(tg, target, name);
+ }
+
+ /**
+ * Depending on whether {@code name} is null, either
+ * {@link #Thread(ThreadGroup, Runnable, String)} or
+ * {@link #Thread(ThreadGroup, Runnable)} is being utilized.
+ * @param tg explicit {@link ThreadGroup}, may be {@code null}
+ * @param target explicit {@link Runnable}, may be {@code null}
+ * @param name explicit name of thread, may be {@code null}
+ */
+ public static Thread create(final ThreadGroup tg, final Runnable target, final String name) {
+ return null != name ? new Thread(tg, target, name) : new Thread(tg, target);
+ }
+
+ @Override
+ public final Throwable getInterruptSource(final boolean clear) {
+ synchronized(sync) {
+ final Throwable r = interruptSource;
+ if( clear ) {
+ clearInterruptSource();
+ }
+ return r;
+ }
+ }
+ @Override
+ public final int getInterruptCounter(final boolean clear) {
+ synchronized(sync) {
+ final int r = interruptCounter;
+ if( clear ) {
+ clearInterruptSource();
+ }
+ return r;
+ }
+ }
+ @Override
+ public final void clearInterruptSource() {
+ synchronized(sync) {
+ interruptCounter = 0;
+ interruptSource = null;
+ }
+ }
+ @Override
+ public final void interrupt() {
+ synchronized(sync) {
+ interruptCounter++;
+ interruptSource = new Throwable(getName()+".interrupt() #"+interruptCounter);
+ }
+ super.interrupt();
+ }
+ }
+}
diff --git a/src/java/com/jogamp/common/util/InterruptedRuntimeException.java b/src/java/com/jogamp/common/util/InterruptedRuntimeException.java
new file mode 100644
index 0000000..af6fea8
--- /dev/null
+++ b/src/java/com/jogamp/common/util/InterruptedRuntimeException.java
@@ -0,0 +1,80 @@
+/**
+ * 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.common.util;
+
+import com.jogamp.common.JogampRuntimeException;
+
+/**
+ * <i>Unchecked exception</i> propagating an {@link InterruptedException}
+ * where handling of the latter is not desired.
+ * <p>
+ * {@link InterruptedRuntimeException} may be thrown either by waiting for any {@link Runnable}
+ * to be completed, or during its execution.
+ * </p>
+ * <p>
+ * The propagated {@link InterruptedException} may be of type {@link SourcedInterruptedException}.
+ * </p>
+ * <p>
+ * </p>
+ */
+@SuppressWarnings("serial")
+public class InterruptedRuntimeException extends JogampRuntimeException {
+
+ /**
+ * Constructor attempts to {@link SourcedInterruptedException#wrap(InterruptedException) wrap}
+ * the given {@link InterruptedException} {@code cause} into a {@link SourcedInterruptedException}.
+ *
+ * @param message the message of this exception
+ * @param cause the propagated {@link InterruptedException}
+ */
+ public InterruptedRuntimeException(final String message, final InterruptedException cause) {
+ super(message, SourcedInterruptedException.wrap(cause));
+ }
+
+ /**
+ * Constructor attempts to {@link SourcedInterruptedException#wrap(InterruptedException) wrap}
+ * the given {@link InterruptedException} {@code cause} into a {@link SourcedInterruptedException}.
+ *
+ * @param cause the propagated {@link InterruptedException}
+ */
+ public InterruptedRuntimeException(final InterruptedException cause) {
+ super(SourcedInterruptedException.wrap(cause));
+ }
+
+ /**
+ * Returns the propagated {@link InterruptedException}, i.e. the cause of this exception.
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ */
+ @Override
+ public InterruptedException getCause() {
+ return (InterruptedException)super.getCause();
+ }
+}
diff --git a/src/java/com/jogamp/common/util/JarUtil.java b/src/java/com/jogamp/common/util/JarUtil.java
index 745dd12..d6c8fd4 100644
--- a/src/java/com/jogamp/common/util/JarUtil.java
+++ b/src/java/com/jogamp/common/util/JarUtil.java
@@ -163,7 +163,7 @@ public class JarUtil {
}
}
}
- if( !uri.scheme.equals( Uri.JAR_SCHEME ) ) {
+ if( !uri.isJarScheme() ) {
throw new IllegalArgumentException("Uri is not using scheme "+Uri.JAR_SCHEME+": <"+uri+">");
}
if(DEBUG) {
@@ -190,7 +190,7 @@ public class JarUtil {
if(null == classJarUri) {
throw new IllegalArgumentException("Uri is null");
}
- if( !classJarUri.scheme.equals(Uri.JAR_SCHEME) ) {
+ if( !classJarUri.isJarScheme() ) {
throw new IllegalArgumentException("Uri is not using scheme "+Uri.JAR_SCHEME+": <"+classJarUri+">");
}
Uri.Encoded ssp = classJarUri.schemeSpecificPart;
@@ -262,7 +262,7 @@ public class JarUtil {
if(null == classJarUri) {
throw new IllegalArgumentException("Uri is null");
}
- if( !classJarUri.scheme.equals(Uri.JAR_SCHEME) ) {
+ if( !classJarUri.isJarScheme() ) {
throw new IllegalArgumentException("Uri is not a using scheme "+Uri.JAR_SCHEME+": <"+classJarUri+">");
}
final Uri.Encoded uriSSP = classJarUri.schemeSpecificPart;
@@ -413,20 +413,6 @@ public class JarUtil {
}
/**
- * See {@link #getRelativeOf(Class, com.jogamp.common.net.Uri.Encoded, com.jogamp.common.net.Uri.Encoded)}.
- * @param classFromJavaJar URI encoded!
- * @param cutOffInclSubDir URI encoded!
- * @param relResPath URI encoded!
- * @return
- * @throws IllegalArgumentException
- * @throws IOException
- * @throws URISyntaxException
- * @deprecated Use {@link #getRelativeOf(Class, com.jogamp.common.net.Uri.Encoded, com.jogamp.common.net.Uri.Encoded)}.
- */
- public static java.net.URI getRelativeOf(final Class<?> classFromJavaJar, final String cutOffInclSubDir, final String relResPath) throws IllegalArgumentException, IOException, URISyntaxException {
- return getRelativeOf(classFromJavaJar, Uri.Encoded.cast(cutOffInclSubDir), Uri.Encoded.cast(relResPath)).toURI();
- }
- /**
* Locates the {@link JarUtil#getJarFileUri(Uri) Jar file Uri} of a given resource
* relative to a given class's Jar's Uri.
* <pre>
diff --git a/src/java/com/jogamp/common/util/JogampVersion.java b/src/java/com/jogamp/common/util/JogampVersion.java
index e9becc6..e06ce1f 100644
--- a/src/java/com/jogamp/common/util/JogampVersion.java
+++ b/src/java/com/jogamp/common/util/JogampVersion.java
@@ -46,6 +46,9 @@ public class JogampVersion {
/** See {@link #getImplementationCommit()} */
public static final Attributes.Name IMPLEMENTATION_COMMIT = new Attributes.Name("Implementation-Commit");
+ /** For FAT JogAmp jar files */
+ private static final String packageNameFAT = "com.jogamp";
+
private final String packageName;
private final Manifest mf;
private final int hash;
@@ -55,12 +58,27 @@ public class JogampVersion {
private final String androidPackageVersionName;
protected JogampVersion(final String packageName, final Manifest mf) {
- this.packageName = packageName;
- this.mf = ( null != mf ) ? mf : new Manifest();
+ if( null != mf ) {
+ // use provided valid data
+ this.mf = mf;
+ this.packageName = packageName;
+ } else {
+ // try FAT jar file
+ final Manifest fatMF = VersionUtil.getManifest(JogampVersion.class.getClassLoader(), packageNameFAT);
+ if( null != fatMF ) {
+ // use FAT jar file
+ this.mf = fatMF;
+ this.packageName = packageNameFAT;
+ } else {
+ // use faulty data, unresolvable ..
+ this.mf = new Manifest();
+ this.packageName = packageName;
+ }
+ }
this.hash = this.mf.hashCode();
mainAttributes = this.mf.getMainAttributes();
mainAttributeNames = mainAttributes.keySet();
- androidPackageVersionName = AndroidUtils.getPackageInfoVersionName(packageName); // null if !Android
+ androidPackageVersionName = AndroidUtils.getPackageInfoVersionName(this.packageName); // null if !Android
}
@Override
diff --git a/src/java/com/jogamp/common/util/RunnableTask.java b/src/java/com/jogamp/common/util/RunnableTask.java
index 6fb98de..2689de1 100644
--- a/src/java/com/jogamp/common/util/RunnableTask.java
+++ b/src/java/com/jogamp/common/util/RunnableTask.java
@@ -30,6 +30,8 @@ package com.jogamp.common.util;
import java.io.PrintStream;
+import com.jogamp.common.JogampRuntimeException;
+
/**
* Helper class to provide a Runnable queue implementation with a Runnable wrapper
* which notifies after execution for the <code>invokeAndWait()</code> semantics.
@@ -38,70 +40,58 @@ public class RunnableTask extends TaskBase {
protected final Runnable runnable;
/**
- * Invokes <code>runnable</code> on the current thread.
- * @param waitUntilDone if <code>true</code>, waits until <code>runnable</code> execution is completed, otherwise returns immediately.
- * @param runnable the {@link Runnable} to execute.
+ * Invokes <code>runnable</code> on the current {@link Thread}.
+ * @param runnable the {@link Runnable} to execute on the current thread.
+ * The runnable <b>must exit</b>, i.e. not loop forever.
+ * @return the newly created and invoked {@link RunnableTask}
+ * @since 2.4.0
*/
- public static void invoke(final boolean waitUntilDone, final Runnable runnable) {
- Throwable throwable = null;
- final Object sync = new Object();
- final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
- synchronized(sync) {
- rt.run();
- if( waitUntilDone ) {
- try {
- sync.wait();
- } catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rt.getThrowable();
- }
- if(null!=throwable) {
- throw new RuntimeException(throwable);
- }
- }
- }
+ public static RunnableTask invokeOnCurrentThread(final Runnable runnable) {
+ final RunnableTask rt = new RunnableTask( runnable, null, false, null );
+ rt.run();
+ return rt;
}
/**
- * Invokes <code>runnable</code> on a new thread belonging to the given {@link ThreadGroup}.
+ * Invokes <code>runnable</code> on a new {@link InterruptSource.Thread},
+ * see {@link InterruptSource.Thread#Thread(ThreadGroup, Runnable, String)} for details.
* @param tg the {@link ThreadGroup} for the new thread, maybe <code>null</code>
+ * @param threadName the name for the new thread, maybe <code>null</code>
* @param waitUntilDone if <code>true</code>, waits until <code>runnable</code> execution is completed, otherwise returns immediately.
* @param runnable the {@link Runnable} to execute on the new thread. If <code>waitUntilDone</code> is <code>true</code>,
- * the runnable <b>must exist</b>, i.e. not loop forever.
- * @param threadName the name for the new thread
- * @return the newly created {@link Thread}
+ * the runnable <b>must exit</b>, i.e. not loop forever.
+ * @return the newly created and invoked {@link RunnableTask}
+ * @since 2.3.2
*/
- public static Thread invokeOnNewThread(final ThreadGroup tg, final boolean waitUntilDone, final Runnable runnable, final String threadName) {
- final Thread t = new Thread(tg, threadName) {
- @Override
- public void run() {
- Throwable throwable = null;
- final Object sync = new Object();
- final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
- synchronized(sync) {
- rt.run();
- if( waitUntilDone ) {
- try {
- sync.wait();
- } catch (final InterruptedException ie) {
- throwable = ie;
- }
- if(null==throwable) {
- throwable = rt.getThrowable();
- }
- if(null!=throwable) {
- throw new RuntimeException(throwable);
- }
+ public static RunnableTask invokeOnNewThread(final ThreadGroup tg, final String threadName,
+ final boolean waitUntilDone, final Runnable runnable) {
+ final RunnableTask rt;
+ if( !waitUntilDone ) {
+ rt = new RunnableTask( runnable, null, true, System.err );
+ final InterruptSource.Thread t = InterruptSource.Thread.create(tg, rt, threadName);
+ t.start();
+ } else {
+ final Object sync = new Object();
+ rt = new RunnableTask( runnable, sync, true, null );
+ final InterruptSource.Thread t = InterruptSource.Thread.create(tg, rt, threadName);
+ synchronized(sync) {
+ t.start();
+ while( rt.isInQueue() ) {
+ try {
+ sync.wait();
+ } catch (final InterruptedException ie) {
+ throw new InterruptedRuntimeException(ie);
+ }
+ final Throwable throwable = rt.getThrowable();
+ if(null!=throwable) {
+ throw new JogampRuntimeException(throwable);
}
}
- } };
- t.start();
- return t;
+ }
+ }
+ return rt;
}
-
/**
* Create a RunnableTask object w/ synchronization,
* ie. suitable for <code>invokeAndWait()</code>, i.e. {@link #invoke(boolean, Runnable) invoke(true, runnable)}.
@@ -126,6 +116,8 @@ public class RunnableTask extends TaskBase {
@Override
public final void run() {
+ execThread = Thread.currentThread();
+
runnableException = null;
tStarted = System.currentTimeMillis();
if(null == syncObject) {
@@ -143,6 +135,7 @@ public class RunnableTask extends TaskBase {
}
} finally {
tExecuted = System.currentTimeMillis();
+ isExecuted = true;
}
} else {
synchronized (syncObject) {
@@ -160,6 +153,7 @@ public class RunnableTask extends TaskBase {
}
} finally {
tExecuted = System.currentTimeMillis();
+ isExecuted = true;
syncObject.notifyAll();
}
}
diff --git a/src/java/com/jogamp/common/util/SourcedInterruptedException.java b/src/java/com/jogamp/common/util/SourcedInterruptedException.java
new file mode 100644
index 0000000..530f1e7
--- /dev/null
+++ b/src/java/com/jogamp/common/util/SourcedInterruptedException.java
@@ -0,0 +1,166 @@
+/**
+ * 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.common.util;
+
+import java.io.PrintStream;
+
+import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.ExceptionUtils.CustomStackTrace;
+
+/**
+ * {@link InterruptedException}, which may include the source, see {@link #getInterruptSource()}.
+ * <p>
+ * This exception may be created directly where {@link #getCause()} returns {@code null},
+ * or by propagating an existing {@link InterruptedException} as returned by {@link #getCause()}.
+ * </p>
+ * @since 2.3.2
+ */
+@SuppressWarnings("serial")
+public class SourcedInterruptedException extends InterruptedException implements CustomStackTrace {
+ final Throwable interruptSource;
+
+ /**
+ * Wraps the given {@link InterruptedException} into a {@link SourcedInterruptedException}
+ * if it is not yet of the desired type and
+ * if the current thread if a {@link InterruptSource}, i.e. the source is known.
+ * <p>
+ * Otherwise the given {@link InterruptedException} instance is returned.
+ * </p>
+ * <p>
+ * In case method is creating a new wrapping instance,
+ * {@link InterruptSource#clearInterruptSource()} is being issued.
+ * </p>
+ *
+ * @param ie the to be wrapped {@link InterruptedException}
+ */
+ public static InterruptedException wrap(final InterruptedException ie) {
+ return wrap(ie, InterruptSource.Util.currentThread());
+ }
+
+ /**
+ * Wraps the given {@link InterruptedException} into a {@link SourcedInterruptedException}
+ * if it is not yet of the same type and if {@code source} is not {@code null}.
+ * <p>
+ * Otherwise the given {@link InterruptedException} instance is returned.
+ * </p>
+ * <p>
+ * In case method is creating a new wrapping instance,
+ * {@link InterruptSource#clearInterruptSource()} is being issued.
+ * </p>
+ *
+ * @param ie the to be wrapped {@link InterruptedException}
+ * @param source the {@link InterruptSource}
+ */
+ public static InterruptedException wrap(final InterruptedException ie, final InterruptSource source) {
+ if( !(ie instanceof SourcedInterruptedException) && null != source ) {
+ return new SourcedInterruptedException(ie, source.getInterruptSource(true));
+ } else {
+ return ie;
+ }
+ }
+
+ /**
+ * @param message mandatory message of this exception
+ * @param cause optional propagated cause
+ * @param interruptSource optional propagated source of {@link Thread#interrupt()} call
+ */
+ public SourcedInterruptedException(final String message, final InterruptedException cause, final Throwable interruptSource) {
+ super(message);
+ if( null != cause ) {
+ initCause(cause);
+ }
+ this.interruptSource = interruptSource;
+ }
+
+ /**
+ * @param cause mandatory propagated cause
+ * @param interruptSource optional propagated source of {@link Thread#interrupt()} call
+ */
+ public SourcedInterruptedException(final InterruptedException cause, final Throwable interruptSource) {
+ super(cause.getMessage());
+ initCause(cause);
+ this.interruptSource = interruptSource;
+ }
+
+ /**
+ * Returns the source of the {@link Thread#interrupt()} call if known,
+ * otherwise {@code null} is returned.
+ */
+ public final Throwable getInterruptSource() {
+ return interruptSource;
+ }
+
+ /**
+ * Returns the propagated {@link InterruptedException}, i.e. the cause of this exception,
+ * or {@code null} if not applicable.
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ */
+ @Override
+ public InterruptedException getCause() {
+ return (InterruptedException)super.getCause();
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(256);
+ sb.append(getClass().getSimpleName()).append(": ");
+ if (null != interruptSource) {
+ sb.append("[sourced]");
+ } else {
+ sb.append("[unknown]");
+ }
+ final String m = getLocalizedMessage();
+ if( null != m ) {
+ sb.append(" ").append(m);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public final void printCauseStack(final PrintStream s, final String causeStr, final int causeIdx, final int stackDepth) {
+ final String s0 = causeStr+"["+causeIdx+"]";
+ s.println(s0+" by "+getClass().getSimpleName()+": "+getMessage()+" on thread "+Thread.currentThread().getName());
+ ExceptionUtils.dumpStack(s, getStackTrace(), 0, stackDepth);
+ if( null != interruptSource ) {
+ ExceptionUtils.printCause(s, s0, interruptSource, 0, 1, stackDepth);
+ }
+ }
+
+ @Override
+ public final void printStackTrace(final PrintStream s, final int causeDepth, final int stackDepth) {
+ s.println(getClass().getSimpleName()+": "+getMessage()+" on thread "+Thread.currentThread().getName());
+ ExceptionUtils.dumpStack(s, getStackTrace(), 0, stackDepth);
+ ExceptionUtils.printCause(s, "Caused", getCause(), 0, causeDepth, stackDepth);
+ if( null != interruptSource ) {
+ ExceptionUtils.printCause(s, "InterruptSource", interruptSource, 0, causeDepth, stackDepth);
+ }
+ }
+}
diff --git a/src/java/com/jogamp/common/util/TaskBase.java b/src/java/com/jogamp/common/util/TaskBase.java
index 59b86c3..64a8313 100644
--- a/src/java/com/jogamp/common/util/TaskBase.java
+++ b/src/java/com/jogamp/common/util/TaskBase.java
@@ -54,17 +54,29 @@ public abstract class TaskBase implements Runnable {
protected Throwable runnableException;
protected long tCreated, tStarted;
protected volatile long tExecuted;
+ protected volatile boolean isExecuted;
protected volatile boolean isFlushed;
+ protected volatile Thread execThread;
+ /**
+ * @param syncObject The synchronization object if caller wait until <code>runnable</code> execution is completed,
+ * or <code>null</code> if waiting is not desired.
+ * @param catchExceptions Influence an occurring exception during <code>runnable</code> execution.
+ * If <code>true</code>, the exception is silenced and can be retrieved via {@link #getThrowable()},
+ * otherwise the exception is thrown.
+ * @param exceptionOut If not <code>null</code>, exceptions are written to this {@link PrintStream}.
+ */
protected TaskBase(final Object syncObject, final boolean catchExceptions, final PrintStream exceptionOut) {
this.syncObject = syncObject;
this.catchExceptions = catchExceptions;
this.exceptionOut = exceptionOut;
this.sourceStack = TRACE_SOURCE ? new Throwable("Creation @") : null;
- tCreated = System.currentTimeMillis();
- tStarted = 0;
- tExecuted = 0;
- isFlushed = false;
+ this.tCreated = System.currentTimeMillis();
+ this.tStarted = 0;
+ this.tExecuted = 0;
+ this.isExecuted = false;
+ this.isFlushed = false;
+ this.execThread = null;
}
protected final String getExceptionOutIntro() {
@@ -77,6 +89,14 @@ public abstract class TaskBase implements Runnable {
}
/**
+ * Returns the execution thread or {@code null} if not yet {@link #run()}.
+ * @since 2.3.2
+ */
+ public final Thread getExecutionThread() {
+ return execThread;
+ }
+
+ /**
* Return the synchronization object if any.
* @see #RunnableTask(Runnable, Object, boolean)
*/
@@ -126,12 +146,12 @@ public abstract class TaskBase implements Runnable {
/**
* @return !{@link #isExecuted()} && !{@link #isFlushed()}
*/
- public final boolean isInQueue() { return 0 != tExecuted && !isFlushed; }
+ public final boolean isInQueue() { return !isExecuted && !isFlushed; }
/**
* @return True if executed, otherwise false;
*/
- public final boolean isExecuted() { return 0 != tExecuted ; }
+ public final boolean isExecuted() { return isExecuted; }
/**
* @return True if flushed, otherwise false;
@@ -159,7 +179,16 @@ public abstract class TaskBase implements Runnable {
@Override
public String toString() {
- return "RunnableTask[executed "+isExecuted()+", tTotal "+getDurationTotal()+" ms, tExec "+getDurationInExec()+" ms, tQueue "+getDurationInQueue()+" ms, attachment "+attachment+", throwable "+getThrowable()+"]";
+ final String etn;
+ final String eth;
+ if( null != execThread ) {
+ etn = execThread.getName();
+ eth = "0x"+Integer.toHexString(execThread.hashCode());
+ } else {
+ etn = "n/a";
+ eth = "n/a";
+ }
+ return "RunnableTask[enqueued "+isInQueue()+"[executed "+isExecuted()+", flushed "+isFlushed()+", thread["+eth+", "+etn+"]], tTotal "+getDurationTotal()+" ms, tExec "+getDurationInExec()+" ms, tQueue "+getDurationInQueue()+" ms, attachment "+attachment+", throwable "+getThrowable()+"]";
}
}
diff --git a/src/java/com/jogamp/common/util/bin/exe-windows-i386.defl b/src/java/com/jogamp/common/util/bin/exe-windows-i386.defl
new file mode 100644
index 0000000..d8f1716
--- /dev/null
+++ b/src/java/com/jogamp/common/util/bin/exe-windows-i386.defl
Binary files differ
diff --git a/src/java/com/jogamp/common/util/bin/exe-windows-i586-268b.bin b/src/java/com/jogamp/common/util/bin/exe-windows-i586-268b.bin
deleted file mode 100644
index b0d5f63..0000000
--- a/src/java/com/jogamp/common/util/bin/exe-windows-i586-268b.bin
+++ /dev/null
Binary files differ
diff --git a/src/java/com/jogamp/common/util/bin/exe-windows-x86_64.defl b/src/java/com/jogamp/common/util/bin/exe-windows-x86_64.defl
new file mode 100644
index 0000000..be0998b
--- /dev/null
+++ b/src/java/com/jogamp/common/util/bin/exe-windows-x86_64.defl
Binary files differ
diff --git a/src/java/com/jogamp/common/util/cache/TempFileCache.java b/src/java/com/jogamp/common/util/cache/TempFileCache.java
index 24f0237..44c7a11 100644
--- a/src/java/com/jogamp/common/util/cache/TempFileCache.java
+++ b/src/java/com/jogamp/common/util/cache/TempFileCache.java
@@ -35,6 +35,7 @@ import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.InterruptSource;
import jogamp.common.Debug;
@@ -238,7 +239,7 @@ public class TempFileCache {
// Add shutdown hook to cleanup the OutputStream, FileChannel,
// and FileLock for the jlnNNNN.lck and jlnNNNN.lck files.
// We do this so that the locks never get garbage-collected.
- Runtime.getRuntime().addShutdownHook(new Thread() {
+ Runtime.getRuntime().addShutdownHook(new InterruptSource.Thread() {
/* @Override */
@Override
public void run() {
@@ -265,7 +266,7 @@ public class TempFileCache {
}
// Start a new Reaper thread to do stuff...
- final Thread reaperThread = new Thread() {
+ final Thread reaperThread = new InterruptSource.Thread() {
/* @Override */
@Override
public void run() {
diff --git a/src/java/com/jogamp/common/util/cache/TempJarCache.java b/src/java/com/jogamp/common/util/cache/TempJarCache.java
index ed69ddc..2ff5140 100644
--- a/src/java/com/jogamp/common/util/cache/TempJarCache.java
+++ b/src/java/com/jogamp/common/util/cache/TempJarCache.java
@@ -273,19 +273,6 @@ public class TempJarCache {
}
/**
- * See {@link #addResources(Class, Uri)}
- * @param certClass
- * @param jarURI
- * @throws IOException
- * @throws SecurityException
- * @throws IllegalArgumentException
- * @throws URISyntaxException
- * @deprecated Use {@link #addResources(Class, Uri)}
- */
- public synchronized static final void addResources(final Class<?> certClass, final java.net.URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
- addResources(certClass, Uri.valueOf(jarURI));
- }
- /**
* Adds native resources, if not yet added.
*
* @param certClass if class is certified, the JarFile entries needs to have the same certificate
@@ -421,14 +408,6 @@ public class TempJarCache {
return null;
}
- /**
- * See {@link #getResourceUri(String)}
- * @deprecated Use {@link #getResourceUri(String)}
- */
- public synchronized static final java.net.URI getResource(final String name) throws URISyntaxException {
- return getResourceUri(name).toURI();
- }
-
/** Similar to {@link ClassLoader#getResource(String)}. */
public synchronized static final Uri getResourceUri(final String name) throws URISyntaxException {
checkInitialized();
diff --git a/src/java/com/jogamp/gluegen/ASTLocusTag.java b/src/java/com/jogamp/gluegen/ASTLocusTag.java
new file mode 100644
index 0000000..aea7699
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/ASTLocusTag.java
@@ -0,0 +1,99 @@
+/**
+ * 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;
+
+/**
+ * An AST location tag.
+ */
+public class ASTLocusTag {
+ /** Source object, might be {@link String}. */
+ public final Object source;
+ /** Line number, {@code -1} if undefined */
+ public final int line;
+ /** Column number, {@code -1} if undefined */
+ public final int column;
+ /** Source text reflecting current location, {@code null} if undefined */
+ public final String text;
+
+ public ASTLocusTag(final Object source, final int line, final int column, final String text) {
+ this.source = source;
+ this.line = line;
+ this.column = column;
+ this.text = text;
+ }
+
+ public String toString() {
+ return toString(new StringBuilder(), null, true).toString();
+ }
+ public StringBuilder toString(final StringBuilder sb, final String level, final boolean inclText) {
+ boolean preCol = false;
+ if (source != null) {
+ sb.append(source);
+ preCol = true;
+ }
+ if (line != -1) {
+ if( preCol ) {
+ sb.append(":");
+ } else {
+ sb.append("line ");
+ }
+ sb.append(line);
+ if (column != -1) {
+ sb.append(":" + column);
+ }
+ preCol = true;
+ }
+ if( null != level && level.length()>0 ) {
+ if( preCol ) {
+ sb.append(": ");
+ }
+ sb.append(level);
+ preCol = true;
+ }
+ if( inclText && null != text && text.length()>0 ) {
+ if( preCol ) {
+ sb.append(": ");
+ } else {
+ sb.append("text ");
+ }
+ sb.append("'").append(text).append("'");
+ }
+ return sb;
+ }
+
+ /**
+ * Interface tag for {@link ASTLocusTag} provider.
+ */
+ public static interface ASTLocusTagProvider {
+ /**
+ * Returns this instance's {@link ASTLocusTag}, if available,
+ * otherwise returns {@code null}.
+ */
+ ASTLocusTag getASTLocusTag();
+ }
+}
diff --git a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
index 93a1ecc..7c88c37 100644
--- a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
@@ -44,20 +44,20 @@ import java.io.*;
import java.text.MessageFormat;
import com.jogamp.common.os.MachineDataInfo;
+import com.jogamp.gluegen.Logging.LoggerIf;
import com.jogamp.gluegen.cgram.types.*;
-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 LoggerIf LOG;
+
protected MethodBinding binding;
/** Name of the package in which the corresponding Java method resides.*/
@@ -124,9 +124,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(), CMethodBindingEmitter.class.getSimpleName());
assert(binding != null);
assert(javaClassName != null);
@@ -148,8 +150,21 @@ public class CMethodBindingEmitter extends FunctionEmitter {
public final MethodBinding getBinding() { return binding; }
@Override
- public String getName() {
- return binding.getName();
+ public String getInterfaceName() {
+ return binding.getInterfaceName();
+ }
+ @Override
+ public String getImplName() {
+ return binding.getImplName();
+ }
+ @Override
+ public String getNativeName() {
+ return binding.getNativeName();
+ }
+
+ @Override
+ public FunctionSymbol getCSymbol() {
+ return binding.getCSymbol();
}
/**
@@ -306,12 +321,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
writer.print("_");
if (isOverloadedBinding) {
writer.print(jniMangle(binding));
- //System.err.println("OVERLOADED MANGLING FOR " + getName() +
- // " = " + jniMangle(binding));
} else {
- writer.print(JavaEmitter.jniMangle(getName()));
- //System.err.println(" NORMAL MANGLING FOR " + binding.getName() +
- // " = " + jniMangle(getName()));
+ writer.print(JavaEmitter.jniMangle(getImplName()));
}
}
@@ -450,8 +461,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
final JavaType javaReturnType = binding.getJavaReturnType();
if (!cReturnType.isVoid()) {
writer.print(" ");
- // Note we must respect const/volatile for return argument
- writer.print(binding.getCSymbol().getReturnType().getName(true));
+ // Note we respect const/volatile in the function return type.
+ // However, we cannot have it 'const' for our local variable.
+ // See cast in emitBodyCallCFunction(..)!
+ writer.print(binding.getCSymbol().getReturnType().getCName(false));
writer.println(" _res;");
if (javaReturnType.isNIOByteBufferArray() ||
javaReturnType.isArrayOfCompoundTypeWrappers()) {
@@ -569,7 +582,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);
@@ -595,14 +608,14 @@ public class CMethodBindingEmitter extends FunctionEmitter {
//
// Note that we properly handle only the case of an array of
// compound type wrappers in emitBodyVariablePostCallCleanup below
- if (!isBaseTypeConst(cArgType) &&
+ if (!cArgType.isBaseTypeConst() &&
!javaArgType.isArrayOfCompoundTypeWrappers()) {
// FIXME: if the arg type is non-const, the sematics might be that
// the function modifies the argument -- we don't yet support
// this.
- throw new RuntimeException(
- "Cannot copy data for ptr-to-ptr arg type \"" + cArgType +
- "\": support for non-const ptr-to-ptr types not implemented.");
+ throw new GlueGenException(
+ "Cannot copy data for ptr-to-ptr arg type \"" + cArgType.getDebugString() +
+ "\": support for non-const ptr-to-ptr types not implemented: "+binding, binding.getCSymbol().getASTLocusTag());
}
writer.println();
@@ -646,16 +659,17 @@ public class CMethodBindingEmitter extends FunctionEmitter {
error = 100;
}
if( 0 < error ) {
- throw new RuntimeException(
- "Could not copy data for type \"" + cArgType +
- "\"; currently only pointer- and array-types are supported. (error "+error+")");
+ throw new GlueGenException(
+ "Could not copy data for type \"" + cArgType.getDebugString() +
+ "\"; currently only pointer- and array-types are supported. (error "+error+"): "+binding,
+ binding.getCSymbol().getASTLocusTag());
}
}
emitMalloc(
writer,
convName+"_copy",
- cArgElementType.getName(),
- isBaseTypeConst(cArgType),
+ cArgElementType.getCName(),
+ cArgType.isBaseTypeConst(),
arrayLenName,
"Could not allocate buffer for copying data in argument \\\""+javaArgName+"\\\"");
@@ -692,7 +706,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,13 +716,14 @@ 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);
} else {
if( null == cArgElementType2 ) {
- throw new RuntimeException("XXX: Type "+cArgType+" not properly handled as ptr-to-ptr");
+ throw new GlueGenException("XXX: Type "+cArgType.getDebugString()+" not properly handled as ptr-to-ptr: "+binding,
+ binding.getCSymbol().getASTLocusTag());
}
// Question: do we always need to copy the sub-arrays, or just
// GetPrimitiveArrayCritical on each jobjectarray element and
@@ -719,14 +734,15 @@ public class CMethodBindingEmitter extends FunctionEmitter {
emitMalloc(
writer,
convName+"_copy[_copyIndex]",
- cArgElementType2.getName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !!
- isBaseTypeConst(cArgType),
+ cArgElementType2.getCName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !!
+ cArgType.isBaseTypeConst(),
"(*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() +
- "\"; need to add support for copying ptr-to-ptr-to-primitiveType subarrays");
+ throw new GlueGenException("Cannot yet handle type \"" + cArgType.getDebugString() +
+ "\"; need to add support for copying ptr-to-ptr-to-primitiveType subarrays: "+binding,
+ binding.getCSymbol().getASTLocusTag());
}
}
@@ -781,7 +797,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
writer.println(" if ( JNI_FALSE == " + isNIOArgName(i) + " && NULL != " + javaArgName + " ) {");
// Release array
- final String modeFlag = isBaseTypeConst(cArgType) ? "JNI_ABORT" : "0" ;
+ final String modeFlag = cArgType.isBaseTypeConst() ? "JNI_ABORT" : "0" ;
writer.print(" (*env)->ReleasePrimitiveArrayCritical(env, " + javaArgName + ", " + convName + ", "+modeFlag+");");
} else {
writer.println(" if ( NULL != " + javaArgName + " ) {");
@@ -792,7 +808,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
//
// FIXME: should factor out this whole block of code into a separate
// method for clarity and maintenance purposes
- if (!isBaseTypeConst(cArgType)) {
+ if (!cArgType.isBaseTypeConst()) {
// FIXME: handle any cleanup from treatment of non-const args,
// assuming they were treated differently in
// emitBodyVariablePreCallSetup() (see the similar section in that
@@ -804,15 +820,16 @@ 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);
writer.println(" }");
} else {
- throw new RuntimeException(
- "Cannot clean up copied data for ptr-to-ptr arg type \"" + cArgType +
- "\": support for cleaning up most non-const ptr-to-ptr types not implemented.");
+ throw new GlueGenException(
+ "Cannot clean up copied data for ptr-to-ptr arg type \"" + cArgType.getDebugString() +
+ "\": support for cleaning up most non-const ptr-to-ptr types not implemented.",
+ binding.getCSymbol().getASTLocusTag());
}
}
@@ -833,9 +850,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
// free each element
final PointerType cArgPtrType = cArgType.asPointer();
if (cArgPtrType == null) {
- throw new RuntimeException(
- "Could not copy data for type \"" + cArgType +
- "\"; currently only pointer types supported.");
+ throw new GlueGenException(
+ "Could not copy data for type \"" + cArgType.getDebugString() +
+ "\"; currently only pointer types supported.",
+ binding.getCSymbol().getASTLocusTag());
}
// process each element in the array
@@ -854,9 +872,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
writer.print(convName+"_copy[_copyIndex]");
writer.println(");");
} else {
- if (true) throw new RuntimeException(
- "Cannot yet handle type \"" + cArgType.getName() +
- "\"; need to add support for cleaning up copied ptr-to-ptr-to-primitiveType subarrays");
+ throw new GlueGenException(
+ "Cannot yet handle type \"" + cArgType.getDebugString() +
+ "\"; need to add support for cleaning up copied ptr-to-ptr-to-primitiveType subarrays",
+ binding.getCSymbol().getASTLocusTag());
}
writer.println(" }");
}
@@ -915,20 +934,9 @@ public class CMethodBindingEmitter extends FunctionEmitter {
javaArgType.isArray() ||
javaArgType.isArrayOfCompoundTypeWrappers() ||
( javaArgType.isNIOBuffer() && forIndirectBufferAndArrayImplementation ) );
- if (isBaseTypeConst(cArgType)) {
- writer.print("const ");
- }
-
- // if this is a pointer to an unsigned type, add unsigned to the name to avoid compiler warnings
- if(cArgType.isPointer()) {
- final Type baseType = cArgType.getBaseElementType();
- if(baseType.isInt() && (((IntType)baseType).isPrimitiveUnsigned())) {
- writer.print("unsigned ");
- }
- }
-
- writer.print(cArgType.getName());
+ writer.print(cArgType.getCName(true));
writer.print(") ");
+
if (cArgType.isPointer() && javaArgType.isPrimitive()) {
writer.print("(intptr_t) ");
}
@@ -975,13 +983,18 @@ public class CMethodBindingEmitter extends FunctionEmitter {
final Type cReturnType = binding.getCReturnType();
if (!cReturnType.isVoid()) {
- writer.print("_res = ");
+ // Note we respect const/volatile in the function return type.
+ // However, we cannot have it 'const' for our local variable.
+ // See return type in emitBodyVariableDeclarations(..)!
+ writer.print("_res = (");
+ writer.print(cReturnType.getCName(false));
+ writer.print(") ");
}
if ( isCStructFunctionPointer && binding.hasContainingType() ) {
// Call through function pointer
writer.print(CMethodBindingEmitter.cThisArgumentName() + "->");
}
- writer.print(binding.getCSymbol().getName());
+ writer.print(getNativeName());
writer.print("(");
emitBodyPassCArguments(writer);
writer.println(");");
@@ -1020,7 +1033,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,36 +1042,76 @@ 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.isAnon() &&
+ cReturnTargetType.asCompound().getNumFields() > 0 )
+ {
+ // fully declared non-anonymous struct pointer: pass content
+ if ( cReturnTargetType.getSize() == null ) {
+ throw new GlueGenException(
+ "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.getCSymbol(),
+ binding.getCSymbol().getASTLocusTag()
+ );
+ }
+ 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) ) { // javaReturnType.isOpaqued() covered above via isPrimitive()
+ // 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(binding.getCSymbol().getASTLocusTag(),
+ "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);");
+ writer.println(" return (*env)->NewStringUTF(env, (const char *)_res);");
} else if (javaReturnType.isArrayOfCompoundTypeWrappers() ||
(javaReturnType.isArray() && javaReturnType.isNIOByteBufferArray())) {
writer.println(" if (NULL == _res) return NULL;");
if (returnValueLengthExpression == null) {
- throw new RuntimeException("Error while generating C code: no length specified for array returned from function " +
- binding);
+ throw new GlueGenException("Error while generating C code: no length specified for array returned from function " +
+ binding, binding.getCSymbol().getASTLocusTag());
}
writer.println(" " + arrayResLength + " = " + returnValueLengthExpression.format(argumentNameArray()) + ";");
writer.println(" " + arrayRes + " = (*env)->NewObjectArray(env, " + arrayResLength + ", (*env)->FindClass(env, \"java/nio/ByteBuffer\"), NULL);");
@@ -1071,7 +1124,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()) {
@@ -1080,9 +1133,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
// expression which computes the array size (already present
// as ReturnValueCapacity, not yet implemented / tested here)
- throw new RuntimeException(
+ throw new GlueGenException(
"Could not emit native code for function \"" + binding +
- "\": array return values for non-char types not implemented yet, for "+binding);
+ "\": array return values for non-char types not implemented yet, for "+binding,
+ binding.getCSymbol().getASTLocusTag());
// FIXME: This is approximately what will be required here
//
@@ -1104,8 +1158,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
//writer.print(arrayRes);
//writer.println(";");
} else {
- System.err.print("Unhandled return type: "+javaReturnType.getDebugString());
- throw new RuntimeException("Unhandled return type: "+javaReturnType.getDebugString()+" for "+binding);
+ throw new GlueGenException("Unhandled return type: "+javaReturnType.getDebugString()+" for "+binding,
+ binding.getCSymbol().getReturnType().getASTLocusTag());
}
}
}
@@ -1116,7 +1170,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
protected String jniMangle(final MethodBinding binding) {
final StringBuilder buf = new StringBuilder();
- buf.append(JavaEmitter.jniMangle(getName()));
+ buf.append(JavaEmitter.jniMangle(getImplName()));
buf.append(getImplSuffix());
buf.append("__");
if (binding.hasContainingType()) {
@@ -1132,7 +1186,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
// We should only see "void" as the first argument of a 1-argument function
// FIXME: should normalize this in the parser
if ((i != 0) || (binding.getNumArguments() > 1)) {
- throw new RuntimeException("Saw illegal \"void\" argument while emitting \"" + getName() + "\"");
+ throw new GlueGenException("Saw illegal \"void\" argument while emitting arg "+i+" of "+binding,
+ binding.getCArgumentType(i).getASTLocusTag());
}
} else {
Class<?> c = type.getJavaClass();
@@ -1164,7 +1219,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
// These are not exposed at the Java level
} else {
// FIXME: add support for char* -> String conversion
- throw new RuntimeException("Unknown kind of JavaType: name="+type.getName());
+ throw new GlueGenException("Unknown kind of JavaType: arg "+i+", name="+type.getName()+" of "+binding,
+ binding.getCArgumentType(i).getASTLocusTag());
}
}
}
@@ -1225,7 +1281,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
writer.println(" (*env)->ThrowNew(env, (*env)->FindClass(env, \"java/lang/OutOfMemoryError\"),");
writer.print(" \"" + errorMessage);
writer.print(" in native dispatcher for \\\"");
- writer.print(getName());
+ writer.print(getInterfaceName());
writer.println("\\\"\");");
writer.print(" return");
if (!binding.getJavaReturnType().isVoid()) {
@@ -1386,33 +1442,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 GlueGenException("Unsupported pointer type: \"" + cType.getDebugString() + "\"", cType.getASTLocusTag());
}
} 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 GlueGenException("Unsupported pointer type: \"" + cType.getDebugString() + "\"", cType.getASTLocusTag());
}
}
} else {
- ptrTypeString = cType.getName();
+ ptrTypeString = cType.getCName();
}
writer.print(" ");
@@ -1434,14 +1491,14 @@ 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)) {
+ if (cType.isBaseTypeConst()) {
writer.print("const ");
}
writer.print(cElementTypeName+" *");
} else {
- if (isBaseTypeConst(cType)) {
+ if (cType.isBaseTypeConst()) {
writer.print("const ");
}
writer.print(ptrTypeString);
@@ -1470,9 +1527,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..675c6d7 100644
--- a/src/java/com/jogamp/gluegen/ConstantDefinition.java
+++ b/src/java/com/jogamp/gluegen/ConstantDefinition.java
@@ -1,71 +1,481 @@
-/*
- * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
+/**
+ * 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:
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
*
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
*
- * - Redistribution 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.
+ * 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.
*
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any kind. ALL
- * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
- * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
- * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
- * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
- * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
- * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
- * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
- * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
- * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * 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 java.util.*;
+import java.math.BigInteger;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+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 a [native] constant expression,
+ * comprises the [native] expression, see {@link #getNativeExpr()}
+ * and the optional {@link CNumber} representation, see {@link #getNumber()}.
+ * <p>
+ * The representation of the equivalent java expression including
+ * the result type is covered by {@link JavaExpr},
+ * which can be computed via {@link #computeJavaExpr(Map)}.
+ * </p>
+ * <p>
+ * This class and its sub-classes define and convert all native expressions
+ * to Java space.
+ * </p>
+ */
+public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSemanticSymbol, ASTLocusTagProvider {
+ public static final long UNSIGNED_INT_MAX_VALUE = 0xffffffffL;
+ public static final BigInteger UNSIGNED_LONG_MAX_VALUE = new BigInteger("ffffffffffffffff", 16);
+
+ /**
+ * A Number, either integer, optionally [long, unsigned],
+ * or floating point, optionally [double].
+ */
+ public static class CNumber {
+ /**
+ * {@code true} if number is integer and value stored in {@link #i},
+ * otherwise {@code false} for floating point and value stored in {@link #f}.
+ */
+ public final boolean isInteger;
+ /** {@code true} if number is a {@code long} {@link #isInteger}. */
+ public final boolean isLong;
+ /** {@code true} if number is an {@code unsigned} {@link #isInteger}. */
+ public final boolean isUnsigned;
+ /** The value if {@link #isInteger} */
+ public final long i;
+
+ /** {@code true} if number is a {@code double precision} {@code floating point}, i.e. !{@link #isInteger}. */
+ public final boolean isDouble;
+ /** The value if !{@link #isInteger} */
+ public final double f;
+
+ /** ctor for integer number */
+ public CNumber(final boolean isLong, final boolean isUnsigned, final long value) {
+ this.isInteger = true;
+ this.isLong = isLong;
+ this.isUnsigned = isUnsigned;
+ this.i = value;
+ this.isDouble = false;
+ this.f = 0.0;
+ }
+ /** ctor for floating point number */
+ public CNumber(final boolean isDouble, final double value) {
+ this.isInteger = false;
+ this.isLong = false;
+ this.isUnsigned = false;
+ this.i = 0;
+ this.isDouble = isDouble;
+ this.f = value;
+ }
+ @Override
+ public int hashCode() {
+ return isInteger ? Long.valueOf(i).hashCode() : Double.valueOf(f).hashCode();
+ }
+ @Override
+ public boolean equals(final Object arg) {
+ if (arg == this) {
+ return true;
+ } else if ( !(arg instanceof CNumber) ) {
+ return false;
+ }
+ final CNumber t = (CNumber) arg;
+ return isInteger == t.isInteger &&
+ ( isInteger ? i == t.i : f == t.f );
+ }
+ public final String toJavaString() {
+ if( isInteger ) {
+ if( i >= 0 || isUnsigned ) {
+ if( isLong ) {
+ return "0x"+Long.toHexString(i)+"L";
+ } else {
+ return "0x"+Integer.toHexString((int)i);
+ }
+ } else {
+ if( isLong ) {
+ return String.valueOf(i)+"L";
+ } else {
+ return String.valueOf((int)i);
+ }
+ }
+ } else {
+ return String.valueOf(f) + ( !isDouble ? "f" : "");
+ }
+ }
+ public final String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ if( isInteger ) {
+ if( isUnsigned ) {
+ sb.append("unsigned ");
+ }
+ if( isLong) {
+ sb.append("long: ");
+ } else {
+ sb.append("int: ");
+ }
+ sb.append(i);
+ } else {
+ if( isDouble ) {
+ sb.append("double: ");
+ } else {
+ sb.append("float: ");
+ }
+ sb.append(f);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+ }
+
+ /**
+ * A valid java expression, including its result type,
+ * usually generated from a native [C] expression,
+ * see {@link JavaExpr#create(ConstantDefinition)}.
+ */
+ public static class JavaExpr {
+ public final String javaExpression;
+ public final CNumber resultType;
+ public final Number resultJavaType;
+ public final String resultJavaTypeName;
+ public JavaExpr(final String javaExpression, final CNumber resultType) {
+ this.javaExpression = javaExpression;
+ this.resultType = resultType;
+ if( resultType.isDouble ) {
+ resultJavaTypeName = "double";
+ resultJavaType = Double.valueOf(resultType.f);
+ } else if( !resultType.isInteger ) {
+ resultJavaTypeName = "float";
+ resultJavaType = Double.valueOf(resultType.f).floatValue();
+ } else if( resultType.isLong ) {
+ resultJavaTypeName = "long";
+ resultJavaType = Long.valueOf(resultType.i);
+ } else /* if( resultType.isInteger ) */ {
+ resultJavaTypeName = "int";
+ resultJavaType = Long.valueOf(resultType.i).intValue();
+ }
+ }
+ /**
+ * Computes a valid {@link JavaExpr java expression} based on the given {@link ConstantDefinition},
+ * which may either be a single {@link CNumber}, see {@link ConstantDefinition#getNumber()},
+ * or represents a native expression, see {@link ConstantDefinition#getExpr()}.
+ */
+ public static JavaExpr compute(final ConstantDefinition constDef,
+ final Map<String, ConstantDefinition.JavaExpr> constMap) {
+ final boolean debug = GlueGen.debug();
+ if( debug ) {
+ System.err.println("ConstJavaExpr.create: "+constDef);
+ }
+ if( constDef.hasNumber() ) {
+ // Already parsed as CNumber completely!
+ if( debug ) {
+ System.err.printf("V %s (isCNumber)%n", constDef);
+ }
+ return new JavaExpr(constDef.getNumber().toJavaString(), constDef.getNumber());
+ }
+ final StringBuilder javaExpr = new StringBuilder();
+ final String nativeExpr = constDef.getNativeExpr();
-/** Represents the definition of a constant which was provided either
- via a #define statement or through an enum definition. */
-public class ConstantDefinition {
+ // "calculates" the result type of a simple expression
+ // example: (2+3)-(2.0f-3.0) -> Double
+ // example: (1 << 2) -> Integer
+ CNumber resultType = null;
+ final Matcher matcher = patternCPPOperand.matcher(nativeExpr);
+ int preStartIdx = 0;
+ int opEndIdx = 0;
+ while ( matcher.find() ) {
+ final int opStartIdx = matcher.start();
+ if( opStartIdx > preStartIdx ) {
+ final String sValue = nativeExpr.substring(preStartIdx, opStartIdx).trim();
+ if( sValue.length() > 0 ) {
+ if( debug ) {
+ System.err.printf("V %03d-%03d: %s%n", preStartIdx, opStartIdx, sValue);
+ }
+ resultType = processValue(constDef, sValue, constMap, resultType, javaExpr);
+ javaExpr.append(" ");
+ }
+ }
+ opEndIdx = matcher.end();
+ final String op = nativeExpr.substring(opStartIdx, opEndIdx);
+ if( debug ) {
+ System.err.printf("O %03d-%03d: %s%n", opStartIdx, opEndIdx, op);
+ }
+ javaExpr.append(op).append(" ");
+ preStartIdx = opEndIdx;
+ }
+ if( opEndIdx < nativeExpr.length() ) {
+ // tail ..
+ final String sValue = nativeExpr.substring(opEndIdx).trim();
+ if( sValue.length() > 0 ) {
+ if( debug ) {
+ System.err.printf("V %03d %03d-%03d: %s (tail)%n", preStartIdx, opEndIdx, nativeExpr.length(), sValue);
+ }
+ resultType = processValue(constDef, sValue, constMap, resultType, javaExpr);
+ }
+ }
+ final String javaExprS = javaExpr.toString().trim();
+ if( null == resultType ) {
+ throw new GlueGenException("Cannot emit const \""+constDef.getName()+"\": value \""+nativeExpr+
+ "\", parsed \""+javaExprS+"\" does not contain a constant number", constDef.getASTLocusTag());
+ }
+ return new JavaExpr(javaExprS, resultType);
+ }
+ private static CNumber processValue(final ConstantDefinition constDef,
+ final String sValue,
+ final Map<String, ConstantDefinition.JavaExpr> constMap,
+ CNumber resultType,
+ final StringBuilder javaExpr) {
+ final CNumber nValue = getANumber(constDef, sValue);
+ if( null != nValue ) {
+ resultType = evalType(resultType , nValue);
+ javaExpr.append(nValue.toJavaString());
+ } else {
+ // Lookup CNumber type in const-map, to evaluate this result type
+ final JavaExpr cje = constMap.get(sValue);
+ if( null != cje ) {
+ resultType = evalType(resultType , cje.resultType);
+ }
+ javaExpr.append(sValue);
+ }
+ return resultType;
+ }
+ private static CNumber getANumber(final ConstantDefinition constDef, final String value) {
+ try {
+ final CNumber number = decodeANumber(value);
+ if( null != number ) {
+ return number;
+ }
+ } catch( final Throwable _t ) {
+ final String msg = "Cannot emit const \""+constDef.getName()+"\": value \""+value+
+ "\" cannot be assigned to a int, long, float, or double";
+ throw new GlueGenException(msg, constDef.getASTLocusTag(), _t);
+ }
+ return null;
+ }
+ private static CNumber evalType(final CNumber resultType, final CNumber type) {
+ //fast path
+ if( type.isDouble ) {
+ return type;
+ }
+ if( null != resultType ) {
+ if( resultType.isInteger ) {
+ if( resultType.isLong ) {
+ /* resultType is Long */
+ if( !type.isInteger ) {
+ /* resultType: Long -> [ Float || Double ] */
+ return type;
+ }
+ } else if( type.isLong || !type.isInteger ) {
+ /* resultType: Integer -> [ Long || Float || Double ] */
+ return type;
+ }
+ } else if( !resultType.isInteger && !resultType.isDouble ) {
+ if( type.isDouble ) {
+ /* resultType: Float -> Double */
+ return type;
+ }
+ }
+ } else {
+ return type;
+ }
+ return resultType;
+ }
+ }
- private final String origName;
- private final HashSet<String> aliasedNames;
- private String name;
- private final String value;
+ private final boolean relaxedEqSem;
+ private final String nativeExpr;
+ private final CNumber number;
private final boolean isEnum;
private final String enumName;
- private Set<String> aliases;
+ private final ASTLocusTag astLocus;
+ /**
+ * Constructor for plain const-values, non-enumerates.
+ * @param name unique name of this constant expression
+ * @param nativeExpr original [native] expression
+ * @param number optional {@link CNumber} representing this constant.
+ * If {@code null}, implementation attempts to derive a {@link CNumber}
+ * of the given {@code nativeExpr}.
+ * @param astLocus AST location of the represented constant.
+ */
+ public ConstantDefinition(final String name,
+ final String nativeExpr,
+ final CNumber number,
+ final ASTLocusTag astLocus) {
+ this(name, nativeExpr, number, false, null, astLocus);
+ }
+ /**
+ * Constructor for enumerates
+ * @param name unique name of this constant expression
+ * @param nativeExpr original [native] expression
+ * @param number optional {@link CNumber} representing this constant.
+ * If {@code null}, implementation attempts to derive a {@link CNumber}
+ * of the given {@code nativeExpr}.
+ * @param enumName optional name of the represented enumeration
+ * @param astLocus AST location of the represented constant.
+ */
public ConstantDefinition(final String name,
- final String value,
- final boolean isEnum,
- final String enumName) {
- this.origName = name;
- this.name = name;
- this.value = value;
+ final String nativeExpr,
+ final CNumber number,
+ final String enumName, final ASTLocusTag astLocus) {
+ this(name, nativeExpr, number, true, enumName, astLocus);
+ }
+ /**
+ * @param name unique name of this constant expression
+ * @param nativeExpr original [native] expression
+ * @param number optional {@link CNumber} representing this constant.
+ * If {@code null}, implementation attempts to derive a {@link CNumber}
+ * of the given {@code nativeExpr}.
+ * @param isEnum {@code true} if this constant is an enumerate, otherwise {@code false}.
+ * @param enumName optional name of the represented enumeration
+ * @param astLocus AST location of the represented constant.
+ */
+ private ConstantDefinition(final String name,
+ final String nativeExpr,
+ final CNumber number,
+ final boolean isEnum, final String enumName, final ASTLocusTag astLocus) {
+ super(name);
+ this.nativeExpr = nativeExpr;
+ this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest();
+ if( null != number ) {
+ this.number = number;
+ } else {
+ // Attempt to parse define string as number
+ final CNumber iNum = decodeIntegerNumber(nativeExpr);
+ if( null != iNum ) {
+ this.number = iNum;
+ } else {
+ final CNumber fNum = decodeDecimalNumber(nativeExpr);
+ if( null != fNum ) {
+ this.number = fNum;
+ } else {
+ this.number = null;
+ }
+ }
+ }
this.isEnum = isEnum;
this.enumName = enumName;
- this.aliasedNames=new HashSet<String>();
+ this.astLocus = astLocus;
}
- public boolean equals(final ConstantDefinition other) {
- return (equals(name, other.name) &&
- equals(value, other.value) &&
- equals(enumName, other.enumName));
+ @Override
+ public ASTLocusTag getASTLocusTag() { return astLocus; }
+
+ /**
+ * Hash by its given {@link #getName() name}.
+ */
+ @Override
+ public final int hashCode() {
+ return getName().hashCode();
}
- private boolean equals(final String s1, final String s2) {
+ /**
+ * 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());
+ }
+ }
+
+ @Override
+ public final int hashCodeSemantics() {
+ // 31 * x == (x << 5) - x
+ int hash = 31 + ( null != getName() ? getName().hashCode() : 0 );
+ hash = ((hash << 5) - hash) + ( isEnum ? 1 : 0 );
+ hash = ((hash << 5) - hash) + ( null != enumName ? enumName.hashCode() : 0 );
+ hash = ((hash << 5) - hash) + ( null != number ? number.hashCode() : 0 );
+ return ((hash << 5) - hash) + ( !relaxedEqSem && null != nativeExpr ? nativeExpr.hashCode() : 0 );
+ }
+
+ @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()) ||
+ isEnum != t.isEnum ||
+ !equals(enumName, t.enumName) ) {
+ return false;
+ }
+ if( null != number ) {
+ if( number.isInteger ) {
+ return number.i == t.number.i;
+ } else {
+ return number.f == t.number.f;
+ }
+ } else {
+ // define's string value may be semantical equal .. but formatted differently!
+ return relaxedEqSem || equals(nativeExpr, t.nativeExpr);
+ }
+ }
+ }
+
+ /** Returns the original [native] expression. */
+ public String getNativeExpr() { return nativeExpr; }
+ /**
+ * Returns the parsed {@link CNumber} of the {@link #getNativeExpr() native expression},
+ * or {@code null} if the latter does not comprise a single number,
+ * i.e. is a complex expression.
+ */
+ public CNumber getNumber() { return number; }
+ /**
+ * Returns {@code true} if this instance represents has a {@link #getNumber() number},
+ * otherwise {@code false}.
+ */
+ public boolean hasNumber() { return null != number; }
+
+ /** Returns {@code null} if this definition was not part of an
+ enumeration, or if the enumeration is anonymous. */
+ public String getEnumName() { return enumName; }
+
+ public boolean isEnum() { return isEnum; }
+
+ @Override
+ public String toString() {
+ return "ConstantDefinition [name \"" + getName()
+ + "\", expression \"" + nativeExpr
+ + "\", number "+number
+ + "], enum[is " + isEnum + ", name \"" + enumName + "\"]]";
+ }
+
+ private static boolean equals(final String s1, final String s2) {
if (s1 == null || s2 == null) {
if (s1 == null && s2 == null) {
return true;
@@ -76,57 +486,469 @@ public class ConstantDefinition {
return s1.equals(s2);
}
- @Override
- public int hashCode() {
- return name.hashCode();
+ /**
+ * Computes the {@link JavaExpr java expression} based on this instance,
+ * see {@link JavaExpr#create(ConstantDefinition)}.
+ */
+ public final JavaExpr computeJavaExpr(final Map<String, ConstantDefinition.JavaExpr> constMap) {
+ return JavaExpr.compute(this, constMap);
}
- /** Supports renaming in Java binding. */
- public void rename(final String name) {
- if(null!=name) {
- this.name = name;
- aliasedNames.add(origName);
- }
+ //
+ // Static utility functions for type detection
+ //
+
+ public static boolean isConstantExpression(final String value) {
+ if( null != value && value.length() > 0 ) {
+ // Single numeric value
+ if ( isNumber(value) ) {
+ return true;
+ }
+ // Find constant expressions like (1 << 3)
+ // if found just pass them through, they will most likely work in java too
+ // expressions containing identifiers are currently ignored (casts too)
+ final String[] values = value.split("[\\s\\(\\)]"); // [ whitespace '(' ')' ]
+ int numberCount = 0;
+ for (final String s : values) {
+ if( s.length() > 0 ) {
+ if( isCPPOperand(s) ) {
+ // OK
+ } else if ( isNumber(s) ) {
+ // OK
+ numberCount++;
+ } else {
+ return false;
+ }
+ }
+ }
+ final boolean res = numberCount > 0;
+ return res;
+ }
+ return false;
+ }
+
+ public static boolean isIdentifier(final String value) {
+ boolean identifier = false;
+
+ final char[] chars = value.toCharArray();
+
+ for (int i = 0; i < chars.length; i++) {
+ final char c = chars[i];
+ if (i == 0) {
+ if (Character.isJavaIdentifierStart(c)) {
+ identifier = true;
+ }
+ } else {
+ if (!Character.isJavaIdentifierPart(c)) {
+ identifier = false;
+ break;
+ }
+ }
+ }
+ return identifier;
+ }
+
+ /**
+ * Returns either {@link #decodeIntegerNumber(String)},
+ * {@link #decodeDecimalNumber(String)} or {@code null}.
+ * @param v
+ */
+ public static CNumber decodeANumber(final String v) {
+ final CNumber iNumber = ConstantDefinition.decodeIntegerNumber(v);
+ if( null != iNumber ) {
+ return iNumber;
+ }
+ return ConstantDefinition.decodeDecimalNumber(v);
}
- public void addAliasedName(final String name) {
- aliasedNames.add(name);
+ /**
+ * If the given string {@link #isIntegerNumber(String)},
+ * return the decoded integer value, represented as a {@code ANumber},
+ * otherwise returns {@code null}.
+ * <p>
+ * Method strips off sign prefix {@code +}
+ * and integer modifier suffixes {@code [uUlL]}
+ * before utilizing {@link Long#decode(String)}.
+ * </p>
+ * @param v
+ */
+ public static CNumber decodeIntegerNumber(final String v) {
+ if( null == v || !isIntegerNumber(v) ) {
+ return null;
+ }
+ String s0 = v.trim();
+ if( 0 == s0.length() ) {
+ return null;
+ }
+ if (s0.startsWith("+")) {
+ s0 = s0.substring(1, s0.length()).trim();
+ if( 0 == s0.length() ) {
+ return null;
+ }
+ }
+ final boolean neg;
+ if (s0.startsWith("-")) {
+ s0 = s0.substring(1, s0.length()).trim();
+ if( 0 == s0.length() ) {
+ return null;
+ }
+ neg = true;
+ } else {
+ neg = false;
+ }
+
+ // Test last two chars for [lL] and [uU] modifiers!
+ boolean isUnsigned = false;
+ boolean isLong = false;
+ final int j = s0.length() - 2;
+ for(int i = s0.length() - 1; i >= 0 && i >= j; i--) {
+ final char lastChar = s0.charAt(s0.length()-1);
+ if( lastChar == 'u' || lastChar == 'U' ) {
+ s0 = s0.substring(0, s0.length()-1);
+ isUnsigned = true;
+ } else if( lastChar == 'l' || lastChar == 'L' ) {
+ s0 = s0.substring(0, s0.length()-1);
+ isLong = true;
+ } else {
+ // early out, no modifier match!
+ break;
+ }
+ }
+ if( 0 == s0.length() ) {
+ return null;
+ }
+ final long res;
+ if( isLong && isUnsigned ) {
+ res = decodeULong(s0, neg);
+ } else {
+ if( neg ) {
+ s0 = "-" + s0;
+ }
+ res = Long.decode(s0).longValue();
+ }
+ final boolean isLong2 = isLong ||
+ ( !isUnsigned && ( Integer.MIN_VALUE > res || res > Integer.MAX_VALUE ) ) ||
+ ( isUnsigned && res > UNSIGNED_INT_MAX_VALUE );
+ return new CNumber(isLong2, isUnsigned, res);
}
- public Collection<String> getAliasedNames() {
- return aliasedNames;
+ private static long decodeULong(final String v, final boolean neg) throws NumberFormatException {
+ final int radix;
+ final int idx;
+ if (v.startsWith("0x") || v.startsWith("0X")) {
+ idx = 2;
+ radix = 16;
+ } else if (v.startsWith("#")) {
+ idx = 1;
+ radix = 16;
+ } else if (v.startsWith("0") && v.length() > 1) {
+ idx = 1;
+ radix = 8;
+ } else {
+ idx = 0;
+ radix = 10;
+ }
+ final String s0 = ( neg ? "-" : "" ) + v.substring(idx);
+ final BigInteger res = new BigInteger(s0, radix);
+ if( res.compareTo(UNSIGNED_LONG_MAX_VALUE) > 0 ) {
+ throw new NumberFormatException("Value \""+v+"\" is > UNSIGNED_LONG_MAX");
+ }
+ return res.longValue();
}
- public String getOrigName() {
- return origName;
+ /**
+ * If the given string {@link #isDecimalNumber(String)},
+ * return the decoded floating-point value, represented as a {@code ANumber} object,
+ * otherwise returns {@code null}.
+ * <p>
+ * Method utilizes {@link Double#valueOf(String)}.
+ * </p>
+ * @param v
+ * @param isDouble return value for {@code double} flag
+ */
+ public static CNumber decodeDecimalNumber(final String v) {
+ if( null == v || !isDecimalNumber(v) ) {
+ return null;
+ }
+ final String s0 = v.trim();
+ if( 0 == s0.length() ) {
+ return null;
+ }
+ boolean _isDouble = false;
+ final char lastChar = s0.charAt(s0.length()-1);
+ if( lastChar == 'd' || lastChar == 'D' ) {
+ _isDouble = true;
+ }
+ final double res = Double.valueOf(s0).doubleValue();
+ final double ares = Math.abs(res);
+ return new CNumber(_isDouble || Float.MIN_VALUE > ares || ares > Float.MAX_VALUE, res);
}
- public String getName() {
- return name;
+ /**
+ * Matches {@link #isHexNumber(String)} or {@link #isDecimalOrIntNumber(String)}.
+ */
+ public static boolean isNumber(final String s) {
+ if( isHexNumber(s) ) {
+ return true;
+ } else {
+ return isDecimalOrIntNumber(s);
+ }
}
- public String getValue() { return value; }
- /** Returns null if this definition was not part of an
- enumeration, or if the enum was anonymous. */
- public String getEnumName() { return enumName; }
+ /**
+ * Matches {@link #isHexNumber(String)} or {@link #patternIntegerNumber}.
+ */
+ public static boolean isIntegerNumber(final String s) {
+ if( isHexNumber(s) ) {
+ return true;
+ } else {
+ return patternIntegerNumber.matcher(s).matches();
+ }
+ }
- public boolean isEnum() { return isEnum; }
+ /**
+ * Matches {@link #patternHexNumber}.
+ */
+ public static boolean isHexNumber(final String s) {
+ return patternHexNumber.matcher(s).matches();
+ }
- public Set<String> getAliases() {
- return aliases;
+ /**
+ * Matches pattern for <code>floating point</code> number,
+ * compatible and described in {@link Double#valueOf(String)}.
+ */
+ public static boolean isDecimalNumber(final String s) {
+ return patternDecimalNumber.matcher(s).matches();
}
- public void addAlias(final String alias) {
- if (aliases == null) {
- aliases = new LinkedHashSet<String>();
- }
- aliases.add(alias);
+ /**
+ * Complete pattern for <code>floating point</code> <i>and</i> <code>integer</code> number,
+ * covering {@link #patternDecimalNumber} <i>and</i> {@link #patternIntegerNumber}.
+ */
+ public static boolean isDecimalOrIntNumber(final String s) {
+ return patternDecimalOrIntNumber.matcher(s).matches();
}
- @Override
- public String toString() {
- return "ConstantDefinition [name " + name + " origName " + origName + " value " + value
- + " aliasedNames " + aliasedNames + " aliases " + aliases
- + " enumName " + enumName + " isEnum " + isEnum + "]";
+ /**
+ * Matches pattern for valid CPP operands, see {@link #patternCPPOperand}.
+ */
+ public static boolean isCPPOperand(final String s) {
+ return patternCPPOperand.matcher(s).matches();
}
+ /**
+ * Complete pattern for <code>hexadecimal</code> number,
+ * including an optional sign {@code [+-]} and optional suffixes {@code [uUlL]}.
+ */
+ public static Pattern patternHexNumber;
+
+ /**
+ * Complete pattern for <code>floating point</code> number,
+ * compatible and described in {@link Double#valueOf(String)}.
+ */
+ public final static Pattern patternDecimalNumber;
+
+ /**
+ * Complete pattern for <code>floating point</code> <i>and</i> <code>integer</code> number,
+ * covering {@link #patternDecimalNumber} <i>and</i> {@link #patternIntegerNumber}.
+ */
+ public final static Pattern patternDecimalOrIntNumber;
+
+ /**
+ * Complete pattern for <code>integer</code> number,
+ * including an optional sign {@code [+-]} and optional suffixes {@code [uUlL]}.
+ */
+ public final static Pattern patternIntegerNumber;
+
+ /**
+ * One of: {@code +} {@code -} {@code *} {@code /} {@code |} {@code &} {@code (} {@code )} {@code <<} {@code >>}
+ * <p>
+ * Expression excludes {@link #patternDecimalOrIntNumber}.
+ * </p>
+ */
+ public static Pattern patternCPPOperand;
+
+ static {
+ final String WhiteSpace = "[\\x00-\\x20]*";
+ final String Digits = "(\\p{Digit}+)";
+ final String HexDigits = "(\\p{XDigit}+)";
+ final String IntTypeSuffix =
+ "(" +
+ "[uU]|" +
+ "([uU][lL])|" +
+ "[lL]|" +
+ "([lL][uU])" +
+ ")";
+
+ final String hexRegex =
+ WhiteSpace + // Optional leading "whitespace"
+ "[+-]?" + // Optional sign character
+ // HexDigits IntTypeSuffix_opt
+ "0[xX]" + HexDigits + IntTypeSuffix + "?" +
+ WhiteSpace // Optional trailing "whitespace"
+ ;
+ patternHexNumber = Pattern.compile(hexRegex);
+
+ final String intRegex =
+ WhiteSpace + // Optional leading "whitespace"
+ "[+-]?" + // Optional sign character
+ // Digits IntTypeSuffix_opt
+ Digits + IntTypeSuffix + "?" +
+ WhiteSpace // Optional trailing "whitespace"
+ ;
+ patternIntegerNumber = Pattern.compile(intRegex);
+
+ // an exponent is 'e' or 'E' followed by an optionally
+ // signed decimal integer.
+ final String Exp = "[eE][+-]?"+Digits;
+ final String fpRegex =
+ WhiteSpace + // Optional leading "whitespace"
+ "[+-]?" + // Optional sign character
+ "("+
+ "NaN|" + // "NaN" string
+ "Infinity|" + // "Infinity" string
+
+ // A decimal floating-point string representing a finite positive
+ // number without a leading sign has at most five basic pieces:
+ // Digits . Digits ExponentPart FloatTypeSuffix
+ //
+ // Since this method allows integer-only strings as input
+ // in addition to strings of floating-point literals, the
+ // two sub-patterns below are simplifications of the grammar
+ // productions from the Java Language Specification, 2nd
+ // edition, section 3.10.2.
+
+ "("+
+ "("+
+ // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
+ "("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
+
+ // . Digits ExponentPart_opt FloatTypeSuffix_opt
+ "(\\.("+Digits+")("+Exp+")?)|"+
+
+ // Hexadecimal w/ binary exponent
+ "(" +
+ "(" +
+ // Hexadecimal strings
+ // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
+ "(0[xX]" + HexDigits + "(\\.)?)|" +
+
+ // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
+ "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
+ ")" +
+
+ // binary exponent
+ "[pP][+-]?" + Digits +
+ ")" +
+ ")" +
+ "[fFdD]?"+
+ ")"+
+ ")" +
+ WhiteSpace // Optional trailing "whitespace"
+ ;
+ patternDecimalNumber = Pattern.compile(fpRegex);
+
+ final String fpOrIntRegex =
+ WhiteSpace + // Optional leading "whitespace"
+ "[+-]?" + // Optional sign character
+ "("+
+ "NaN|" + // "NaN" string
+ "Infinity|" + // "Infinity" string
+
+ // Matching integers w/ IntTypeSuffix,
+ // which are otherwise not matched by the below floating point matcher!
+ // Digits IntTypeSuffix
+ "(" + Digits + IntTypeSuffix +")|" +
+
+ // A decimal floating-point string representing a finite positive
+ // number without a leading sign has at most five basic pieces:
+ // Digits . Digits ExponentPart FloatTypeSuffix
+ //
+ // Since this method allows integer-only strings as input
+ // in addition to strings of floating-point literals, the
+ // two sub-patterns below are simplifications of the grammar
+ // productions from the Java Language Specification, 2nd
+ // edition, section 3.10.2.
+
+ "("+
+ "("+
+ // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
+ "(" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|" +
+
+ // . Digits ExponentPart_opt FloatTypeSuffix_opt
+ "(\\.(" + Digits + ")(" + Exp + ")?)|" +
+
+ // Hexadecimal w/ binary exponent
+ "(" +
+ "(" +
+ // Hexadecimal strings
+ // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
+ "(0[xX]" + HexDigits + "(\\.)?)|" +
+
+ // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
+ "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
+ ")" +
+
+ // binary exponent
+ "[pP][+-]?" + Digits +
+ ")" +
+ ")" +
+ "[fFdD]?"+
+ ")"+
+ ")" +
+ WhiteSpace // Optional trailing "whitespace"
+ ;
+ patternDecimalOrIntNumber = Pattern.compile(fpOrIntRegex);
+
+ final String fpOrIntRegex2 =
+ WhiteSpace + // Optional leading "whitespace"
+ // "[+-]?" + // Optional sign character
+ "("+
+ "NaN|" + // "NaN" string
+ "Infinity|" + // "Infinity" string
+
+ // Matching integers w/ IntTypeSuffix,
+ // which are otherwise not matched by the below floating point matcher!
+ // Digits IntTypeSuffix
+ "(" + Digits + IntTypeSuffix +")|" +
+
+ // A decimal floating-point string representing a finite positive
+ // number without a leading sign has at most five basic pieces:
+ // Digits . Digits ExponentPart FloatTypeSuffix
+ //
+ // Since this method allows integer-only strings as input
+ // in addition to strings of floating-point literals, the
+ // two sub-patterns below are simplifications of the grammar
+ // productions from the Java Language Specification, 2nd
+ // edition, section 3.10.2.
+
+ "("+
+ "("+
+ // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
+ "(" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|" +
+
+ // . Digits ExponentPart_opt FloatTypeSuffix_opt
+ "(\\.(" + Digits + ")(" + Exp + ")?)|" +
+
+ // Hexadecimal w/ binary exponent
+ "(" +
+ "(" +
+ // Hexadecimal strings
+ // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
+ "(0[xX]" + HexDigits + "(\\.)?)|" +
+
+ // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
+ "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
+ ")" +
+
+ // binary exponent
+ "[pP][+-]?" + Digits +
+ ")" +
+ ")" +
+ "[fFdD]?"+
+ ")"+
+ ")" +
+ WhiteSpace // Optional trailing "whitespace"
+ ;
+ patternCPPOperand = Pattern.compile("(?!"+fpOrIntRegex2+")[\\+\\-\\*\\/\\|\\&\\(\\)]|(\\<\\<)|(\\>\\>)");
+ }
}
diff --git a/src/java/com/jogamp/gluegen/DebugEmitter.java b/src/java/com/jogamp/gluegen/DebugEmitter.java
index 6381c8c..046c2b6 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) {
@@ -66,7 +74,7 @@ public class DebugEmitter implements GlueEmitter {
@Override
public void emitDefine(final ConstantDefinition def, final String optionalComment) {
final String name = def.getName();
- final String value = def.getValue();
+ final String value = def.getNativeExpr();
System.out.println("#define " + name + " " + value +
(optionalComment != null ? ("// " + optionalComment) : ""));
}
@@ -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..bfbb73b 100644
--- a/src/java/com/jogamp/gluegen/FunctionEmitter.java
+++ b/src/java/com/jogamp/gluegen/FunctionEmitter.java
@@ -42,57 +42,43 @@ 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 {
public static final EmissionModifier STATIC = new EmissionModifier("static");
- private final boolean isInterfaceVal;
+ private final boolean isInterface;
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.isInterface = 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) {
+ isInterface = arg.isInterface;
modifiers = new ArrayList<EmissionModifier>(arg.modifiers);
commentEmitter = arg.commentEmitter;
defaultOutput = arg.defaultOutput;
- isInterfaceVal = arg.isInterfaceVal;
+ cfg = arg.cfg;
}
- public boolean isInterface() { return isInterfaceVal; }
-
- /**
- * Checks the base type of pointer-to-pointer, pointer, array or plain for const-ness.
- * <p>
- * Note: Implementation walks down to the base type and returns it's const-ness.
- * Intermediate 'const' qualifier are not considered, e.g. const pointer.
- * </p>
- */
- protected final boolean isBaseTypeConst(final Type type) {
- if ( 2 == type.pointerDepth() ) {
- return type.asPointer().getTargetType().asPointer().getTargetType().isConst();
- } else if ( 1 == type.pointerDepth() ) {
- return type.asPointer().getTargetType().isConst();
- } else if( type.isArray() ) {
- return type.asArray().getBaseElementType().isConst();
- } else {
- return type.isConst();
- }
- }
+ public boolean isInterface() { return isInterface; }
public PrintWriter getDefaultOutput() { return defaultOutput; }
@@ -111,7 +97,11 @@ public abstract class FunctionEmitter {
public Iterator<EmissionModifier> getModifiers() { return modifiers.iterator(); }
- public abstract String getName();
+ public abstract String getInterfaceName();
+ public abstract String getImplName();
+ public abstract String getNativeName();
+
+ public abstract FunctionSymbol getCSymbol();
/**
* Emit the function to the specified output (instead of the default
diff --git a/src/java/com/jogamp/gluegen/GenericCPP.java b/src/java/com/jogamp/gluegen/GenericCPP.java
new file mode 100644
index 0000000..db414d9
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/GenericCPP.java
@@ -0,0 +1,63 @@
+/**
+ * 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 java.io.OutputStream;
+import java.io.Reader;
+import java.util.List;
+
+import com.jogamp.gluegen.jcpp.LexerException;
+
+/**
+ * Generic C preprocessor interface for GlueGen
+ */
+public interface GenericCPP {
+
+ public void addDefine(String name, String value) throws LexerException;
+
+ public String findFile(String filename);
+
+ public OutputStream out();
+ public void setOut(OutputStream out);
+
+ public void run(Reader reader, String filename) throws GlueGenException;
+
+ /**
+ * Returns a list of {@link ConstantDefinition}, i.e.
+ * <i>non-function-like</i> and <i>non-empty</i> macros w/ <i>constant-value</i>,
+ * as derived during parsing.
+ * <p>
+ * May return an empty list, in case this preprocessor does not
+ * store {@link ConstantDefinition}s.
+ * </p>
+ * @throws GlueGenException
+ */
+ public List<ConstantDefinition> getConstantDefinitions() throws GlueGenException;
+
+
+} \ No newline at end of file
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..6dee6f0 100644
--- a/src/java/com/jogamp/gluegen/GlueGen.java
+++ b/src/java/com/jogamp/gluegen/GlueGen.java
@@ -43,11 +43,13 @@ 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.*;
+import com.jogamp.gluegen.jcpp.JCPP;
import static java.lang.System.*;
@@ -61,14 +63,18 @@ public class GlueGen implements GlueEmitterControls {
}
private final List<String> forcedStructNames = new ArrayList<String>();
- private PCPP preprocessor;
+ private GenericCPP 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;
+ private static Level logLevel = null;
+
+ public static void setDebug(final boolean v) { debug=v; }
+ public static void setLogLevel(final Level l) { logLevel=l; }
public static boolean debug() { return debug; }
@Override
@@ -83,38 +89,66 @@ 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;
}
}
+ /** GlueGen's build in macro name {@value}, when compiling w/ GlueGen. */
+ public static final String __GLUEGEN__ = "__GLUEGEN__";
@SuppressWarnings("unchecked")
- 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) {
+ 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 copyCPPOutput2Stderr) {
try {
- final File out = File.createTempFile("PCPPTemp", ".pcpp");
+ if(debug) {
+ Logging.getLogger().setLevel(Level.ALL);
+ } else if( null != logLevel ) {
+ Logging.getLogger().setLevel(logLevel);
+ }
+ 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("CPPTemp", ".cpp");
final FileOutputStream outStream = new FileOutputStream(out);
+ // preprocessor = new PCPP(includePaths, debug, copyCPPOutput2Stderr);
+ preprocessor = new JCPP(includePaths, debug, copyCPPOutput2Stderr);
+ final String cppName = preprocessor.getClass().getSimpleName();
if(debug) {
- System.err.println("PCPP output at (persistent): " + out.getAbsolutePath());
+ System.err.println("CPP <"+cppName+"> output at (persistent): " + out.getAbsolutePath());
} else {
out.deleteOnExit();
}
- preprocessor = new PCPP(includePaths, debug, copyPCPPOutput2Stderr);
- preprocessor.addDefine("__GLUEGEN__", "2");
+ preprocessor.addDefine(__GLUEGEN__, "2");
preprocessor.setOut(outStream);
preprocessor.run(reader, filename);
outStream.flush();
outStream.close();
+ if(debug) {
+ System.err.println("CPP <"+cppName+"> done");
+ }
final FileInputStream inStream = new FileInputStream(out);
final DataInputStream dis = new DataInputStream(inStream);
@@ -140,6 +174,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 +197,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 +209,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>")) {
@@ -197,63 +217,93 @@ 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));
+ final EnumType.Enumerator enumerate = enumeration.getEnum(i);
+ final ConstantDefinition def =
+ new ConstantDefinition(enumerate.getName(), enumerate.getExpr(),
+ enumerate.getNumber(),
+ enumName, enumeration.getASTLocusTag());
+ allConstants.add(def);
}
}
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(), null, def.getASTLocusTag()));
}
+ allConstants.addAll(preprocessor.getConstantDefinitions());
- 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);
- 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) {
- if (!emittedDefines.contains(def.getName())) {
- emittedDefines.add(def.getName());
- final Set<String> aliases = def.getAliases();
- if (aliases != null) {
- comment.append("Alias for: <code>");
- for (final String alias : aliases) {
- comment.append(" ").append(alias);
- }
- comment.append("</code>");
+ 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++;
}
- if (def.getEnumName() != null) {
- if (comment.length() > 0)
- comment.append("<br>\n");
+ }
+ i=0;
+ System.err.println("Filtered Functions: "+allFunctions.size());
+ for (final FunctionSymbol cFunc : allFunctions) {
+ System.err.println("Filtered ["+i+"]: "+cFunc.getAliasedString());
+ i++;
+ }
+ }
- comment.append("Defined as part of enum type \"");
- comment.append(def.getEnumName());
- comment.append("\"");
- }
- if (comment.length() > 0) {
- emit.emitDefine(def, comment.toString());
- comment.setLength(0);
- }
- else {
- emit.emitDefine(def, null);
+ if ( !cfg.structsOnly() ) {
+ 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 : allConstants) {
+ if (!emittedDefines.contains(def.getName())) {
+ emittedDefines.add(def.getName());
+ 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) {
+ if(0 < i) {
+ comment.append("</code>, <code>");
+ }
+ comment.append(alias);
+ i++;
+ }
+ comment.append("</code>");
+ }
+ if (def.getEnumName() != null) {
+ if (comment.length() > 0)
+ comment.append("<br>\n");
+
+ comment.append("Defined as part of enum type \"");
+ comment.append(def.getEnumName());
+ comment.append("\"");
+ }
+ if (comment.length() > 0) {
+ emit.emitDefine(def, comment.toString());
+ comment.setLength(0);
+ }
+ else {
+ emit.emitDefine(def, null);
+ }
}
}
+ emit.endDefines();
}
- emit.endDefines();
// 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
- // to be skipped).
+ // emitted (e.g., if an Ignore directive in the JavaEmitter causes it to be skipped).
sym.getType().visit(referencedStructs);
}
@@ -273,13 +323,9 @@ public class GlueGen implements GlueEmitterControls {
// Lay out structs
emit.beginStructLayout();
- for (final Iterator<Type> iter = referencedStructs.results(); iter.hasNext();) {
- final Type t = iter.next();
- if (t.isCompound()) {
- emit.layoutStruct(t.asCompound());
- } else if (t.isPointer()) {
- final PointerType p = t.asPointer();
- final CompoundType c = p.getTargetType().asCompound();
+ for (final Iterator<CompoundType> iter = referencedStructs.layouts(); iter.hasNext();) {
+ final CompoundType c = iter.next();
+ if( !c.isLayouted() ) {
emit.layoutStruct(c);
}
}
@@ -290,20 +336,23 @@ public class GlueGen implements GlueEmitterControls {
for (final Iterator<Type> iter = referencedStructs.results(); iter.hasNext();) {
final Type t = iter.next();
if (t.isCompound()) {
+ assert t.isTypedef() && 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.isTypedef() && 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.endFunctions();
+ if ( !cfg.structsOnly() ) {
+ // emit java and C code to interface with the native functions
+ emit.beginFunctions(td, sd, headerParser.getCanonMap());
+ emit.emitFunctions(allFunctions);
+ emit.endFunctions();
+ }
// end emission of glue code
emit.endEmission();
@@ -340,6 +389,9 @@ public class GlueGen implements GlueEmitterControls {
emitterFQN = arg.substring(2);
} else if (arg.startsWith("-C")) {
cfgFiles.add(arg.substring(2));
+ } else if (arg.equals("--logLevel")) {
+ i++;
+ logLevel = Level.parse(args[i]);
} else if (arg.equals("--debug")) {
debug=true;
} else if (arg.equals("--dumpCPP")) {
@@ -392,7 +444,7 @@ public class GlueGen implements GlueEmitterControls {
out.println("file or files can be specified with -C option; e.g,");
out.println("-Cjava-emitter.cfg.");
out.println(" --debug enables debug mode");
- out.println(" --dumpCPP directs PCPP to dump all output to stderr as well");
+ out.println(" --dumpCPP directs CPP to dump all output to stderr as well");
exit(1);
}
}
diff --git a/src/java/com/jogamp/gluegen/GlueGenException.java b/src/java/com/jogamp/gluegen/GlueGenException.java
new file mode 100644
index 0000000..b6713e1
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/GlueGenException.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright 2010 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.common.JogampRuntimeException;
+
+/** A generic exception for Jogamp errors used throughout the binding
+ as a substitute for {@link RuntimeException}. */
+
+@SuppressWarnings("serial")
+public class GlueGenException extends JogampRuntimeException {
+ final ASTLocusTag locus;
+
+ public ASTLocusTag getASTLocusTag() { return locus; }
+
+ /** Constructs a GlueGenException object. */
+ public GlueGenException() {
+ super();
+ locus = null;
+ }
+
+ /** Constructs a GlueGenException object with the specified detail
+ message. */
+ public GlueGenException(final String message) {
+ super(message);
+ locus = null;
+ }
+
+ /** Constructs a GlueGenException object with the specified detail
+ message and root cause. */
+ public GlueGenException(final String message, final Throwable cause) {
+ super(message, cause);
+ locus = null;
+ }
+
+ /** Constructs a GlueGenException object with the specified root
+ cause. */
+ public GlueGenException(final Throwable cause) {
+ super(cause);
+ locus = null;
+ }
+
+ /** Constructs a GlueGenException object with the specified detail
+ message and root cause. */
+ public GlueGenException(final String message, final ASTLocusTag locusTag) {
+ super(message);
+ this.locus = locusTag;
+ }
+
+ /** Constructs a GlueGenException object with the specified detail
+ message and root cause. */
+ public GlueGenException(final String message, final ASTLocusTag locusTag, final Throwable cause) {
+ super(message, cause);
+ this.locus = locusTag;
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(256);
+ if (null != locus) {
+ locus.toString(sb, "error", true).append(": ");
+ }
+ sb.append(getClass().getSimpleName()).append(": ").append(getLocalizedMessage());
+ return sb.toString();
+ }
+
+}
diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java
index 346920d..019ca2d 100644
--- a/src/java/com/jogamp/gluegen/JavaConfiguration.java
+++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java
@@ -40,21 +40,19 @@
package com.jogamp.gluegen;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
import com.jogamp.gluegen.JavaEmitter.EmissionStyle;
import com.jogamp.gluegen.JavaEmitter.MethodAccess;
+import com.jogamp.gluegen.Logging.LoggerIf;
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.*;
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.*;
@@ -63,17 +61,13 @@ import static com.jogamp.gluegen.JavaEmitter.EmissionStyle.*;
JavaEmitter. */
public class JavaConfiguration {
-
- public static final boolean DEBUG_IGNORES = GlueGen.debug() || false;
- public static final boolean DEBUG_RENAMES = GlueGen.debug() || false;
-
private int nestedReads;
private String packageName;
private String implPackageName;
private String className;
private String implClassName;
- protected static final Logger LOG = Logger.getLogger(JavaConfiguration.class.getPackage().getName());
+ protected final LoggerIf LOG;
public static String NEWLINE = System.getProperty("line.separator");
@@ -108,6 +102,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
@@ -137,6 +138,7 @@ public class JavaConfiguration {
private final Map<String, MethodAccess> accessControl = new HashMap<String, MethodAccess>();
private final Map<String, TypeInfo> typeInfoMap = new HashMap<String, TypeInfo>();
private final Set<String> returnsString = new HashSet<String>();
+ private final Map<String, JavaType> returnsOpaqueJType = new HashMap<String, JavaType>();
private final Map<String, String> returnedArrayLengths = new HashMap<String, String>();
/**
@@ -158,6 +160,7 @@ public class JavaConfiguration {
private boolean forceUseNIODirectOnly4All = false;
private final Set<String> useNIODirectOnly = new HashSet<String>();
private final Set<String> manuallyImplement = new HashSet<String>();
+ private final Map<String, String> delegatedImplementation = new HashMap<String, String>();
private final Set<String> manualStaticInitCall = new HashSet<String>();
private final Set<String> forceStaticInitCode = new HashSet<String>();
private final Map<String, List<String>> customJavaCode = new HashMap<String, List<String>>();
@@ -180,6 +183,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(), JavaConfiguration.class.getSimpleName());
+ }
+
/** Reads the configuration file.
@param filename path to file that should be read
*/
@@ -317,6 +324,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;
@@ -333,7 +349,7 @@ public class JavaConfiguration {
}
// Default access control is public
return PUBLIC;
- }
+ }
/** Returns the package in which the generated glue code expects to
find its run-time helper classes (Buffers, Platform,
@@ -358,15 +374,31 @@ public class JavaConfiguration {
}
private static final boolean DEBUG_TYPE_INFO = false;
+
+ /**
+ * If the given {@code canonicalName} should be considered opaque,
+ * returns the TypeInfo describing the replacement type.
+ * <p>
+ * Returns null if this type should not be considered opaque.
+ * </p>
+ * <p>
+ * If symbol references a struct fields, see {@link #canonicalStructFieldSymbol(String, String)},
+ * it describes field's array-length or element-count referenced by a pointer.
+ * </p>
+ */
+ public TypeInfo canonicalNameOpaque(final String canonicalName) {
+ return typeInfoMap.get(canonicalName);
+ }
+
/** 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 +409,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 +425,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 +440,9 @@ public class JavaConfiguration {
type = type.asPointer().getTargetType();
}
}
-
+ if (DEBUG_TYPE_INFO) {
+ System.err.println(" [X] NULL");
+ }
return null;
}
@@ -497,6 +512,13 @@ public class JavaConfiguration {
public boolean returnsString(final String functionName) {
return returnsString.contains(functionName);
}
+ /** Indicates whether the given function (which returns a
+ <code>char*</code> in C) should be translated as returning a
+ <code>java.lang.String</code>. */
+ public boolean returnsString(final AliasedSymbol symbol) {
+ return returnsString.contains( symbol.getName() ) ||
+ oneInSet(returnsString, symbol.getAliasedNames());
+ }
/**
* Returns a MessageFormat string of the Java expression calculating
@@ -549,17 +571,6 @@ public class JavaConfiguration {
return forceUseNIODirectOnly4All || useNIODirectOnly.contains(functionName);
}
- /** Returns true if the glue code for the given function will be
- manually implemented by the end user.
- * <p>
- * If symbol references a struct field or method, see {@link #canonicalStructFieldSymbol(String, String)},
- * it describes field's array-length or element-count referenced by a pointer.
- * </p>
- */
- public boolean manuallyImplement(final String functionName) {
- return manuallyImplement.contains(functionName);
- }
-
/**
* Returns true if the static initialization java code calling <code>initializeImpl()</code>
* for the given class will be manually implemented by the end user
@@ -727,52 +738,94 @@ public class JavaConfiguration {
return parentClass.get(className);
}
- public void dumpIgnoresOnce() {
- if(!dumpedIgnores) {
- dumpedIgnores = true;
- dumpIgnores();
+ public void logIgnoresOnce() {
+ if(!loggedIgnores) {
+ loggedIgnores = true;
+ logIgnores();
}
}
- private static boolean dumpedIgnores = false;
+ private static boolean loggedIgnores = false;
- public void dumpIgnores() {
- System.err.println("Extended Intf: ");
+ public void logIgnores() {
+ LOG.log(INFO, "Extended Intf: {0}", extendedIntfSymbolsIgnore.size());
for (final String str : extendedIntfSymbolsIgnore) {
- System.err.println("\t"+str);
+ LOG.log(INFO, "\t{0}", str);
}
- System.err.println("Extended Impl: ");
+ LOG.log(INFO, "Extended Impl: {0}", extendedImplSymbolsIgnore.size());
for (final String str : extendedImplSymbolsIgnore) {
- System.err.println("\t"+str);
+ LOG.log(INFO, "\t{0}", str);
}
- System.err.println("Ignores (All): ");
+ LOG.log(INFO, "Ignores (All): {0}", ignores.size());
for (final Pattern pattern : ignores) {
- System.err.println("\t"+pattern);
+ LOG.log(INFO, "\t{0}", pattern);
}
}
- public void dumpRenamesOnce() {
- if(!dumpedRenames) {
- dumpedRenames = true;
- dumpRenames();
+ public void logRenamesOnce() {
+ if(!loggedRenames) {
+ loggedRenames = true;
+ logRenames();
}
}
- private static boolean dumpedRenames = false;
+ private static boolean loggedRenames = false;
- public void dumpRenames() {
- System.err.println("Symbol Renames: ");
+ public void logRenames() {
+ LOG.log(INFO, "Symbol Renames: {0}", javaSymbolRenames.size());
for (final String key : javaSymbolRenames.keySet()) {
- System.err.println("\t"+key+" -> "+javaSymbolRenames.get(key));
+ LOG.log(INFO, "\t{0} -> {1}", key, javaSymbolRenames.get(key));
}
- System.err.println("Symbol Aliasing (through renaming): ");
+ LOG.log(INFO, "Symbol Aliasing (through renaming): {0}", javaSymbolRenames.size());
for(final String newName : javaSymbolRenames.values()) {
final Set<String> origNames = javaRenamedSymbols.get(newName);
if(null!=origNames) {
- System.err.println("\t"+newName+" <- "+origNames);
+ LOG.log(INFO, "\t{0} <- {1}", newName, origNames);
}
}
}
+ public static <K,V> V oneInMap(final Map<K, V> map, final Set<K> symbols) {
+ if( null != map && map.size() > 0 &&
+ null != symbols && symbols.size() > 0 ) {
+ for(final K sym : symbols) {
+ final V v = map.get(sym);
+ if( null != v ) {
+ return v;
+ }
+ }
+ }
+ return null;
+ }
+ public static <K> boolean oneInSet(final Set<K> set1, final Set<K> set2) {
+ if( null != set1 && set1.size() > 0 &&
+ null != set2 && set2.size() > 0 ) {
+ for(final K sym : set2) {
+ if( set1.contains( sym ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ private static boolean onePatternMatch(final Pattern ignoreRegexp, final Set<String> set) {
+ if( null != ignoreRegexp && null != set && set.size() > 0 ) {
+ for(final String sym : set) {
+ final Matcher matcher = ignoreRegexp.matcher(sym);
+ if (matcher.matches()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ protected static ASTLocusTag getASTLocusTag(final AliasedSymbol s) {
+ if( s instanceof ASTLocusTagProvider ) {
+ return ((ASTLocusTagProvider)s).getASTLocusTag();
+ } else {
+ return null;
+ }
+ }
+
/**
* Returns the canonical configuration name for a struct field name,
* i.e. 'struct-name'.'field-name'
@@ -782,136 +835,286 @@ 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.
+ * Variant of {@link #manuallyImplement(AliasedSymbol)},
+ * where this method only considers the {@link AliasedSymbol#getName() current-name}
+ * of the given symbol, not the {@link #getJavaSymbolRename(String) renamed-symbol}.
+ */
+ public boolean manuallyImplement(final String functionName) {
+ if( manuallyImplement.contains(functionName) ) {
+ LOG.log(INFO, "ManuallyImplement: \"{0}\"", functionName);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the glue code for the given aliased function will be
+ * manually implemented by the end user.
* <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>
+ * If symbol references a struct field or method, see {@link #canonicalStructFieldSymbol(String, String)},
+ * it describes field's array-length or element-count referenced by a pointer.
+ * </p>
+ * @see #manuallyImplement(String)
*/
- 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 ) ) {
- if(DEBUG_IGNORES) {
- System.err.println("Ignore Intf ignore : "+symbol);
+ public boolean manuallyImplement(final AliasedSymbol symbol) {
+ final String name = symbol.getName();
+ final Set<String> aliases = symbol.getAliasedNames();
+
+ if ( manuallyImplement.contains( name ) ||
+ oneInSet(manuallyImplement, aliases)
+ )
+ {
+ LOG.log(INFO, getASTLocusTag(symbol), "ManuallyImplement: {0}", symbol);
+ return true;
+ } else {
+ return false;
}
- 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 ) ) {
- if(DEBUG_IGNORES) {
- System.err.println("Ignore Intf !extended: " + symbol);
+ }
+
+ /**
+ * Variant of {@link #getDelegatedImplementation(AliasedSymbol)},
+ * where this method only considers the {@link AliasedSymbol#getName() current-name}
+ * of the given symbol, not the {@link #getJavaSymbolRename(String) renamed-symbol}.
+ */
+ public String getDelegatedImplementation(final String functionName) {
+ final String res = delegatedImplementation.get(functionName);
+ if( null == res ) {
+ return null;
+ }
+ LOG.log(INFO, "DelegatedImplementation: {0} -> {1}", functionName, res);
+ return res;
+ }
+
+ /**
+ * Returns the {@code RENAMED-IMPL-SYMBOL} if the implementation of the glue code
+ * of the given function shall be manually delegated by the end user.
+ * <p>
+ * {@code DelegateImplementation <ORIG-SYMBOL> <RENAMED-IMPL-SYMBOL>}
+ * </p>
+ * <p>
+ * The interface is emitted unchanged.
+ * </p>
+ * <p>
+ * The Java and native-code implementation is renamed to {@code RENAMED-IMPL-SYMBOL}.
+ * The user's manual implementation of {@code ORIG-SYMBOL}
+ * may delegate to {@code RENAMED-IMPL-SYMBOL}.
+ * </p>
+ * <p>
+ * If symbol references a struct field or method, see {@link #canonicalStructFieldSymbol(String, String)},
+ * it describes field's array-length or element-count referenced by a pointer.
+ * </p>
+ */
+ public String getDelegatedImplementation(final AliasedSymbol symbol) {
+ final String name = symbol.getName();
+ final Set<String> aliases = symbol.getAliasedNames();
+
+ String res = delegatedImplementation.get(name);
+ if( null == res ) {
+ res = oneInMap(delegatedImplementation, aliases);
+ if( null == res ) {
+ return null;
}
- return true;
- }
- return shouldIgnoreInImpl_Int(symbol);
+ }
+ LOG.log(INFO, getASTLocusTag(symbol), "DelegatedImplementation: {0} -> {1}", symbol, res);
+ return res;
+ }
+
+ /**
+ * Variant of {@link #getOpaqueReturnType(AliasedSymbol)},
+ * where this method only considers the {@link AliasedSymbol#getName() current-name}
+ * of the given symbol, not the {@link #getJavaSymbolRename(String) renamed-symbol}.
+ */
+ public JavaType getOpaqueReturnType(final String functionName) {
+ final JavaType res = returnsOpaqueJType.get(functionName);
+ if( null == res ) {
+ return null;
+ }
+ LOG.log(INFO, "ReturnsOpaque: {0} -> {1}", functionName, res);
+ return res;
}
/**
- * Returns true if this #define, function, struct, or field within
- * a struct should be ignored during glue code generation of implementation only.
+ * Returns the opaque {@link JavaType} for the given function {@link AliasedSymbol}
+ * or {@code null} if not opaque.
* <p>
- * For struct fields see {@link #canonicalStructFieldSymbol(String, String)}.
+ * {@code ReturnsOpaque <Primitive Java Type> <Function Name>}
* </p>
*/
- public boolean shouldIgnoreInImpl(final String symbol) {
- return shouldIgnoreInImpl_Int(symbol);
+ public JavaType getOpaqueReturnType(final AliasedSymbol symbol) {
+ final String name = symbol.getName();
+ final Set<String> aliases = symbol.getAliasedNames();
+ JavaType res = returnsOpaqueJType.get(name);
+ if( null == res ) {
+ res = oneInMap(returnsOpaqueJType, aliases);
+ if( null == res ) {
+ return null;
+ }
+ }
+ LOG.log(INFO, getASTLocusTag(symbol), "ReturnsOpaque: {0} -> {1}", symbol, res);
+ return res;
}
- private boolean shouldIgnoreInImpl_Int(final String symbol) {
+ /**
+ * Variant of {@link #shouldIgnoreInInterface(AliasedSymbol)},
+ * where this method only considers the {@link AliasedSymbol#getName() current-name}
+ * of the given symbol, not the {@link #getJavaSymbolRename(String) renamed-symbol}.
+ */
+ 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 AliasedSymbol symbol) {
+ return shouldIgnoreInInterface_Int(symbol);
+ }
- if(DEBUG_IGNORES) {
- dumpIgnoresOnce();
- }
+ protected final boolean shouldIgnoreInInterface_Int(final AliasedSymbol symbol) {
+ if( GlueGen.debug() ) {
+ logIgnoresOnce();
+ }
+ final String name = symbol.getName();
+ final Set<String> aliases = symbol.getAliasedNames();
- // 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 ( extendedIntfSymbolsIgnore.contains( name ) ||
+ oneInSet(extendedIntfSymbolsIgnore, aliases)
+ )
+ {
+ LOG.log(INFO, getASTLocusTag(symbol), "Ignore Intf ignore (one): {0}", symbol);
+ 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 ) ) {
- if(DEBUG_IGNORES) {
- System.err.println("Ignore Impl !extended: " + 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) ) {
+ LOG.log(INFO, getASTLocusTag(symbol), "Ignore Intf !extended (all): {0}", symbol);
return true;
- }
+ }
+ return shouldIgnoreInImpl_Int(symbol);
+ }
- // 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;
+ /**
+ * Returns true if this aliased symbol should be ignored
+ * during glue code generation of implementation only.
+ * <p>
+ * 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 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();
+
+ // Simple case-1; the symbol (orig or renamed) is in the interface ignore table
+ if ( extendedImplSymbolsIgnore.contains( name ) ||
+ oneInSet(extendedImplSymbolsIgnore, aliases)
+ )
+ {
+ LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl ignore (one): {0}", symbol);
+ return true;
+ }
+ // 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) ) {
+ LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl !extended (all): {0}", 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) ) {
+ LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl RegEx: {0}", symbol);
+ 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()) {
+ LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl unignores==0: {0} -> {1}", symbol, 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) {
+ LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl !unignore: {0} -> {1}", symbol, 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
throws a run-time exception with an "unimplemented" message
during glue code generation. */
- public boolean isUnimplemented(final String symbol) {
- // 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 : unimplemented) {
- final Matcher matcher = regexp.matcher(symbol);
- if (matcher.matches()) {
- return true;
+ public boolean isUnimplemented(final AliasedSymbol symbol) {
+ // 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 unimplRegexp : unimplemented) {
+ final Matcher matcher = unimplRegexp.matcher(symbol.getName());
+ if ( matcher.matches() || onePatternMatch(unimplRegexp, symbol.getAliasedNames()) ) {
+ return true;
+ }
}
- }
+ return false;
+ }
- 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
@@ -932,8 +1135,8 @@ public class JavaConfiguration {
function under the hood. Returns null if this symbol has not
been explicitly renamed. */
public String getJavaSymbolRename(final String origName) {
- if(DEBUG_RENAMES) {
- dumpRenamesOnce();
+ if( LOG.isLoggable(INFO) ) {
+ logRenamesOnce();
}
return javaSymbolRenames.get(origName);
}
@@ -945,18 +1148,12 @@ public class JavaConfiguration {
/** Programmatically adds a rename directive for the given symbol. */
public void addJavaSymbolRename(final String origName, final String newName) {
- if(DEBUG_RENAMES) {
- System.err.print("\tRename "+origName+" -> "+newName);
- }
+ LOG.log(INFO, "\tRename {0} -> {1}", origName, newName);
final String prevValue = javaSymbolRenames.put(origName, newName);
if(null != prevValue && !prevValue.equals(newName)) {
throw new RuntimeException("Rename-Override Attampt: "+origName+" -> "+newName+
", but "+origName+" -> "+prevValue+" already exist. Run in 'debug' mode to analyze!");
}
- if(DEBUG_RENAMES) {
- System.err.println();
- }
-
Set<String> origNames = javaRenamedSymbols.get(newName);
if(null == origNames) {
origNames = new HashSet<String>();
@@ -965,6 +1162,16 @@ public class JavaConfiguration {
origNames.add(origName);
}
+ /** Programmatically adds a delegate implementation directive for the given symbol. */
+ public void addDelegateImplementation(final String origName, final String renamedImpl) {
+ LOG.log(INFO, "\tDelegateImplementation {0} -> {1}", origName, renamedImpl);
+ final String prevValue = delegatedImplementation.put(origName, renamedImpl);
+ if(null != prevValue && !prevValue.equals(renamedImpl)) {
+ throw new RuntimeException("Rename-Override Attampt: "+origName+" -> "+renamedImpl+
+ ", but "+origName+" -> "+prevValue+" already exist. Run in 'debug' mode to analyze!");
+ }
+ }
+
/** Returns true if the emission style is AllStatic. */
public boolean allStatic() {
return emissionStyle == AllStatic;
@@ -1033,11 +1240,14 @@ 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));
}catch(final IllegalArgumentException ex) {
- LOG.log(WARNING, "Error parsing \"style\" command at line {0} in file \"{1}\"", new Object[]{lineNo, filename});
+ LOG.log(WARNING, "Error parsing \"style\" command at line {0} in file \"{1}\"", lineNo, filename);
}
} else if (cmd.equalsIgnoreCase("AccessControl")) {
readAccessControl(tok, filename, lineNo);
@@ -1047,6 +1257,8 @@ public class JavaConfiguration {
readOpaque(tok, filename, lineNo);
} else if (cmd.equalsIgnoreCase("ReturnsString")) {
readReturnsString(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("ReturnsOpaque")) {
+ readReturnsOpaque(tok, filename, lineNo);
} else if (cmd.equalsIgnoreCase("ReturnedArrayLength")) {
readReturnedArrayLength(tok, filename, lineNo);
// Warning: make sure delimiters are reset at the top of this loop
@@ -1147,10 +1359,10 @@ public class JavaConfiguration {
readParentClass(tok, filename, lineNo);
} else if (cmd.equalsIgnoreCase("RenameJavaType")) {
readRenameJavaType(tok, filename, lineNo);
- } else if (cmd.equalsIgnoreCase("RenameJavaSymbol") ||
- // Backward compatibility
- cmd.equalsIgnoreCase("RenameJavaMethod")) {
+ } else if (cmd.equalsIgnoreCase("RenameJavaSymbol")) {
readRenameJavaSymbol(tok, filename, lineNo);
+ } else if (cmd.equalsIgnoreCase("DelegateImplementation")) {
+ readDelegateImplementation(tok, filename, lineNo);
} else if (cmd.equalsIgnoreCase("RuntimeExceptionType")) {
runtimeExceptionType = readString("RuntimeExceptionType", tok, filename, lineNo);
} else if (cmd.equalsIgnoreCase("UnsupportedExceptionType")) {
@@ -1222,7 +1434,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) {
@@ -1243,6 +1455,17 @@ public class JavaConfiguration {
}
}
+ protected void readReturnsOpaque(final StringTokenizer tok, final String filename, final int lineNo) {
+ try {
+ final JavaType javaType = JavaType.createForOpaqueClass(stringToPrimitiveType(tok.nextToken()));
+ final String funcName = tok.nextToken();
+ returnsOpaqueJType.put(funcName, javaType);
+ } catch (final Exception e) {
+ throw new RuntimeException("Error parsing \"ReturnsOpaque\" command at line " + lineNo +
+ " in file \"" + filename + "\"", e);
+ }
+ }
+
protected void readReturnsString(final StringTokenizer tok, final String filename, final int lineNo) {
try {
final String name = tok.nextToken();
@@ -1684,6 +1907,17 @@ public class JavaConfiguration {
}
}
+ public void readDelegateImplementation(final StringTokenizer tok, final String filename, final int lineNo) {
+ try {
+ final String fromName = tok.nextToken();
+ final String toName = tok.nextToken();
+ addDelegateImplementation(fromName, toName);
+ } catch (final NoSuchElementException e) {
+ throw new RuntimeException("Error parsing \"DelegateImplementation\" command at line " + lineNo +
+ " in file \"" + filename + "\": missing expected parameter", e);
+ }
+ }
+
protected void readJavaPrologueOrEpilogue(final StringTokenizer tok, final String filename, final int lineNo, final boolean prologue) {
try {
String methodName = tok.nextToken();
@@ -1755,6 +1989,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..02e56a4 100644
--- a/src/java/com/jogamp/gluegen/JavaEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaEmitter.java
@@ -40,22 +40,56 @@
package com.jogamp.gluegen;
-import com.jogamp.common.nio.Buffers;
-import com.jogamp.common.os.DynamicLookupHelper;
-import com.jogamp.common.os.MachineDataInfo;
-
-import java.io.*;
-import java.util.*;
-import java.text.MessageFormat;
-
-import com.jogamp.gluegen.cgram.types.*;
-
+import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PACKAGE_PRIVATE;
+import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PRIVATE;
+import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PROTECTED;
+import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PUBLIC;
+import static com.jogamp.gluegen.JavaEmitter.MethodAccess.PUBLIC_ABSTRACT;
+import static java.util.logging.Level.FINE;
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.nio.Buffer;
-import java.util.logging.Logger;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import jogamp.common.os.MachineDataInfoRuntime;
-import static java.util.logging.Level.*;
-import static com.jogamp.gluegen.JavaEmitter.MethodAccess.*;
+
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.common.os.DynamicLookupHelper;
+import com.jogamp.common.os.MachineDataInfo;
+import com.jogamp.common.util.ArrayHashMap;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+import com.jogamp.gluegen.Logging.LoggerIf;
+import com.jogamp.gluegen.cgram.types.AliasedSymbol;
+import com.jogamp.gluegen.cgram.types.ArrayType;
+import com.jogamp.gluegen.cgram.types.CVAttributes;
+import com.jogamp.gluegen.cgram.types.CompoundType;
+import com.jogamp.gluegen.cgram.types.Field;
+import com.jogamp.gluegen.cgram.types.FunctionSymbol;
+import com.jogamp.gluegen.cgram.types.FunctionType;
+import com.jogamp.gluegen.cgram.types.IntType;
+import com.jogamp.gluegen.cgram.types.PointerType;
+import com.jogamp.gluegen.cgram.types.SizeThunk;
+import com.jogamp.gluegen.cgram.types.StructLayout;
+import com.jogamp.gluegen.cgram.types.Type;
+import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol;
+import com.jogamp.gluegen.cgram.types.TypeDictionary;
// PROBLEMS:
// - what if something returns 'const int *'? Could we
@@ -70,7 +104,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;
@@ -97,13 +130,19 @@ public class JavaEmitter implements GlueEmitter {
private final String javaName;
}
- private PrintWriter javaWriter; // Emits either interface or, in AllStatic mode, everything
+ private String javaFileName; // of javaWriter or javaImplWriter
+ private PrintWriter javaWriter; // Emits either interface or, in AllStatic mode, everything
private PrintWriter javaImplWriter; // Only used in non-AllStatic modes for impl class
+ private String cFileName; // of cWriter
private PrintWriter cWriter;
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 LoggerIf LOG;
+
+ public JavaEmitter() {
+ LOG = Logging.getLogger(JavaEmitter.class.getPackage().getName(), JavaEmitter.class.getSimpleName());
+ }
@Override
public void readConfigurationFile(final String filename) throws Exception {
@@ -111,61 +150,129 @@ 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 boolean preserveOrder,
+ final List<T> outList) {
+ final JavaConfiguration cfg = getConfig();
+ final ArrayHashMap<String, T> symMap =
+ new ArrayHashMap<String, T>(false, 100, ArrayHashMap.DEFAULT_LOAD_FACTOR);
+ for (final T sym : inList) {
+ final String origName = sym.getName();
+ final String newName = cfg.getJavaSymbolRename(origName);
+ final T dupSym;
+ if( null != newName ) {
+ // Alias Name
+ dupSym = symMap.get(newName);
+ if( null != dupSym ) {
+ // only rename to allow 'equalSemantics' to not care ..
+ sym.rename(newName);
+ }
+ } else {
+ // Original Name
+ dupSym = symMap.get(origName);
+ }
+ if( null != dupSym ) {
+ // Duplicate alias .. check
+ if( !dupSym.equalSemantics(sym) ) {
+ final ASTLocusTag loc;
+ final String preLoc;
+ if( sym instanceof ASTLocusTagProvider ) {
+ loc = ((ASTLocusTagProvider)sym).getASTLocusTag();
+ } else {
+ loc = null;
+ }
+ if( dupSym instanceof ASTLocusTagProvider ) {
+ preLoc = String.format(",%n %s: previous definition is here",
+ ((ASTLocusTagProvider)dupSym).getASTLocusTag().toString(new StringBuilder(), "note", true));
+ } else {
+ preLoc = "";
+ }
+ final String mode = null != newName ? "alias" : "orig";
+ final String message =
+ String.format("Duplicate Name (%s) w/ incompatible value:%n this '%s',%n have '%s'%s",
+ mode, sym.getAliasedString(), dupSym.getAliasedString(), preLoc);
+ throw new GlueGenException(message, loc);
+ }
+ }
+ if( null != newName ) {
+ // Alias Name
+ if( null != dupSym ) {
+ // Duplicate alias .. add aliased name
+ dupSym.addAliasedName(origName);
+ } else {
+ // No duplicate .. rename and add
+ sym.rename(newName);
+ symMap.put(newName, sym);
+ }
+ } else {
+ // Original Name
+ if( null != dupSym ) {
+ // Duplicate orig .. drop
+ } else {
+ // No duplicate orig .. add
+ symMap.put(origName, sym);
+ }
+ }
+ }
+ outList.addAll(symMap.getData());
+ if( !preserveOrder ) {
+ // 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, true, new ArrayList<ConstantDefinition>(100));
+ functions = filterSymbolsInt(inFuncList, true, 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()) {
controls.forceStructEmission(structs);
}
- if (!cfg.structsOnly()) {
+ if ( !cfg.structsOnly() ) {
try {
openWriters();
} catch (final Exception e) {
throw new RuntimeException("Unable to open files for writing", e);
}
emitAllFileHeaders();
-
- // Handle renaming of constants
- controls.runSymbolFilter(new ConstantRenamer());
}
}
@Override
public void endEmission() {
- if (!cfg.structsOnly()) {
+ if ( !cfg.structsOnly() ) {
emitAllFileFooters();
try {
@@ -178,177 +285,11 @@ public class JavaEmitter implements GlueEmitter {
@Override
public void beginDefines() throws Exception {
- if ((cfg.allStatic() || cfg.emitInterface()) && !cfg.structsOnly()) {
+ if ( ( cfg.allStatic() || cfg.emitInterface() ) && !cfg.structsOnly() ) {
javaWriter().println();
}
}
- protected static int getJavaRadix(final String name, final String value) {
- // FIXME: need to handle when type specifier is in last char (e.g.,
- // "1.0d or 2759L", because parseXXX() methods don't allow the type
- // specifier character in the string.
- //
- //char lastChar = value.charAt(value.length()-1);
-
- try {
- // see if it's a long or int
- int radix;
- String parseValue;
- // FIXME: are you allowed to specify hex/octal constants with
- // negation, e.g. "-0xFF" or "-056"? If so, need to modify the
- // following "if(..)" checks and parseValue computation
- if (value.startsWith("0x") || value.startsWith("0X")) {
- radix = 16;
- parseValue = value.substring(2);
- }
- else if (value.startsWith("0") && value.length() > 1) {
- // TODO: is "0" the prefix in C to indicate octal???
- radix = 8;
- parseValue = value.substring(1);
- }
- else {
- radix = 10;
- parseValue = value;
- }
- //System.err.println("parsing " + value + " as long w/ radix " + radix);
- Long.parseLong(parseValue, radix);
- return radix;
- } catch (final NumberFormatException e) {
- try {
- // see if it's a double or float
- Double.parseDouble(value);
- return 10;
- } catch (final NumberFormatException e2) {
- throw new RuntimeException(
- "Cannot emit define \""+name+"\": value \""+value+
- "\" cannot be assigned to a int, long, float, or double", e2);
- }
- }
- }
-
- protected static Object getJavaValue(final String name, final String value) {
-
- // "calculates" the result type of a simple expression
- // example: (2+3)-(2.0f-3.0) -> Double
- // example: (1 << 2) -> Integer
-
- final Scanner scanner = new Scanner(value).useDelimiter("[+-/*/></(/)]");
-
- Object resultType = null;
-
- while (scanner.hasNext()) {
-
- final String t = scanner.next().trim();
-
- if(0<t.length()) {
- final Object type = getJavaValue2(name, t);
-
- //fast path
- if(type instanceof Double)
- return type;
-
- if(resultType != null) {
-
- if(resultType instanceof Integer) {
- if(type instanceof Long || type instanceof Float || type instanceof Double)
- resultType = type;
- }else if(resultType instanceof Long) {
- if(type instanceof Float || type instanceof Double)
- resultType = type;
- }else if(resultType instanceof Float) {
- if(type instanceof Float)
- resultType = type;
- }
- }else{
- resultType = type;
- }
-
- //fast path
- if(resultType instanceof Double)
- return type;
- }
- }
-
- return resultType;
- }
-
- private static Object getJavaValue2(final String name, final String value) {
- // FIXME: need to handle when type specifier is in last char (e.g.,
- // "1.0d or 2759L", because parseXXX() methods don't allow the type
- // specifier character in the string.
- //
- final char lastChar = value.charAt(value.length()-1);
-
- try {
- // see if it's a long or int
- int radix;
- String parseValue;
- // FIXME: are you allowed to specify hex/octal constants with
- // negation, e.g. "-0xFF" or "-056"? If so, need to modify the
- // following "if(..)" checks and parseValue computation
- if (value.startsWith("0x") || value.startsWith("0X")) {
- radix = 16;
- parseValue = value.substring(2);
- } else if (value.startsWith("0") && value.length() > 1) {
- // TODO: is "0" the prefix in C to indicate octal???
- radix = 8;
- parseValue = value.substring(1);
- } else {
- radix = 10;
- parseValue = value;
- }
- if(lastChar == 'u' || lastChar == 'U') {
- parseValue = parseValue.substring(0, parseValue.length()-1);
- }
-
- //System.err.println("parsing " + value + " as long w/ radix " + radix);
- final long longVal = Long.parseLong(parseValue, radix);
- // if constant is small enough, store it as an int instead of a long
- if (longVal > Integer.MIN_VALUE && longVal < Integer.MAX_VALUE) {
- return (int)longVal;
- }
- return longVal;
-
- } catch (final NumberFormatException e) {
- try {
- // see if it's a double or float
- final double dVal = Double.parseDouble(value);
- final double absVal = Math.abs(dVal);
- // if constant is small enough, store it as a float instead of a double
- if (absVal < Float.MIN_VALUE || absVal > Float.MAX_VALUE) {
- return new Double(dVal);
- }
- return new Float((float) dVal);
- } catch (final NumberFormatException e2) {
- throw new RuntimeException(
- "Cannot emit define \""+name+"\": value \""+value+
- "\" cannot be assigned to a int, long, float, or double", e2);
- }
- }
- }
-
-
- protected static String getJavaType(final String name, final String value) {
- final Object oval = getJavaValue(name, value);
- return getJavaType(name, oval);
- }
-
- protected static String getJavaType(final String name, final Object oval) {
- if(oval instanceof Integer) {
- return "int";
- } else if(oval instanceof Long) {
- return "long";
- } else if(oval instanceof Float) {
- return "float";
- } else if(oval instanceof Double) {
- return "double";
- }
-
- throw new RuntimeException(
- "Cannot emit define (2) \""+name+"\": value \""+oval+
- "\" cannot be assigned to a int, long, float, or double");
- }
-
/** Mangle a class, package or function name for JNI usage, i.e. replace all '.' w/ '_' */
protected static String jniMangle(final String name) {
return name.replaceAll("_", "_1").replace('.', '_');
@@ -358,10 +299,12 @@ public class JavaEmitter implements GlueEmitter {
return "Java_"+jniMangle(javaPackageName)+"_"+jniMangle(javaClassName);
}
+ private final Map<String, ConstantDefinition.JavaExpr> constMap =
+ new HashMap<String, ConstantDefinition.JavaExpr>();
+
@Override
public void emitDefine(final ConstantDefinition def, final String optionalComment) throws Exception {
-
- if (cfg.allStatic() || cfg.emitInterface()) {
+ if ( ( cfg.allStatic() || cfg.emitInterface() ) && !cfg.structsOnly() ) {
// TODO: Some defines (e.g., GL_DOUBLE_EXT in gl.h) are defined in terms
// of other defines -- should we emit them as references to the original
// define (not even sure if the lexer supports this)? Right now they're
@@ -371,24 +314,22 @@ public class JavaEmitter implements GlueEmitter {
// currently only emits only numeric defines -- if it handled #define'd
// objects it would make a bigger difference.
- final String name = def.getName();
- String value = def.getValue();
-
- if (!cfg.shouldIgnoreInInterface(name)) {
- final String type = getJavaType(name, value);
+ if ( !cfg.shouldIgnoreInInterface(def) ) {
+ final ConstantDefinition.JavaExpr constExpr = def.computeJavaExpr(constMap);
+ constMap.put(def.getName(), constExpr);
+ javaWriter().print(" /** ");
if (optionalComment != null && optionalComment.length() != 0) {
- javaWriter().println(" /** " + optionalComment + " */");
+ javaWriter().print(optionalComment);
+ javaWriter().print(" - ");
}
- String suffix = "";
- if(!value.endsWith(")")) {
- if (type.equals("float") && !value.endsWith("f")) {
- suffix = "f";
- }else if(value.endsWith("u") || value.endsWith("U")) {
- value = value.substring(0, value.length()-1);
- }
+ javaWriter().print("CType: ");
+ if( constExpr.resultType.isUnsigned ) {
+ javaWriter().print("unsigned ");
}
-
- javaWriter().println(" public static final " + type + " " + name + " = " + value + suffix + ";");
+ javaWriter().print(constExpr.resultJavaTypeName);
+ javaWriter().println(" */");
+ javaWriter().println(" public static final " + constExpr.resultJavaTypeName +
+ " " + def.getName() + " = " + constExpr.javaExpression + ";");
}
}
}
@@ -402,67 +343,51 @@ 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
- if ((cfg.allStatic() || cfg.emitInterface()) && !cfg.structsOnly()) {
+ if ( ( cfg.allStatic() || cfg.emitInterface() ) && !cfg.structsOnly() ) {
javaWriter().println();
}
}
@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);
+ public Iterator<FunctionSymbol> emitFunctions(final List<FunctionSymbol> funcsToBind) throws Exception {
+ if ( !cfg.structsOnly() ) {
+ // Bind all the C funcs to Java methods
+ final ArrayList<FunctionEmitter> methodBindingEmitters = new ArrayList<FunctionEmitter>(2*funcsToBind.size());
+ {
+ int i=0;
+ for (final FunctionSymbol cFunc : funcsToBind) {
+ // Check to see whether this function should be ignored
+ if ( !cfg.shouldIgnoreInImpl(cFunc) ) {
+ methodBindingEmitters.addAll(generateMethodBindingEmitters(cFunc));
+ LOG.log(INFO, cFunc.getASTLocusTag(), "Non-Ignored Impl[{0}]: {1}", i++, cFunc);
+ }
- 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());
}
- });
-
- // 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));
- }
-
- }
+ }
- // 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
+ // Emit all the methods
+ {
+ 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
+ LOG.log(INFO, cFunc.getASTLocusTag(), "Non-Ignored Intf[{0}]: {1}", i++, cFunc);
+ }
+ } catch (final Exception e) {
+ throw new GlueGenException(
+ "Error while emitting binding for \"" + emitter.getCSymbol().getAliasedString() + "\"",
+ emitter.getCSymbol().getASTLocusTag(), 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
return funcsToBind.iterator();
}
@@ -506,25 +431,33 @@ public class JavaEmitter implements GlueEmitter {
* native code because it doesn't need any processing of the
* outgoing arguments).
*/
- protected void generatePublicEmitters(final MethodBinding binding, final List<FunctionEmitter> allEmitters, final boolean signatureOnly) {
- if (cfg.manuallyImplement(binding.getName()) && !signatureOnly) {
+ protected void generatePublicEmitters(final MethodBinding binding, final List<FunctionEmitter> allEmitters,
+ final boolean signatureOnly) {
+ final FunctionSymbol cSymbol = binding.getCSymbol();
+ if ( !signatureOnly && cfg.manuallyImplement(cSymbol) ) {
// We only generate signatures for manually-implemented methods;
// user provides the implementation
return;
}
- final MethodAccess accessControl = cfg.accessControl(binding.getName());
+ final MethodAccess accessControl;
+
+ if ( !signatureOnly && null != binding.getDelegationImplName() ) {
+ // private access for delegation implementation methods
+ accessControl = PRIVATE;
+ } else {
+ accessControl = cfg.accessControl(binding.getName());
+ }
+
// We should not emit anything except public APIs into interfaces
- if (signatureOnly && (accessControl != PUBLIC)) {
+ if ( signatureOnly && PUBLIC != accessControl ) {
return;
}
- final PrintWriter writer = ((signatureOnly || cfg.allStatic()) ? javaWriter() : javaImplWriter());
-
// It's possible we may not need a body even if signatureOnly is
// set to false; for example, if the routine doesn't take any
// arrays or buffers as arguments
- final boolean isUnimplemented = cfg.isUnimplemented(binding.getName());
+ final boolean isUnimplemented = cfg.isUnimplemented(cSymbol);
final List<String> prologue = cfg.javaPrologueForMethod(binding, false, false);
final List<String> epilogue = cfg.javaEpilogueForMethod(binding, false, false);
final boolean needsBody = isUnimplemented ||
@@ -536,25 +469,31 @@ public class JavaEmitter implements GlueEmitter {
if( !requiresStaticInitialization ) {
requiresStaticInitialization = binding.signatureRequiresStaticInitialization();
if( requiresStaticInitialization ) {
- LOG.log(INFO, "StaticInit Trigger.1 \"{0}\"", binding);
+ LOG.log(INFO, cSymbol.getASTLocusTag(), "StaticInit Trigger.1 \"{0}\"", binding);
}
}
+ final boolean emitBody = !signatureOnly && needsBody;
+ final boolean isNativeMethod = !isUnimplemented && !needsBody && !signatureOnly;
+
+ final PrintWriter writer = ((signatureOnly || cfg.allStatic()) ? javaWriter() : javaImplWriter());
+
final JavaMethodBindingEmitter emitter =
new JavaMethodBindingEmitter(binding,
writer,
cfg.runtimeExceptionType(),
cfg.unsupportedExceptionType(),
- !signatureOnly && needsBody,
+ emitBody, // emitBody
cfg.tagNativeBinding(),
- false, // eraseBufferAndArrayTypes
+ false, // eraseBufferAndArrayTypes
cfg.useNIOOnly(binding.getName()),
cfg.useNIODirectOnly(binding.getName()),
- false,
- false,
- false,
- isUnimplemented,
- signatureOnly,
+ false, // forDirectBufferImplementation
+ false, // forIndirectBufferAndArrayImplementation
+ isUnimplemented, // isUnimplemented
+ signatureOnly, // isInterface
+ isNativeMethod, // isNativeMethod
+ false, // isPrivateNativeMethod
cfg);
switch (accessControl) {
case PUBLIC: emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); break;
@@ -565,7 +504,7 @@ public class JavaEmitter implements GlueEmitter {
if (cfg.allStatic()) {
emitter.addModifier(FunctionEmitter.STATIC);
}
- if (!isUnimplemented && !needsBody && !signatureOnly) {
+ if (isNativeMethod) {
emitter.addModifier(JavaMethodBindingEmitter.NATIVE);
}
emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName()));
@@ -585,7 +524,8 @@ public class JavaEmitter implements GlueEmitter {
*/
protected void generatePrivateEmitters(final MethodBinding binding,
final List<FunctionEmitter> allEmitters) {
- if (cfg.manuallyImplement(binding.getName())) {
+ final FunctionSymbol cSymbol = binding.getCSymbol();
+ if (cfg.manuallyImplement(cSymbol)) {
// Don't produce emitters for the implementation class
return;
}
@@ -594,11 +534,11 @@ public class JavaEmitter implements GlueEmitter {
cfg.javaPrologueForMethod(binding, false, false) != null ||
cfg.javaEpilogueForMethod(binding, false, false) != null ;
- if ( !cfg.isUnimplemented( binding.getName() ) ) {
+ if ( !cfg.isUnimplemented( cSymbol ) ) {
if( !requiresStaticInitialization ) {
requiresStaticInitialization = binding.signatureRequiresStaticInitialization();
if( requiresStaticInitialization ) {
- LOG.log(INFO, "StaticInit Trigger.2 \"{0}\"", binding);
+ LOG.log(INFO, cSymbol.getASTLocusTag(), "StaticInit Trigger.2 \"{0}\"", binding);
}
}
@@ -621,16 +561,17 @@ public class JavaEmitter implements GlueEmitter {
writer,
cfg.runtimeExceptionType(),
cfg.unsupportedExceptionType(),
- false,
+ false, // emitBody
cfg.tagNativeBinding(),
- true, // eraseBufferAndArrayTypes
+ true, // eraseBufferAndArrayTypes
cfg.useNIOOnly(binding.getName()),
cfg.useNIODirectOnly(binding.getName()),
- true,
- true,
- false,
- false,
- false,
+ true, // forDirectBufferImplementation
+ false, // forIndirectBufferAndArrayImplementation
+ false, // isUnimplemented
+ false, // isInterface
+ true, // isNativeMethod
+ true, // isPrivateNativeMethod
cfg);
emitter.addModifier(JavaMethodBindingEmitter.PRIVATE);
if (cfg.allStatic()) {
@@ -658,7 +599,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);
}
@@ -700,18 +641,34 @@ public class JavaEmitter implements GlueEmitter {
* Generate all appropriate Java bindings for the specified C function
* symbols.
*/
- protected List<? extends FunctionEmitter> generateMethodBindingEmitters(final Set<MethodBinding> methodBindingSet, final FunctionSymbol sym) throws Exception {
-
+ protected List<? extends FunctionEmitter> generateMethodBindingEmitters(final FunctionSymbol sym) throws Exception {
final ArrayList<FunctionEmitter> allEmitters = new ArrayList<FunctionEmitter>();
-
try {
+ if( cfg.emitInterface() ) {
+ generateMethodBindingEmittersImpl(allEmitters, sym, true);
+ }
+ if( cfg.emitImpl() ) {
+ generateMethodBindingEmittersImpl(allEmitters, sym, false);
+ }
+ } catch (final Exception e) {
+ throw new GlueGenException("Error while generating bindings for \"" + sym + "\"", sym.getASTLocusTag(), e);
+ }
+
+ return allEmitters;
+ }
+ private void generateMethodBindingEmittersImpl(final ArrayList<FunctionEmitter> allEmitters,
+ final FunctionSymbol sym,
+ final boolean forInterface) throws Exception
+ {
// Get Java binding for the function
- final MethodBinding mb = bindFunction(sym, null, null, machDescJava);
+ final MethodBinding mb = bindFunction(sym, forInterface, machDescJava, null, null);
// JavaTypes representing C pointers in the initial
// MethodBinding have not been lowered yet to concrete types
final List<MethodBinding> bindings = expandMethodBinding(mb);
+ final HashSet<MethodBinding> methodBindingSet = new HashSet<MethodBinding>();
+
for (final MethodBinding binding : bindings) {
if(!methodBindingSet.add(binding)) {
@@ -772,25 +729,19 @@ public class JavaEmitter implements GlueEmitter {
// Note in particular that the public entry point taking an
// array is merely a special case of the indirect buffer case.
- if (cfg.emitInterface()) {
+ if ( forInterface ) {
generatePublicEmitters(binding, allEmitters, true);
- }
- if (cfg.emitImpl()) {
+ } else {
generatePublicEmitters(binding, allEmitters, false);
generatePrivateEmitters(binding, allEmitters);
}
} // end iteration over expanded bindings
- } catch (final Exception e) {
- throw new RuntimeException("Error while generating bindings for \"" + sym + "\"", e);
}
- return allEmitters;
- }
-
@Override
public void endFunctions() throws Exception {
- if (!cfg.structsOnly()) {
+ if ( !cfg.structsOnly() ) {
if (cfg.allStatic() || cfg.emitInterface()) {
emitCustomJavaCode(javaWriter(), cfg.className());
}
@@ -821,40 +772,89 @@ 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 structCTypedefPtr) throws Exception {
+ final String structCTypeName, typedefedName;
{
- String _name = structCType.getName();
- if (_name == null && alternateName != null) {
- _name = alternateName;
+ final String _name = structCType.getName();
+ if ( null != structCTypedefPtr && null != structCTypedefPtr.getName() ) {
+ // always use typedef'ed name if available
+ typedefedName = structCTypedefPtr.getName();
+ structCTypeName = typedefedName;
+ } else {
+ // fall back to actual struct type name
+ typedefedName = null;
+ structCTypeName = _name;
}
- structCTypeName = _name;
- }
-
- if (structCTypeName == null) {
- final String structName = structCType.getStructName();
- if ( null != structName && cfg.shouldIgnoreInInterface(structName) ) {
+ LOG.log(INFO, structCType.getASTLocusTag(), "Struct emission of structCType {0}", structCType);
+ LOG.log(INFO, structCType.getASTLocusTag()," structCTypedefPtr {0}", structCTypedefPtr);
+ LOG.log(INFO, structCType.getASTLocusTag()," : structCTypeName \"{0}\" -> typedefedName \"{1}\" -> \"{2}\"",
+ _name, typedefedName, structCTypeName);
+ if ( null == structCTypeName ) {
+ LOG.log(INFO, structCType.getASTLocusTag(),
+ "skipping emission of unnamed struct {0} w/o typedef", structCType);
+ return;
+ }
+ final AliasedSymbol.AliasedSymbolImpl aliases = new AliasedSymbol.AliasedSymbolImpl(structCTypeName);
+ aliases.addAliasedName(_name);
+ aliases.addAliasedName(typedefedName);
+ if ( cfg.shouldIgnoreInInterface(aliases) ) {
+ LOG.log(INFO, structCType.getASTLocusTag(),
+ "skipping emission of ignored \"{0}\": {1}", aliases, structCType);
return;
}
- LOG.log(WARNING, "skipping emission of unnamed struct \"{0}\"", structCType);
- return;
}
- if (cfg.shouldIgnoreInInterface(structCTypeName)) {
- return;
+ if( null != structCTypedefPtr && isOpaque(structCTypedefPtr) ) {
+ LOG.log(INFO, structCType.getASTLocusTag(),
+ "skipping emission of opaque typedef {0}", structCTypedefPtr);
+ return;
+ }
+ if( isOpaque(structCType) ) {
+ LOG.log(INFO, structCType.getASTLocusTag(),
+ "skipping emission of opaque c-struct {0}", structCType);
+ return;
}
- final Type containingCType = canonicalize(new PointerType(SizeThunk.POINTER, structCType, 0));
+ final Type containingCType;
+ {
+ // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser)
+ final Type aptr;
+ int mode;
+ if( null != typedefedName ) {
+ aptr = structCTypedefPtr;
+ mode = 1;
+ } else {
+ aptr = new PointerType(SizeThunk.POINTER, structCType, 0);
+ aptr.setTypedefName(typedefedName);
+ mode = 2;
+ }
+ containingCType = canonicalize(aptr);
+ LOG.log(INFO, structCType.getASTLocusTag(), "containingCType[{0}]: {1} -canon-> {2}", mode, aptr, containingCType);
+ }
final JavaType containingJType = typeToJavaType(containingCType, null);
- if (!containingJType.isCompoundTypeWrapper()) {
- return;
+ if( containingJType.isOpaqued() ) {
+ LOG.log(INFO, structCType.getASTLocusTag(),
+ "skipping emission of opaque {0}, {1}", containingJType, structCType);
+ return;
+ }
+ if( !containingJType.isCompoundTypeWrapper() ) {
+ LOG.log(WARNING, structCType.getASTLocusTag(),
+ "skipping emission of non-compound {0}, {1}", containingJType, structCType);
+ return;
}
final String containingJTypeName = containingJType.getName();
+ LOG.log(INFO, structCType.getASTLocusTag(),
+ "perform emission of \"{0}\" -> \"{1}\": {2}", structCTypeName, containingJTypeName, structCType);
+
+ if( 0 == structCType.getNumFields() ) {
+ LOG.log(INFO, structCType.getASTLocusTag(),
+ "emission of \"{0}\" with zero fields {1}", containingJTypeName, structCType);
+ }
this.requiresStaticInitialization = false; // reset
@@ -884,13 +884,13 @@ public class JavaEmitter implements GlueEmitter {
final Field field = structCType.getField(i);
final Type fieldType = field.getType();
- final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, field.getName());
+ final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, field.getName());
if (!cfg.shouldIgnoreInInterface(cfgFieldName0)) {
final String renamed = cfg.getJavaSymbolRename(cfgFieldName0);
final String fieldName = renamed==null ? field.getName() : renamed;
- final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, fieldName);
+ final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, fieldName);
if ( fieldType.isFunctionPointer() || fieldType.isPointer() || requiresGetCStringLength(fieldType, cfgFieldName1) ) {
needsNativeCode = true;
@@ -978,11 +978,11 @@ public class JavaEmitter implements GlueEmitter {
for (int i = 0; i < structCType.getNumFields(); i++) {
final Field field = structCType.getField(i);
final Type fieldType = field.getType();
- final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, field.getName());
+ final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, field.getName());
if ( !cfg.shouldIgnoreInInterface(cfgFieldName0) ) {
final String renamed = cfg.getJavaSymbolRename(cfgFieldName0);
final String fieldName = null==renamed ? field.getName() : renamed;
- final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, fieldName);
+ final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, fieldName);
if (fieldType.isFunctionPointer()) {
// no offset/size for function pointer ..
if( GlueGen.debug() ) {
@@ -993,8 +993,8 @@ public class JavaEmitter implements GlueEmitter {
// handle the union in jawt_Win32DrawingSurfaceInfo (fabricate
// a name?)
if (fieldType.getName() == null) {
- throw new RuntimeException("Anonymous structs as fields not supported yet, field \"" +
- cfgFieldName1 + "\", "+fieldType.getDebugString());
+ throw new GlueGenException("Anonymous structs as fields not supported yet, field \"" +
+ cfgFieldName1 + "\", "+fieldType.getDebugString(), fieldType.getASTLocusTag());
}
if( GlueGen.debug() ) {
System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, cfgFieldName1, fieldType.getDebugString(), "compound");
@@ -1012,11 +1012,11 @@ public class JavaEmitter implements GlueEmitter {
try {
externalJavaType = typeToJavaType(fieldType, machDescJava);
} catch (final Exception e) {
- throw new RuntimeException("Error occurred while creating accessor for field \"" +
- cfgFieldName1 + "\", "+fieldType.getDebugString(), e);
+ throw new GlueGenException("Error occurred while creating accessor for field \"" +
+ cfgFieldName1 + "\", "+fieldType.getDebugString(), fieldType.getASTLocusTag(), e);
}
if( GlueGen.debug() ) {
- System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, fieldName, fieldType.getDebugString(), "MISC");
+ System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, cfgFieldName1, fieldType.getDebugString(), "MISC");
System.err.printf("SE.os.%02d: javaType %s%n", (i+1), externalJavaType.getDebugString());
}
if (externalJavaType.isPrimitive()) {
@@ -1040,6 +1040,7 @@ public class JavaEmitter implements GlueEmitter {
}
}
javaWriter.println();
+ // getDelegatedImplementation
if( !cfg.manuallyImplement(JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, "size")) ) {
javaWriter.println(" public static int size() {");
javaWriter.println(" return "+containingJTypeName+"_size[mdIdx];");
@@ -1073,52 +1074,62 @@ public class JavaEmitter implements GlueEmitter {
final Field field = structCType.getField(i);
final Type fieldType = field.getType();
- final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, field.getName());
+ final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, field.getName());
if (!cfg.shouldIgnoreInInterface(cfgFieldName0)) {
final String renamed = cfg.getJavaSymbolRename(cfgFieldName0);
final String fieldName = renamed==null ? field.getName() : renamed;
- final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, fieldName);
+ final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, fieldName);
+ final TypeInfo opaqueFieldType = cfg.typeInfo(fieldType);
+ final boolean isOpaqueFieldType = null != opaqueFieldType;
+ final TypeInfo opaqueField = cfg.canonicalNameOpaque(cfgFieldName1);
+ final boolean isOpaqueField = null != opaqueField;
if( GlueGen.debug() ) {
- System.err.printf("SE.ac.%02d: %s / %s, %s%n", (i+1), field, cfgFieldName1, fieldType.getDebugString());
+ System.err.printf("SE.ac.%02d: %s / %s (opaque %b), %s (opaque %b)%n", (i+1),
+ (i+1), field, cfgFieldName1, isOpaqueField, fieldType.getDebugString(), isOpaqueFieldType);
}
- if (fieldType.isFunctionPointer()) {
+ if ( fieldType.isFunctionPointer() && !isOpaqueField ) {
+ final FunctionSymbol func = new FunctionSymbol(field.getName(), fieldType.asPointer().getTargetType().asFunction());
+ func.rename(renamed); // null is OK
generateFunctionPointerCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName,
containingCType, containingJType, i,
- new FunctionSymbol(fieldName, fieldType.asPointer().getTargetType().asFunction()), cfgFieldName1);
- } else if (fieldType.isCompound()) {
+ func, cfgFieldName1);
+ } else if ( fieldType.isCompound() && !isOpaqueField ) {
// FIXME: will need to support this at least in order to
// handle the union in jawt_Win32DrawingSurfaceInfo (fabricate a name?)
if (fieldType.getName() == null) {
- throw new RuntimeException("Anonymous structs as fields not supported yet (field \"" +
- field + "\" in type \"" + structCTypeName + "\")");
+ throw new GlueGenException("Anonymous structs as fields not supported yet (field \"" +
+ field + "\" in type \"" + structCTypeName + "\")",
+ fieldType.getASTLocusTag());
}
javaWriter.println();
- generateGetterSignature(javaWriter, fieldType, false, false, fieldType.getName(), capitalizeString(fieldName), null, null);
+ generateGetterSignature(javaWriter, fieldType, false, false, fieldType.getName(), fieldName, capitalizeString(fieldName), null, null);
javaWriter.println(" {");
javaWriter.println(" return " + fieldType.getName() + ".create( accessor.slice( " +
fieldName+"_offset[mdIdx], "+fieldName+"_size[mdIdx] ) );");
javaWriter.println(" }");
- } else if ( fieldType.isArray() || fieldType.isPointer() ) {
- generateArrayGetterSetterCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName,
- containingCType, containingJType,
- i, field, fieldName, cfgFieldName1);
+ } else if ( ( fieldType.isArray() || fieldType.isPointer() ) && !isOpaqueField ) {
+ generateArrayGetterSetterCode(methodBindingSet, javaWriter, jniWriter, structCType, structCTypeName,
+ structClassPkgName, containingCType,
+ containingJType, i, field, fieldName, cfgFieldName1);
} else {
final JavaType javaType;
try {
javaType = typeToJavaType(fieldType, machDescJava);
} catch (final Exception e) {
- System.err.println("Error occurred while creating accessor for field \"" +
- field.getName() + "\", "+fieldType.getDebugString());
- throw(e);
+ throw new GlueGenException("Error occurred while creating accessor for field \"" +
+ field.getName() + "\", "+fieldType.getDebugString(), fieldType.getASTLocusTag(), e);
}
- if (javaType.isPrimitive()) {
+ if ( isOpaqueFieldType || isOpaqueField || javaType.isPrimitive()) {
// Primitive type
final boolean fieldTypeNativeSizeFixed = fieldType.getSize().hasFixedNativeSize();
final String javaTypeName;
- if ( isOpaque(fieldType) ) {
- javaTypeName = compatiblePrimitiveJavaTypeName(fieldType, javaType, machDescJava);
+ if ( isOpaqueFieldType ) {
+ javaTypeName = opaqueFieldType.javaType().getName();
+ } else if ( isOpaqueField ) {
+ javaTypeName = opaqueField.javaType().getName();
+ // javaTypeName = compatiblePrimitiveJavaTypeName(fieldType, javaType, machDescJava);
} else {
javaTypeName = javaType.getName();
}
@@ -1126,15 +1137,14 @@ public class JavaEmitter implements GlueEmitter {
final String capFieldName = capitalizeString(fieldName);
final String sizeDenominator = fieldType.isPointer() ? "pointer" : javaTypeName ;
- if(GlueGen.debug()) {
- System.err.println("Java.StructEmitter.Primitive: "+field.getName()+", "+fieldType.getDebugString()+", "+javaTypeName+", "+
- ", fixedSize "+fieldTypeNativeSizeFixed+", opaque "+isOpaque(fieldType)+", sizeDenominator "+sizeDenominator);
- }
+ LOG.log(FINE, structCType.getASTLocusTag(),
+ "Java.StructEmitter.Primitive: "+field.getName()+", "+fieldType+", "+javaTypeName+", "+
+ ", fixedSize "+fieldTypeNativeSizeFixed+", opaque[t "+isOpaqueFieldType+", f "+isOpaqueField+"], sizeDenominator "+sizeDenominator);
if( !fieldType.isConst() ) {
// Setter
javaWriter.println();
- generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capFieldName, null, javaTypeName, null, null);
+ generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capFieldName, null, javaTypeName, null, null);
javaWriter.println(" {");
if( fieldTypeNativeSizeFixed ) {
javaWriter.println(" accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val);");
@@ -1147,7 +1157,7 @@ public class JavaEmitter implements GlueEmitter {
// Getter
javaWriter.println();
- generateGetterSignature(javaWriter, fieldType, false, false, javaTypeName, capFieldName, null, null);
+ generateGetterSignature(javaWriter, fieldType, false, false, javaTypeName, fieldName, capFieldName, null, null);
javaWriter.println(" {");
javaWriter.print (" return ");
if( fieldTypeNativeSizeFixed ) {
@@ -1216,9 +1226,9 @@ public class JavaEmitter implements GlueEmitter {
private void generateGetterSignature(final PrintWriter writer, final Type origFieldType,
final boolean staticMethod, final boolean abstractMethod,
- final String returnTypeName, final String capitalizedFieldName,
- final String customArgs, final String arrayLengthExpr) {
- writer.print(" /** Getter for native field: "+origFieldType.getDebugString());
+ final String returnTypeName, final String fieldName,
+ final String capitalizedFieldName, final String customArgs, final String arrayLengthExpr) {
+ writer.print(" /** Getter for native field <code>"+fieldName+"</code>: "+origFieldType.getDebugString());
if( null != arrayLengthExpr ) {
writer.print(", with array length of <code>"+arrayLengthExpr+"</code>");
}
@@ -1231,10 +1241,10 @@ public class JavaEmitter implements GlueEmitter {
}
private void generateSetterSignature(final PrintWriter writer, final Type origFieldType, final boolean abstractMethod,
- final String returnTypeName, final String capitalizedFieldName,
- final String customArgsPre, final String paramTypeName, final String customArgsPost,
- final String arrayLengthExpr) {
- writer.print(" /** Setter for native field: "+origFieldType.getDebugString());
+ final String returnTypeName, final String fieldName,
+ final String capitalizedFieldName, final String customArgsPre, final String paramTypeName,
+ final String customArgsPost, final String arrayLengthExpr) {
+ writer.print(" /** Setter for native field <code>"+fieldName+"</code>: "+origFieldType.getDebugString());
if( null != arrayLengthExpr ) {
writer.print(", with array length of <code>"+arrayLengthExpr+"</code>");
}
@@ -1288,7 +1298,7 @@ public class JavaEmitter implements GlueEmitter {
final Type containingCType, final JavaType containingJType,
final int i, final FunctionSymbol funcSym, final String returnSizeLookupName) {
// Emit method call and associated native code
- final MethodBinding mb = bindFunction(funcSym, containingJType, containingCType, machDescJava);
+ final MethodBinding mb = bindFunction(funcSym, true /* forInterface */, machDescJava, containingJType, containingCType);
mb.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis
// JavaTypes representing C pointers in the initial
@@ -1310,16 +1320,17 @@ public class JavaEmitter implements GlueEmitter {
javaWriter,
cfg.runtimeExceptionType(),
cfg.unsupportedExceptionType(),
- true,
+ true, // emitBody
cfg.tagNativeBinding(),
false, // eraseBufferAndArrayTypes
useNIOOnly,
useNIODirectOnly,
- false,
- false, // FIXME: should unify this with the general emission code
+ false, // forDirectBufferImplementation
false, // forIndirectBufferAndArrayImplementation
- false, // FIXME: should unify this with the general emission code
- false,
+ false, // isUnimplemented
+ false, // isInterface
+ false, // isNativeMethod
+ false, // isPrivateNativeMethod
cfg);
emitter.addModifier(JavaMethodBindingEmitter.PUBLIC);
emitter.emit();
@@ -1330,17 +1341,17 @@ public class JavaEmitter implements GlueEmitter {
javaWriter,
cfg.runtimeExceptionType(),
cfg.unsupportedExceptionType(),
- false,
+ false, // emitBody
cfg.tagNativeBinding(),
- true, // eraseBufferAndArrayTypes
+ true, // eraseBufferAndArrayTypes
useNIOOnly,
useNIODirectOnly,
- true,
- true, // FIXME: should unify this with the general emission code
+ true, // forDirectBufferImplementation
false, // forIndirectBufferAndArrayImplementation
- false, // FIXME: should unify this with the general emission code
- false,
- cfg);
+ false, // isUnimplemented
+ false, // isInterface
+ false, // isNativeMethod
+ true, cfg);
emitter.addModifier(JavaMethodBindingEmitter.PRIVATE);
emitter.addModifier(JavaMethodBindingEmitter.NATIVE);
emitter.emit();
@@ -1355,7 +1366,7 @@ public class JavaEmitter implements GlueEmitter {
false,
true,
false, // forIndirectBufferAndArrayImplementation
- machDescJava);
+ machDescJava, getConfiguration());
cEmitter.setIsCStructFunctionPointer(true);
prepCEmitter(returnSizeLookupName, binding.getJavaReturnType(), cEmitter);
cEmitter.emit();
@@ -1369,7 +1380,7 @@ public class JavaEmitter implements GlueEmitter {
final int i, final FunctionSymbol funcSym,
final String returnSizeLookupName, final String docArrayLenExpr, final String nativeArrayLenExpr) {
// Emit method call and associated native code
- final MethodBinding mb = bindFunction(funcSym, containingJType, containingCType, machDescJava);
+ final MethodBinding mb = bindFunction(funcSym, true /* forInterface */, machDescJava, containingJType, containingCType);
mb.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis
// JavaTypes representing C pointers in the initial
@@ -1392,16 +1403,17 @@ public class JavaEmitter implements GlueEmitter {
javaWriter,
cfg.runtimeExceptionType(),
cfg.unsupportedExceptionType(),
- false,
- cfg.tagNativeBinding(),
- true, // eraseBufferAndArrayTypes
+ false, // emitBody
+ cfg.tagNativeBinding(), // tagNativeBinding
+ true, // eraseBufferAndArrayTypes
useNIOOnly,
useNIODirectOnly,
- true,
- true, // FIXME: should unify this with the general emission code
- false, // forIndirectBufferAndArrayImplementation
- false, // FIXME: should unify this with the general emission code
- false,
+ false, // forDirectBufferImplementation
+ false, // forIndirectBufferAndArrayImplementation
+ false, // isUnimplemented
+ true, // isInterface
+ true, // isNativeMethod
+ true, // isPrivateNativeMethod
cfg);
if( null != docArrayLenExpr ) {
emitter.setReturnedArrayLengthExpression(docArrayLenExpr, true);
@@ -1420,7 +1432,7 @@ public class JavaEmitter implements GlueEmitter {
false,
true,
false, // forIndirectBufferAndArrayImplementation
- machDescJava);
+ machDescJava, getConfiguration());
cEmitter.setIsCStructFunctionPointer(false);
final String lenExprSet;
if( null != nativeArrayLenExpr ) {
@@ -1470,14 +1482,16 @@ public class JavaEmitter implements GlueEmitter {
final String cfgVal = cfg.returnedArrayLength(returnSizeLookupName);
if( null != cfgVal ) {
if( hasFixedTypeLen[0] ) {
- System.err.println("WARNING: struct array field '"+returnSizeLookupName+"' of '"+type+"' length '"+Arrays.toString(length)+"' overwritten by cfg-expression: "+cfgVal);
+ LOG.log(WARNING, type.getASTLocusTag(),
+ "struct array field '"+returnSizeLookupName+"' of '"+type+"' length '"+Arrays.toString(length)+"' overwritten by cfg-expression: "+cfgVal);
}
return cfgVal;
}
if( hasFixedTypeLen[0] ) {
return lengthExpr.toString();
} else {
- System.err.println("WARNING: struct array field '"+returnSizeLookupName+"' length '"+Arrays.toString(length)+"' without fixed- nor configured-size: "+type.getDebugString());
+ LOG.log(WARNING, type.getASTLocusTag(),
+ "struct array field '"+returnSizeLookupName+"' length '"+Arrays.toString(length)+"' without fixed- nor configured-size: {0}", type);
return null;
}
}
@@ -1510,16 +1524,18 @@ public class JavaEmitter implements GlueEmitter {
private void generateArrayGetterSetterCode(final Set<MethodBinding> methodBindingSet,
final PrintWriter javaWriter, final PrintWriter jniWriter,
+ final CompoundType structCType,
final String structCTypeName, final String structClassPkgName,
final Type containingCType, final JavaType containingJType,
- final int i, final Field field, final String fieldName, final String returnSizeLookupName) throws Exception {
+ final int i, final Field field, final String fieldName,
+ final String returnSizeLookupName) throws Exception {
final Type fieldType = field.getType();
final JavaType javaType;
try {
javaType = typeToJavaType(fieldType, machDescJava);
} catch (final Exception e) {
- throw new RuntimeException("Error occurred while creating array/pointer accessor for field \"" +
- returnSizeLookupName + "\", "+fieldType.getDebugString(), e);
+ throw new GlueGenException("Error occurred while creating array/pointer accessor for field \"" +
+ returnSizeLookupName + "\", "+fieldType.getDebugString(), fieldType.getASTLocusTag(), e);
}
if( GlueGen.debug() ) {
System.err.printf("SE.ac.%02d: javaType %s%n", (i+1), javaType.getDebugString());
@@ -1586,7 +1602,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println();
final String msg = "SKIP ptr-ptr (depth "+pointerType.pointerDepth()+"): "+returnSizeLookupName +": "+fieldType;
javaWriter.println(" // "+msg);
- System.err.println("WARNING: "+msg);
+ LOG.log(WARNING, structCType.getASTLocusTag(), msg);
return;
}
}
@@ -1598,8 +1614,9 @@ public class JavaEmitter implements GlueEmitter {
try {
baseJElemType = typeToJavaType(baseCElemType, machDescJava);
} catch (final Exception e ) {
- throw new RuntimeException("Error occurred while creating array/pointer accessor for field \"" +
- returnSizeLookupName + "\", baseType "+baseCElemType.getDebugString()+", topType "+fieldType.getDebugString(), e);
+ throw new GlueGenException("Error occurred while creating array/pointer accessor for field \"" +
+ returnSizeLookupName + "\", baseType "+baseCElemType.getDebugString()+", topType "+fieldType.getDebugString(),
+ fieldType.getASTLocusTag(), e);
}
baseJElemTypeName = baseJElemType.getName();
baseCElemNativeSizeFixed = baseCElemType.isPrimitive() ? baseCElemType.getSize().hasFixedNativeSize() : true;
@@ -1609,7 +1626,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println();
final String msg = "SKIP primitive w/ platform dependent sized type in struct: "+returnSizeLookupName+": "+fieldType.getDebugString();
javaWriter.println(" // "+msg);
- System.err.println("WARNING: "+msg);
+ LOG.log(WARNING, structCType.getASTLocusTag(), msg);
return;
}
}
@@ -1625,7 +1642,7 @@ public class JavaEmitter implements GlueEmitter {
_arrayLengthExpr = "getCStringLengthImpl(pString)+1";
_arrayLengthExprIsConst = false;
this.requiresStaticInitialization = true;
- LOG.log(INFO, "StaticInit Trigger.3 \"{0}\"", returnSizeLookupName);
+ LOG.log(INFO, structCType.getASTLocusTag(), "StaticInit Trigger.3 \"{0}\"", returnSizeLookupName);
} else {
useGetCStringLength = false;
}
@@ -1635,7 +1652,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println();
final String msg = "SKIP unsized array in struct: "+returnSizeLookupName+": "+fieldType.getDebugString();
javaWriter.println(" // "+msg);
- System.err.println("WARNING: "+msg);
+ LOG.log(WARNING, structCType.getASTLocusTag(), msg);
return;
}
boolean _hasSingleElement=false;
@@ -1657,7 +1674,7 @@ public class JavaEmitter implements GlueEmitter {
//
if( !hasSingleElement && useFixedTypeLen[0] ) {
javaWriter.println();
- generateGetterSignature(javaWriter, fieldType, arrayLengthExprIsConst, false, "final int", capitalFieldName+"ArrayLength", null, arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, arrayLengthExprIsConst, false, "final int", fieldName, capitalFieldName+"ArrayLength", null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" return "+arrayLengthExpr+";");
javaWriter.println(" }");
@@ -1671,11 +1688,11 @@ public class JavaEmitter implements GlueEmitter {
// Setter Primitive Pointer
final String msg = "SKIP setter for primitive-pointer type in struct: "+returnSizeLookupName+": "+fieldType.getDebugString();
javaWriter.println(" // "+msg);
- System.err.println("INFO: "+msg);
+ LOG.log(INFO, structCType.getASTLocusTag(), msg);
} else {
// Setter Primitive Array
if( hasSingleElement ) {
- generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr);
+ generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr);
javaWriter.println(" {");
if( baseCElemNativeSizeFixed ) {
javaWriter.println(" accessor.set" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx], val);");
@@ -1685,7 +1702,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println(" return this;");
javaWriter.println(" }");
} else {
- generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr);
+ generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";");
javaWriter.println(" if( offset + val.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + val.length \"+val.length+\" > array-length \"+arrayLength); };");
@@ -1708,11 +1725,11 @@ public class JavaEmitter implements GlueEmitter {
// Setter Struct Pointer
final String msg = "SKIP setter for complex-pointer type in struct: "+returnSizeLookupName+": "+fieldType.getDebugString();
javaWriter.println(" // "+msg);
- System.err.println("INFO: "+msg);
+ LOG.log(INFO, structCType.getASTLocusTag(), msg);
} else {
// Setter Struct Array
if( hasSingleElement ) {
- generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr);
+ generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final int elemSize = "+baseJElemTypeName+".size();");
javaWriter.println(" final ByteBuffer destB = getBuffer();");
@@ -1728,7 +1745,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println(" return this;");
javaWriter.println(" }");
} else {
- generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr);
+ generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";");
javaWriter.println(" if( offset + val.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + val.length \"+val.length+\" > array-length \"+arrayLength); };");
@@ -1750,7 +1767,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println(" return this;");
javaWriter.println(" }");
javaWriter.println();
- generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, "final int index", baseJElemTypeName, null, arrayLengthExpr);
+ generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, "final int index", baseJElemTypeName, null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";");
javaWriter.println(" final int elemSize = "+baseJElemTypeName+".size();");
@@ -1779,12 +1796,12 @@ public class JavaEmitter implements GlueEmitter {
if( isPointer ) {
// Getter Primitive Pointer
final FunctionType ft = new FunctionType(dummyFuncTypeName, SizeThunk.POINTER, fieldType, 0);
- ft.addArgument(containingCType.getCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST),
+ ft.addArgument(containingCType.newCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST),
CMethodBindingEmitter.cThisArgumentName());
ft.addArgument(int32Type, nativeArrayLengthArg);
final FunctionSymbol fs = new FunctionSymbol("get"+capitalFieldName, ft);
jniWriter.println();
- jniWriter.print("static "+fs.toString());
+ jniWriter.print("static "+fs.toString(false));
jniWriter.println("{");
jniWriter.println(" return "+CMethodBindingEmitter.cThisArgumentName()+"->"+field.getName()+";");
jniWriter.println("}");
@@ -1792,7 +1809,7 @@ public class JavaEmitter implements GlueEmitter {
generateArrayPointerCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName,
containingCType, containingJType, i, fs, returnSizeLookupName, arrayLengthExpr, nativeArrayLengthArg);
javaWriter.println();
- generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeNameC+"Buffer", capitalFieldName, null, arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeNameC+"Buffer", fieldName, capitalFieldName, null, arrayLengthExpr);
javaWriter.println(" {");
if( useGetCStringLength ) {
javaWriter.println(" final int arrayLength = get"+capitalFieldName+"ArrayLength();");
@@ -1809,7 +1826,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println(" }");
if( isString && isByteBuffer ) {
javaWriter.println();
- generateGetterSignature(javaWriter, fieldType, false, false, "String", capitalFieldName+"AsString", null, arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, "String", fieldName, capitalFieldName+"AsString", null, arrayLengthExpr);
javaWriter.println(" {");
if( useGetCStringLength ) {
javaWriter.println(" final int arrayLength = get"+capitalFieldName+"ArrayLength();");
@@ -1829,7 +1846,7 @@ public class JavaEmitter implements GlueEmitter {
}
if( useGetCStringLength ) {
javaWriter.println();
- generateGetterSignature(javaWriter, fieldType, false, false, "final int", capitalFieldName+"ArrayLength", null, arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, "final int", fieldName, capitalFieldName+"ArrayLength", null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final long pString = PointerBuffer.wrap( accessor.slice(" + fieldName+"_offset[mdIdx], PointerBuffer.ELEMENT_SIZE) ).get(0);");
javaWriter.println(" return "+arrayLengthExpr+";");
@@ -1838,7 +1855,7 @@ public class JavaEmitter implements GlueEmitter {
} else {
// Getter Primitive Array
if( hasSingleElement ) {
- generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName, capitalFieldName, null, arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName, fieldName, capitalFieldName, null, arrayLengthExpr);
javaWriter.println(" {");
if( baseCElemNativeSizeFixed ) {
javaWriter.println(" return accessor.get" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx]);");
@@ -1848,7 +1865,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println(" }");
javaWriter.println();
} else {
- generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeNameC+"Buffer", capitalFieldName, null, arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeNameC+"Buffer", fieldName, capitalFieldName, null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.print(" return accessor.slice(" + fieldName+"_offset[mdIdx], Buffers.SIZEOF_"+baseJElemTypeNameU+" * "+arrayLengthExpr+")");
if( !isByteBuffer ) {
@@ -1858,7 +1875,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println(" }");
javaWriter.println();
if( isString && isByteBuffer ) {
- generateGetterSignature(javaWriter, fieldType, false, false, "String", capitalFieldName+"AsString", null, arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, "String", fieldName, capitalFieldName+"AsString", null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final int offset = " + fieldName+"_offset[mdIdx];");
javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";");
@@ -1872,7 +1889,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println(" return new String(ba, 0, i);");
javaWriter.println(" }");
} else {
- generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName+"[]", capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName+"[]", fieldName, capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";");
javaWriter.println(" if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + result.length \"+result.length+\" > array-length \"+arrayLength); };");
@@ -1887,12 +1904,12 @@ public class JavaEmitter implements GlueEmitter {
if( isPointer ) {
// Getter Struct Pointer
final FunctionType ft = new FunctionType(dummyFuncTypeName, SizeThunk.POINTER, fieldType, 0);
- ft.addArgument(containingCType.getCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST),
+ ft.addArgument(containingCType.newCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST),
CMethodBindingEmitter.cThisArgumentName());
ft.addArgument(int32Type, nativeArrayElemOffsetArg);
final FunctionSymbol fs = new FunctionSymbol("get"+capitalFieldName, ft);
jniWriter.println();
- jniWriter.print("static "+fs.toString());
+ jniWriter.print("static "+fs.toString(false));
jniWriter.println("{");
jniWriter.println(" return "+CMethodBindingEmitter.cThisArgumentName()+"->"+field.getName()+"+"+nativeArrayElemOffsetArg+";");
jniWriter.println("}");
@@ -1901,7 +1918,7 @@ public class JavaEmitter implements GlueEmitter {
containingCType, containingJType, i, fs, returnSizeLookupName, arrayLengthExpr, nativeArrayLengthONE);
javaWriter.println();
if( hasSingleElement ) {
- generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName, capitalFieldName, null, arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName, fieldName, capitalFieldName, null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final ByteBuffer source = getBuffer();");
javaWriter.println(" final ByteBuffer _res = get"+capitalFieldName+"0(source, 0);");
@@ -1909,7 +1926,7 @@ public class JavaEmitter implements GlueEmitter {
javaWriter.println(" return "+baseJElemTypeName+".create(_res);");
javaWriter.println(" }");
} else {
- generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName+"[]", capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName+"[]", fieldName, capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";");
javaWriter.println(" if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + result.length \"+result.length+\" > array-length \"+arrayLength); };");
@@ -1925,12 +1942,12 @@ public class JavaEmitter implements GlueEmitter {
} else {
// Getter Struct Array
if( hasSingleElement ) {
- generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName, capitalFieldName, null, arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName, fieldName, capitalFieldName, null, arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" return "+baseJElemTypeName+".create(accessor.slice("+fieldName+"_offset[mdIdx], "+baseJElemTypeName+".size()));");
javaWriter.println(" }");
} else {
- generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName+"[]", capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
+ generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName+"[]", fieldName, capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
javaWriter.println(" {");
javaWriter.println(" final int arrayLength = "+arrayLengthExpr+";");
javaWriter.println(" if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + result.length \"+result.length+\" > array-length \"+arrayLength); };");
@@ -1947,12 +1964,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 ) {
- System.err.println("typeToJavaType: "+cType.getDebugString()+" -> "+jt.getDebugString());
- }
+ LOG.log(FINE, cType.getASTLocusTag(), "typeToJavaType: {0} -> {1}", cType, jt);
return jt;
}
private boolean isJNIEnvPointer(final Type cType) {
@@ -1968,7 +1982,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 +2000,16 @@ 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() ) {
- LOG.log(INFO, "Opaque Type: {0}, targetType: {1}, bottomType: {2} is ptr-ptr", new Object[]{cType.getDebugString(), targetType, bottomType});
+ // t is<type>**, targetType is <type>*, we need to get <type>
+ final Type bottomType = targetType.asPointer().getTargetType();
+ LOG.log(INFO, cType.getASTLocusTag(), "Opaque Type: {0}, targetType: {1}, bottomType: {2} is ptr-ptr",
+ cType, targetType, bottomType);
}
}
}
}
- if(!isPointerPointer) {
+ if( !isPointerPointer ) {
return info.javaType();
}
}
@@ -2006,8 +2020,9 @@ public class JavaEmitter implements GlueEmitter {
case 2: return javaType(Short.TYPE);
case 4: return javaType(Integer.TYPE);
case 8: return javaType(Long.TYPE);
- default: throw new RuntimeException("Unknown integer type of size " +
- cType.getSize(curMachDesc) + " and name " + cType.getName());
+ default: throw new GlueGenException("Unknown integer type of size " +
+ cType.getSize(curMachDesc) + " and name " + cType.getName(),
+ cType.getASTLocusTag());
}
} else if (cType.isFloat()) {
return javaType(Float.TYPE);
@@ -2042,8 +2057,9 @@ public class JavaEmitter implements GlueEmitter {
case 2: return JavaType.createForCShortPointer();
case 4: return JavaType.createForCInt32Pointer();
case 8: return JavaType.createForCInt64Pointer();
- default: throw new RuntimeException("Unknown integer array type of size " +
- cType.getSize(curMachDesc) + " and name " + cType.getName()+", "+cType.getDebugString());
+ default: throw new GlueGenException("Unknown integer array type of size " +
+ cType.getSize(curMachDesc) + " and name " + cType.getName()+", "+cType.getDebugString(),
+ cType.getASTLocusTag());
}
} else if (targetType.isFloat()) {
return JavaType.createForCFloatPointer();
@@ -2058,19 +2074,28 @@ public class JavaEmitter implements GlueEmitter {
cType.getName().equals("jobject")) {
return javaType(java.lang.Object.class);
}
- String name = targetType.getName();
- if (name == null) {
- // Try containing pointer type for any typedefs
- name = cType.getName();
- if (name == null) {
- throw new RuntimeException("Couldn't find a proper type name for pointer type " + cType.getDebugString());
- }
+ // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser)
+ String name;
+ if( !targetType.isTypedef() && cType.isTypedef() ) {
+ // If compound is not a typedef _and_ containing pointer is typedef, use the latter.
+ name = cType.getName();
+ } else {
+ // .. otherwise try compound name
+ name = targetType.getName();
+ if( null == name ) {
+ // .. fall back to pointer type name
+ name = cType.getName();
+ if (name == null) {
+ throw new GlueGenException("Couldn't find a proper type name for pointer type " + cType.getDebugString(),
+ cType.getASTLocusTag());
+ }
+ }
}
-
return JavaType.createForCStruct(cfg.renameJavaType(name));
} else {
- throw new RuntimeException("Don't know how to convert pointer/array type \"" +
- cType.getDebugString() + "\"");
+ throw new GlueGenException("Don't know how to convert pointer/array type \"" +
+ cType.getDebugString() + "\"",
+ cType.getASTLocusTag());
}
}
// Handle Types of form pointer-to-pointer-to-type or
@@ -2084,19 +2109,22 @@ public class JavaEmitter implements GlueEmitter {
// t is<type>**, targetType is <type>*, we need to get <type>
bottomType = targetType.asPointer().getTargetType();
if( GlueGen.debug() ) {
- LOG.log(INFO, "typeToJavaType(ptr-ptr): {0}, targetType: {1}, bottomType: {2}", new Object[]{cType.getDebugString(), targetType, bottomType});
+ LOG.log(INFO, cType.getASTLocusTag(), "typeToJavaType(ptr-ptr): {0}, targetType: {1}, bottomType: {2}",
+ cType.getDebugString(), targetType, bottomType);
}
return JavaType.forNIOPointerBufferClass();
} else if(targetType.isArray()) {
// t is<type>[][], targetType is <type>[], we need to get <type>
bottomType = targetType.asArray().getBaseElementType();
if( GlueGen.debug() ) {
- LOG.log(INFO, "typeToJavaType(ptr-ptr.array): {0}, targetType: {1}, bottomType: {2}", new Object[]{cType.getDebugString(), targetType, bottomType});
+ LOG.log(INFO, cType.getASTLocusTag(), "typeToJavaType(ptr-ptr.array): {0}, targetType: {1}, bottomType: {2}",
+ cType.getDebugString(), targetType, bottomType);
}
} else {
bottomType = targetType;
if( GlueGen.debug() ) {
- LOG.log(INFO, "typeToJavaType(ptr-ptr.primitive): {0}, targetType: {1}, bottomType: {2}", new Object[]{cType.getDebugString(), targetType, bottomType});
+ LOG.log(INFO, cType.getASTLocusTag(), "typeToJavaType(ptr-ptr.primitive): {0}, targetType: {1}, bottomType: {2}",
+ cType.getDebugString(), targetType, bottomType);
}
}
@@ -2110,16 +2138,17 @@ public class JavaEmitter implements GlueEmitter {
case 2: return javaType(ArrayTypes.shortBufferArrayClass);
case 4: return javaType(ArrayTypes.intBufferArrayClass);
case 8: return javaType(ArrayTypes.longBufferArrayClass);
- default: throw new RuntimeException("Unknown two-dimensional integer array type of element size " +
- bottomType.getSize(curMachDesc) + " and name " + bottomType.getName()+", "+bottomType.getDebugString());
+ default: throw new GlueGenException("Unknown two-dimensional integer array type of element size " +
+ bottomType.getSize(curMachDesc) + " and name " + bottomType.getName()+", "+bottomType.getDebugString(),
+ bottomType.getASTLocusTag());
}
} else if (bottomType.isFloat()) {
return javaType(ArrayTypes.floatBufferArrayClass);
} else if (bottomType.isDouble()) {
return javaType(ArrayTypes.doubleBufferArrayClass);
} else {
- throw new RuntimeException("Unexpected primitive type " + bottomType.getDebugString() +
- " in two-dimensional array");
+ throw new GlueGenException("Unexpected primitive type " + bottomType.getDebugString() +
+ " in two-dimensional array", bottomType.getASTLocusTag());
}
} else if (bottomType.isVoid()) {
return javaType(ArrayTypes.bufferArrayClass);
@@ -2128,32 +2157,38 @@ public class JavaEmitter implements GlueEmitter {
// Array of pointers; convert as array of StructAccessors
return JavaType.createForCArray(bottomType);
} else {
- throw new RuntimeException(
+ throw new GlueGenException(
"Could not convert C type \"" + cType.getDebugString() + "\" " +
"to appropriate Java type; need to add more support for " +
"depth=2 pointer/array types [debug info: targetType=\"" +
- targetType + "\"]");
+ targetType + "\"]", cType.getASTLocusTag());
}
} else {
// can't handle this type of pointer/array argument
- throw new RuntimeException(
+ throw new GlueGenException(
"Could not convert C pointer/array \"" + cType.getDebugString() + "\" to " +
"appropriate Java type; types with pointer/array depth " +
"greater than 2 are not yet supported [debug info: " +
"pointerDepth=" + cType.pointerDepth() + " arrayDimension=" +
- cType.arrayDimension() + " targetType=\"" + targetType + "\"]");
+ cType.arrayDimension() + " targetType=\"" + targetType + "\"]",
+ cType.getASTLocusTag());
}
- } else if(cType.isCompound() ) { // FIXME: Compound and Compound-Arrays
- final String name = cType.getName();
+ } else if( cType.isCompound() ) { // FIXME: Compound and Compound-Arrays
+ String name = cType.getName();
if (name == null) {
- throw new RuntimeException("Couldn't find a proper type name for pointer type " + cType.getDebugString());
+ name = cType.asCompound().getStructName();
+ if (name == null) {
+ throw new GlueGenException("Couldn't find a proper type name for pointer type " + cType.getDebugString(),
+ cType.getASTLocusTag());
+ }
}
return JavaType.createForCStruct(cfg.renameJavaType(name));
} else {
- throw new RuntimeException(
+ throw new GlueGenException(
"Could not convert C type \"" + cType.getDebugString() + "\" (class " +
- cType.getClass().getName() + ") to appropriate Java type");
+ cType.getClass().getName() + ") to appropriate Java type",
+ cType.getASTLocusTag());
}
}
@@ -2189,7 +2224,7 @@ public class JavaEmitter implements GlueEmitter {
}
private boolean isOpaque(final Type type) {
- return (cfg.typeInfo(type, typedefDictionary) != null);
+ return null != cfg.typeInfo(type);
}
private String compatiblePrimitiveJavaTypeName(final Type fieldType,
@@ -2198,14 +2233,16 @@ public class JavaEmitter implements GlueEmitter {
final Class<?> c = javaType.getJavaClass();
if (!isIntegerType(c)) {
// FIXME
- throw new RuntimeException("Can't yet handle opaque definitions of structs' fields to non-integer types (byte, short, int, long, etc.): type: "+fieldType+", javaType "+javaType+", javaClass "+c);
+ throw new GlueGenException("Can't yet handle opaque definitions of structs' fields to non-integer types (byte, short, int, long, etc.): type: "+fieldType+", javaType "+javaType+", javaClass "+c,
+ fieldType.getASTLocusTag());
}
switch ((int) fieldType.getSize(curMachDesc)) {
case 1: return "byte";
case 2: return "short";
case 4: return "int";
case 8: return "long";
- default: throw new RuntimeException("Can't handle opaque definitions if the starting type isn't compatible with integral types");
+ default: throw new GlueGenException("Can't handle opaque definitions if the starting type isn't compatible with integral types",
+ fieldType.getASTLocusTag());
}
}
@@ -2229,13 +2266,16 @@ public class JavaEmitter implements GlueEmitter {
}
if (cfg.allStatic() || cfg.emitInterface()) {
- javaWriter = openFile(jRoot + File.separator + cfg.className() + ".java", cfg.className());
+ javaFileName = jRoot + File.separator + cfg.className() + ".java";
+ javaWriter = openFile(javaFileName, cfg.className());
}
if (!cfg.allStatic() && cfg.emitImpl()) {
- javaImplWriter = openFile(jImplRoot + File.separator + cfg.implClassName() + ".java", cfg.implClassName());
+ javaFileName = jImplRoot + File.separator + cfg.implClassName() + ".java";
+ javaImplWriter = openFile(javaFileName, cfg.implClassName());
}
if (cfg.emitImpl()) {
- cWriter = openFile(nRoot + File.separator + cfg.implClassName() + "_JNI.c", cfg.implClassName());
+ cFileName = nRoot + File.separator + cfg.implClassName() + "_JNI.c";
+ cWriter = openFile(cFileName, cfg.implClassName());
}
if (javaWriter != null) {
@@ -2249,6 +2289,9 @@ public class JavaEmitter implements GlueEmitter {
}
}
+ /** For {@link #javaWriter} or {@link #javaImplWriter} */
+ protected String javaFileName() { return javaFileName; }
+
protected PrintWriter javaWriter() {
if (!cfg.allStatic() && !cfg.emitInterface()) {
throw new InternalError("Should not call this");
@@ -2263,6 +2306,9 @@ public class JavaEmitter implements GlueEmitter {
return javaImplWriter;
}
+ /** For {@link #cImplWriter} */
+ protected String cFileName() { return cFileName; }
+
protected PrintWriter cWriter() {
if (!cfg.emitImpl()) {
throw new InternalError("Should not call this");
@@ -2454,8 +2500,9 @@ public class JavaEmitter implements GlueEmitter {
if (getConfig().emitImpl()) {
cWriter.println("#include <assert.h>");
+ cWriter.println("#include <stddef.h>");
cWriter.println();
- cWriter.println("static jobject JVMUtil_NewDirectByteBufferCopy(JNIEnv *env, void * source_address, jlong capacity); /* forward decl. */");
+ cWriter.println("static jobject JVMUtil_NewDirectByteBufferCopy(JNIEnv *env, void * source_address, size_t capacity); /* forward decl. */");
cWriter.println();
}
for (final String code : cfg.customCCode()) {
@@ -2468,6 +2515,7 @@ public class JavaEmitter implements GlueEmitter {
"static const char * clazzNameBuffers = \"com/jogamp/common/nio/Buffers\";\n"+
"static const char * clazzNameBuffersStaticNewCstrName = \"newDirectByteBuffer\";\n"+
"static const char * clazzNameBuffersStaticNewCstrSignature = \"(I)Ljava/nio/ByteBuffer;\";\n"+
+ "static const char * sFatalError = \"FatalError:\";\n"+
"static jclass clazzBuffers = NULL;\n"+
"static jmethodID cstrBuffersNew = NULL;\n"+
"static jboolean _initClazzAccessDone = JNI_FALSE;\n"+
@@ -2479,13 +2527,13 @@ public class JavaEmitter implements GlueEmitter {
"\n"+
" c = (*env)->FindClass(env, clazzNameBuffers);\n"+
" if(NULL==c) {\n"+
- " fprintf(stderr, \"FatalError: Can't find %s\\n\", clazzNameBuffers);\n"+
+ " fprintf(stderr, \"%s Can't find %s\\n\", sFatalError, clazzNameBuffers);\n"+
" (*env)->FatalError(env, clazzNameBuffers);\n"+
" return JNI_FALSE;\n"+
" }\n"+
" clazzBuffers = (jclass)(*env)->NewGlobalRef(env, c);\n"+
" if(NULL==clazzBuffers) {\n"+
- " fprintf(stderr, \"FatalError: Can't use %s\\n\", clazzNameBuffers);\n"+
+ " fprintf(stderr, \"%s Can't use %s\\n\", sFatalError, clazzNameBuffers);\n"+
" (*env)->FatalError(env, clazzNameBuffers);\n"+
" return JNI_FALSE;\n"+
" }\n"+
@@ -2493,7 +2541,7 @@ public class JavaEmitter implements GlueEmitter {
" cstrBuffersNew = (*env)->GetStaticMethodID(env, clazzBuffers,\n"+
" clazzNameBuffersStaticNewCstrName, clazzNameBuffersStaticNewCstrSignature);\n"+
" if(NULL==cstrBuffersNew) {\n"+
- " fprintf(stderr, \"FatalError: can't create %s.%s %s\\n\",\n"+
+ " fprintf(stderr, \"%s can't create %s.%s %s\\n\", sFatalError,\n"+
" clazzNameBuffers,\n"+
" clazzNameBuffersStaticNewCstrName, clazzNameBuffersStaticNewCstrSignature);\n"+
" (*env)->FatalError(env, clazzNameBuffersStaticNewCstrName);\n"+
@@ -2503,18 +2551,35 @@ public class JavaEmitter implements GlueEmitter {
" return JNI_TRUE;\n"+
"}\n"+
"\n"+
- "static jobject JVMUtil_NewDirectByteBufferCopy(JNIEnv *env, void * source_address, jlong capacity) {\n"+
+ "#define JINT_MAX_VALUE ((size_t)0x7fffffffU)\n"+
+ "static const char * sNewBufferImplNotCalled = \"initializeImpl() not called\";\n"+
+ "static const char * sNewBufferMAX_INT = \"capacity > MAX_INT\";\n"+
+ "static const char * sNewBufferNULL = \"New direct ByteBuffer is NULL\";\n"+
+ "\n"+
+ "static jobject JVMUtil_NewDirectByteBufferCopy(JNIEnv *env, void * source_address, size_t capacity) {\n"+
" jobject jbyteBuffer;\n"+
" void * byteBufferPtr;\n"+
"\n"+
" if( JNI_FALSE == _initClazzAccessDone ) {\n"+
- " fprintf(stderr, \"FatalError: initializeImpl() not called\\n\");\n"+
- " (*env)->FatalError(env, \"initializeImpl() not called\");\n"+
+ " fprintf(stderr, \"%s %s\\n\", sFatalError, sNewBufferImplNotCalled);\n"+
+ " (*env)->FatalError(env, sNewBufferImplNotCalled);\n"+
" return NULL;\n"+
" }\n"+
- " jbyteBuffer = (*env)->CallStaticObjectMethod(env, clazzBuffers, cstrBuffersNew, capacity);\n"+
- " byteBufferPtr = (*env)->GetDirectBufferAddress(env, jbyteBuffer);\n"+
- " memcpy(byteBufferPtr, source_address, capacity);\n"+
+ " if( JINT_MAX_VALUE < capacity ) {\n"+
+ " fprintf(stderr, \"%s %s: %lu\\n\", sFatalError, sNewBufferMAX_INT, (unsigned long)capacity);\n"+
+ " (*env)->FatalError(env, sNewBufferMAX_INT);\n"+
+ " return NULL;\n"+
+ " }\n"+
+ " jbyteBuffer = (*env)->CallStaticObjectMethod(env, clazzBuffers, cstrBuffersNew, (jint)capacity);\n"+
+ " if( NULL == jbyteBuffer ) {\n"+
+ " fprintf(stderr, \"%s %s: size %lu\\n\", sFatalError, sNewBufferNULL, (unsigned long)capacity);\n"+
+ " (*env)->FatalError(env, sNewBufferNULL);\n"+
+ " return NULL;\n"+
+ " }\n"+
+ " if( 0 < capacity ) {\n"+
+ " byteBufferPtr = (*env)->GetDirectBufferAddress(env, jbyteBuffer);\n"+
+ " memcpy(byteBufferPtr, source_address, capacity);\n"+
+ " }\n"+
" return jbyteBuffer;\n"+
"}\n"+
"\n";
@@ -2580,36 +2645,46 @@ public class JavaEmitter implements GlueEmitter {
potentially representing C pointers rather than true Java types)
and must be lowered to concrete Java types before creating
emitters for them. */
- private MethodBinding bindFunction(final FunctionSymbol sym,
- final JavaType containingType,
- final Type containingCType,
- 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())) {
+ private MethodBinding bindFunction(FunctionSymbol sym,
+ final boolean forInterface,
+ final MachineDataInfo curMachDesc,
+ final JavaType containingType, final Type containingCType) {
+
+ final String delegationImplName = null == containingType && null == containingCType ?
+ cfg.getDelegatedImplementation(sym) : null;
+ if( !forInterface && null != delegationImplName ) {
+ // We need to reflect the 'delegationImplName' for implementations
+ // to allow all subsequent type/cfg checks to hit on AliasedSymbol!
+ sym = FunctionSymbol.cloneWithDeepAliases(sym);
+ sym.addAliasedName(delegationImplName);
+ }
+ final String name = sym.getName();
+ final JavaType javaReturnType;
+
+ if (cfg.returnsString(sym)) {
final PointerType prt = sym.getReturnType().asPointer();
if (prt == null ||
prt.getTargetType().asInt() == null ||
prt.getTargetType().getSize(curMachDesc) != 1) {
- throw new RuntimeException(
+ throw new GlueGenException(
"Cannot apply ReturnsString configuration directive to \"" + sym +
- "\". ReturnsString requires native method to have return type \"char *\"");
+ "\". ReturnsString requires native method to have return type \"char *\"",
+ sym.getASTLocusTag());
}
- binding.setJavaReturnType(javaType(java.lang.String.class));
+ javaReturnType = javaType(java.lang.String.class);
} else {
- binding.setJavaReturnType(typeToJavaType(sym.getReturnType(), curMachDesc));
+ final JavaType r = cfg.getOpaqueReturnType(sym);
+ if( null != r ) {
+ javaReturnType = r;
+ } else {
+ javaReturnType = typeToJavaType(sym.getReturnType(), curMachDesc);
+ }
}
- // System.out.println("bindFunction(1) "+binding.getJavaReturnType());
-
// List of the indices of the arguments in this function that should be
// converted from byte[] or short[] to String
- final List<Integer> stringArgIndices = cfg.stringArguments(binding.getName());
+ final List<JavaType> javaArgumentTypes = new ArrayList<JavaType>();
+ final List<Integer> stringArgIndices = cfg.stringArguments(name);
for (int i = 0; i < sym.getNumArguments(); i++) {
final Type cArgType = sym.getArgumentType(i);
@@ -2637,20 +2712,21 @@ public class JavaEmitter implements GlueEmitter {
}
}
else {
- throw new RuntimeException(
+ throw new GlueGenException(
"Cannot apply ArgumentIsString configuration directive to " +
"argument " + i + " of \"" + sym + "\": argument type is not " +
- "a \"void*\", \"char *\", \"short *\", \"char**\", or \"short**\" equivalent");
+ "a \"void*\", \"char *\", \"short *\", \"char**\", or \"short**\" equivalent",
+ sym.getASTLocusTag());
}
}
- binding.addJavaArgumentType(mappedType);
+ javaArgumentTypes.add(mappedType);
//System.out.println("During binding of [" + sym + "], added mapping from C type: " + cArgType + " to Java type: " + mappedType);
}
-
- // System.out.println("---> " + binding);
- // System.out.println(" ---> " + binding.getCSymbol());
- // System.out.println("bindFunction(3) "+binding);
- return binding;
+ final MethodBinding mb = new MethodBinding(sym, delegationImplName,
+ javaReturnType, javaArgumentTypes,
+ containingType, containingCType);
+ mangleBinding(mb);
+ return mb;
}
private MethodBinding lowerMethodBindingPointerTypes(final MethodBinding inputBinding,
@@ -2710,7 +2786,7 @@ public class JavaEmitter implements GlueEmitter {
result = result.replaceJavaArgumentType(i, JavaType.forNIODoubleBufferClass());
}
} else {
- throw new RuntimeException("Unknown C pointer type " + t);
+ throw new GlueGenException("Unknown C pointer type " + t);
}
}
}
@@ -2735,7 +2811,7 @@ public class JavaEmitter implements GlueEmitter {
} else if (t.isCDoublePointerType()) {
result = result.replaceJavaArgumentType(-1, JavaType.forNIODoubleBufferClass());
} else {
- throw new RuntimeException("Unknown C pointer type " + t);
+ throw new GlueGenException("Unknown C pointer type " + t, result.getCReturnType().getASTLocusTag());
}
}
@@ -2748,6 +2824,14 @@ public class JavaEmitter implements GlueEmitter {
return result;
}
+ /**
+ * Allow specializations to modify the given {@link MethodBinding}
+ * before {@link #expandMethodBinding(MethodBinding) expanding} and emission.
+ */
+ protected void mangleBinding(final MethodBinding binding) {
+ // NOP
+ }
+
// Expands a MethodBinding containing C primitive pointer types into
// multiple variants taking Java primitive arrays and NIO buffers, subject
// to the per-function "NIO only" rule in the configuration file
@@ -2779,10 +2863,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..d3fca14 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.
@@ -64,22 +67,22 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
protected final CommentEmitter defaultJavaCommentEmitter = new DefaultCommentEmitter();
protected final CommentEmitter defaultInterfaceCommentEmitter = new InterfaceCommentEmitter();
+ protected final boolean tagNativeBinding;
+ protected final boolean useNIODirectOnly;
+ protected final MethodBinding binding;
// Exception type raised in the generated code if runtime checks fail
private final String runtimeExceptionType;
private final String unsupportedExceptionType;
+ private final boolean useNIOOnly;
+ private final boolean isNativeMethod;
+ private final boolean isUnimplemented;
- protected boolean emitBody;
- protected boolean eraseBufferAndArrayTypes;
- protected boolean useNIOOnly;
- protected boolean useNIODirectOnly;
- protected boolean forImplementingMethodCall;
- protected boolean forDirectBufferImplementation;
- protected boolean forIndirectBufferAndArrayImplementation;
- protected boolean isUnimplemented;
- protected boolean tagNativeBinding;
-
- protected MethodBinding binding;
+ private boolean emitBody;
+ private boolean eraseBufferAndArrayTypes;
+ private boolean isPrivateNativeMethod;
+ private boolean forDirectBufferImplementation;
+ private boolean forIndirectBufferAndArrayImplementation;
// Manually-specified prologue and epilogue code
protected List<String> prologue;
@@ -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,
@@ -109,13 +109,13 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
final boolean eraseBufferAndArrayTypes,
final boolean useNIOOnly,
final boolean useNIODirectOnly,
- final boolean forImplementingMethodCall,
final boolean forDirectBufferImplementation,
final boolean forIndirectBufferAndArrayImplementation,
final boolean isUnimplemented,
final boolean isInterface,
- final JavaConfiguration configuration) {
- super(output, isInterface);
+ final boolean isNativeMethod,
+ final boolean isPrivateNativeMethod, final JavaConfiguration configuration) {
+ super(output, isInterface, configuration);
this.binding = binding;
this.runtimeExceptionType = runtimeExceptionType;
this.unsupportedExceptionType = unsupportedExceptionType;
@@ -124,16 +124,17 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
this.eraseBufferAndArrayTypes = eraseBufferAndArrayTypes;
this.useNIOOnly = useNIOOnly;
this.useNIODirectOnly = useNIODirectOnly;
- this.forImplementingMethodCall = forImplementingMethodCall;
this.forDirectBufferImplementation = forDirectBufferImplementation;
this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation;
this.isUnimplemented = isUnimplemented;
- if (forImplementingMethodCall) {
+ this.isNativeMethod = isNativeMethod;
+ this.isPrivateNativeMethod = isPrivateNativeMethod;
+ if (isPrivateNativeMethod) {
setCommentEmitter(defaultJavaCommentEmitter);
} else {
setCommentEmitter(defaultInterfaceCommentEmitter);
}
- cfg = configuration;
+ // !forImplementingMethodCall && !isInterface
}
public JavaMethodBindingEmitter(final JavaMethodBindingEmitter arg) {
@@ -146,7 +147,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
eraseBufferAndArrayTypes = arg.eraseBufferAndArrayTypes;
useNIOOnly = arg.useNIOOnly;
useNIODirectOnly = arg.useNIODirectOnly;
- forImplementingMethodCall = arg.forImplementingMethodCall;
+ isNativeMethod = arg.isNativeMethod;
+ isPrivateNativeMethod = arg.isPrivateNativeMethod;
forDirectBufferImplementation = arg.forDirectBufferImplementation;
forIndirectBufferAndArrayImplementation = arg.forIndirectBufferAndArrayImplementation;
isUnimplemented = arg.isUnimplemented;
@@ -154,18 +156,31 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
epilogue = arg.epilogue;
returnedArrayLengthExpression = arg.returnedArrayLengthExpression;
returnedArrayLengthExpressionOnlyForComments = arg.returnedArrayLengthExpressionOnlyForComments;
- cfg = arg.cfg;
}
public final MethodBinding getBinding() { return binding; }
- public boolean isForImplementingMethodCall() { return forImplementingMethodCall; }
+ public boolean isNativeMethod() { return isNativeMethod; }
+ public boolean isPrivateNativeMethod() { return isPrivateNativeMethod; }
public boolean isForDirectBufferImplementation() { return forDirectBufferImplementation; }
public boolean isForIndirectBufferAndArrayImplementation() { return forIndirectBufferAndArrayImplementation; }
@Override
- public String getName() {
- return binding.getName();
+ public String getInterfaceName() {
+ return binding.getInterfaceName();
+ }
+ @Override
+ public String getImplName() {
+ return binding.getImplName();
+ }
+ @Override
+ public String getNativeName() {
+ return binding.getNativeName();
+ }
+
+ @Override
+ public FunctionSymbol getCSymbol() {
+ return binding.getCSymbol();
}
protected String getArgumentName(final int i) {
@@ -233,8 +248,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
/** Accessor for subclasses. */
- public void setForImplementingMethodCall(final boolean impl) {
- this.forImplementingMethodCall = impl;
+ public void setPrivateNativeMethod(final boolean v) {
+ this.isPrivateNativeMethod = v;
}
/** Accessor for subclasses. */
@@ -322,10 +337,12 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
@Override
protected void emitName(final PrintWriter writer) {
- if (forImplementingMethodCall) {
- writer.print(getImplMethodName());
+ if (isPrivateNativeMethod) {
+ writer.print(getNativeImplMethodName());
+ } else if( isInterface()) {
+ writer.print(getInterfaceName());
} else {
- writer.print(getName());
+ writer.print(getImplName());
}
}
@@ -334,7 +351,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
boolean needComma = false;
int numEmitted = 0;
- if (forImplementingMethodCall && binding.hasContainingType()) {
+ if (isPrivateNativeMethod && binding.hasContainingType()) {
// Always emit outgoing "this" argument
writer.print("ByteBuffer ");
writer.print(javaThisArgumentName());
@@ -395,8 +412,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
- protected String getImplMethodName() {
- return binding.getName() + ( useNIODirectOnly ? "0" : "1" );
+ protected String getNativeImplMethodName() {
+ return binding.getImplName() + ( useNIODirectOnly ? "0" : "1" );
}
protected String byteOffsetArgName(final int i) {
@@ -544,7 +561,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
protected void emitCall(final MethodBinding binding, final PrintWriter writer) {
- writer.print(getImplMethodName());
+ writer.print(getNativeImplMethodName());
writer.print("(");
emitCallArguments(binding, writer);
writer.print(");");
@@ -675,9 +692,10 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
} else if(type.isIntArray()) {
writer.print(", Buffers.SIZEOF_INT * ");
} else {
- throw new RuntimeException("Unsupported type for calculating array offset argument for " +
+ throw new GlueGenException("Unsupported type for calculating array offset argument for " +
getArgumentName(i) +
- " -- error occurred while processing Java glue code for " + getName());
+ " -- error occurred while processing Java glue code for " + getCSymbol().getAliasedString(),
+ getCSymbol().getASTLocusTag());
}
writer.print(offsetArgName(i));
}
@@ -688,7 +706,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
} else if (type.isPrimitiveArray()) {
if (useNIOOnly) {
- throw new RuntimeException("NIO[Direct]Only "+binding+" is set, but "+getArgumentName(i)+" is a primitive array");
+ throw new GlueGenException("NIO[Direct]Only "+binding+" is set, but "+getArgumentName(i)+" is a primitive array",
+ getCSymbol().getASTLocusTag());
}
writer.print( ", false");
}
@@ -706,7 +725,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
// ByteBuffers back into the wrapper types
for (int i = 0; i < binding.getNumArguments(); i++) {
final JavaType javaArgType = binding.getJavaArgumentType(i);
- if ( javaArgType.isArrayOfCompoundTypeWrappers() && !isBaseTypeConst(javaArgType.getElementCType()) ) {
+ if ( javaArgType.isArrayOfCompoundTypeWrappers() && !javaArgType.getElementCType().isBaseTypeConst() ) {
final String argName = binding.getArgumentName(i);
writer.println(" for (int _ctr = 0; _ctr < " + argName + ".length; _ctr++) {");
writer.println(" if ((" + argName + "[_ctr] == null && " + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr] == null) ||");
@@ -743,8 +762,9 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
} else if (returnType.isNIOLongBuffer()) {
writer.println(" return _res.asLongBuffer();");
} else {
- throw new RuntimeException("While emitting glue code for " + getName() +
- ": can not legally make pointers opaque to anything but PointerBuffer or LongBuffer/long");
+ throw new GlueGenException("While emitting glue code for " + getCSymbol().getAliasedString() +
+ ": can not legally make pointers opaque to anything but PointerBuffer or LongBuffer/long",
+ getCSymbol().getASTLocusTag());
}
} else if (getBinding().getCReturnType().pointerDepth() == 1 && returnType.isNIOLongBuffer()) {
writer.println(" return _res.asLongBuffer();");
@@ -812,6 +832,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 +866,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
@@ -852,7 +894,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
writer.print(" valid values are: <code>");
for (int j = 0; j < enumType.getNumEnumerates(); ++j) {
if (j>0) writer.print(", ");
- writer.print(enumType.getEnumName(j));
+ writer.print(enumType.getEnum(j).getName());
}
writer.println("</code>");
} else if (javaType.isNIOBuffer()) {
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..c057db4 100644
--- a/src/java/com/jogamp/gluegen/Logging.java
+++ b/src/java/com/jogamp/gluegen/Logging.java
@@ -31,57 +31,352 @@
*/
package com.jogamp.gluegen;
+import java.util.HashMap;
+import java.util.Map;
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;
+import jogamp.common.Debug;
+
import com.jogamp.common.util.PropertyAccess;
+import com.jogamp.gluegen.cgram.types.AliasedSymbol;
+import com.jogamp.gluegen.cgram.types.Type;
/**
*
- * @author Michael Bien
+ * @author Michael Bien, et.al.
*/
public class Logging {
+ public static final boolean DEBUG = Debug.debug("Logging");
+
+ /**
+ * An interface for {@link Logger}.
+ */
+ public static interface LoggerIf {
+ /**
+ * See {@link Logger#info(String)}
+ */
+ void info(final String msg);
+ /**
+ * See {@link Logger#info(String)}
+ */
+ void info(final ASTLocusTag loc, final String msg);
+
+ /**
+ * See {@link Logger#warning(String)}
+ */
+ void warning(final String msg);
+ /**
+ * See {@link Logger#warning(String)}
+ */
+ void warning(final ASTLocusTag loc, final String msg);
+
+ /**
+ * Calls {@link #log(Level, String)} w/ {@link Level#FINE}.
+ */
+ void debug(final String msg);
+ /**
+ * Calls {@link #log(Level, ASTLocusTag, String)} w/ {@link Level#FINE}.
+ */
+ void debug(final ASTLocusTag loc, final String msg);
+
+ /**
+ * See {@link Logger#log(Level, String)}
+ */
+ void log(final Level level, final String msg);
+ /**
+ * See {@link Logger#log(Level, String, Object)}
+ */
+ void log(final Level level, final String msg, final Object param);
+ /**
+ * See {@link Logger#log(Level, String, Object[])}
+ */
+ void log(final Level level, final String msg, final Object ... params);
+
+ /**
+ * See {@link Logger#log(Level, String)}
+ */
+ void log(final Level level, final ASTLocusTag loc, final String msg);
+ /**
+ * See {@link Logger#log(Level, String, Object)}
+ */
+ void log(final Level level, final ASTLocusTag loc, final String msg, final Object param);
+ /**
+ * See {@link Logger#log(Level, String, Object[])}
+ */
+ void log(final Level level, final ASTLocusTag loc, final String msg, final Object ... params);
+
+ /**
+ * See {@link Logger#setLevel(Level)}
+ */
+ void setLevel(final Level newLevel) throws SecurityException;
+ /**
+ * See {@link Handler#setLevel(Level)}
+ */
+ void setLevelOfAllHandler(final Level newLevel) throws SecurityException;
+ /**
+ * See {@link Logger#getLevel()}
+ */
+ Level getLevel();
+ /**
+ * See {@link Logger#isLoggable(Level)}
+ */
+ boolean isLoggable(Level level);
+ /**
+ * See {@link Logger#getName()}
+ */
+ String getName();
+ /**
+ * See {@link Logger#getHandlers()}
+ */
+ Handler[] getHandlers();
+ /**
+ * See {@link LogRecord#getSourceClassName()}
+ */
+ String getSourceClassName();
+ }
+ /* pp */ static class FQNLogger implements LoggerIf {
+ public final Logger impl;
+ public final PlainLogConsoleHandler handler;
+ /* pp */ FQNLogger(final String fqnClassName, final String simpleClassName, final Level level) {
+ this.impl = Logger.getLogger(fqnClassName);
+ this.handler = new PlainLogConsoleHandler(new PlainLogFormatter(simpleClassName), Level.ALL);
+ this.impl.setUseParentHandlers(false);
+ this.impl.setLevel(level);
+ this.impl.addHandler(this.handler);
+ this.impl.log(Level.INFO, "Logging.new: "+impl.getName()+": level "+level+
+ ": obj 0x"+Integer.toHexString(impl.hashCode()));
+ }
+ @Override
+ public void info(final String msg) {
+ impl.info(msg);
+ }
+ @Override
+ public void info(final ASTLocusTag loc, final String msg) {
+ handler.plf.setASTLocusTag(loc);
+ try {
+ impl.info(msg);
+ } finally {
+ handler.plf.setASTLocusTag(null);
+ }
+ }
+
+ @Override
+ public void warning(final String msg) {
+ impl.warning(msg);
+ }
+ @Override
+ public void warning(final ASTLocusTag loc, final String msg) {
+ handler.plf.setASTLocusTag(loc);
+ try {
+ impl.warning(msg);
+ } finally {
+ handler.plf.setASTLocusTag(null);
+ }
+ }
+
+ @Override
+ public void debug(final String msg) {
+ log(Level.FINE, msg);
+ }
+ @Override
+ public void debug(final ASTLocusTag loc, final String msg) {
+ log(Level.FINE, loc, msg);
+ }
+
+ @Override
+ public void log(final Level level, final String msg) {
+ impl.log(level, msg);
+ }
+ @Override
+ public void log(final Level level, final String msg, final Object param) {
+ impl.log(level, msg, param);
+ }
+ @Override
+ public void log(final Level level, final String msg, final Object ... params) {
+ impl.log(level, msg, params);
+ }
- static void init() {
+ @Override
+ public void log(final Level level, final ASTLocusTag loc, final String msg) {
+ handler.plf.setASTLocusTag(loc);
+ try {
+ impl.log(level, msg);
+ } finally {
+ handler.plf.setASTLocusTag(null);
+ }
+ }
+ @Override
+ public void log(final Level level, final ASTLocusTag loc, final String msg, final Object param) {
+ handler.plf.setASTLocusTag(loc);
+ try {
+ impl.log(level, msg, param);
+ } finally {
+ handler.plf.setASTLocusTag(null);
+ }
+ }
+ @Override
+ public void log(final Level level, final ASTLocusTag loc, final String msg, final Object ... params) {
+ handler.plf.setASTLocusTag(loc);
+ try {
+ impl.log(level, msg, params);
+ } finally {
+ handler.plf.setASTLocusTag(null);
+ }
+ }
+
+ @Override
+ public void setLevel(final Level newLevel) throws SecurityException {
+ impl.setLevel(newLevel);
+ }
+ @Override
+ public void setLevelOfAllHandler(final Level newLevel) throws SecurityException {
+ final Handler[] hs = getHandlers();
+ for(final Handler h:hs) {
+ h.setLevel(newLevel);
+ }
+ }
+ @Override
+ public Level getLevel() {
+ return impl.getLevel();
+ }
+ @Override
+ public boolean isLoggable(final Level level) {
+ return impl.isLoggable(level);
+ }
+ @Override
+ public String getName() {
+ return impl.getName();
+ }
+ @Override
+ public synchronized Handler[] getHandlers() {
+ return impl.getHandlers();
+ }
+ @Override
+ public String getSourceClassName() {
+ return handler.plf.simpleClassName;
+ }
+ }
+ static class PlainLogConsoleHandler extends ConsoleHandler {
+ final PlainLogFormatter plf;
+ PlainLogConsoleHandler(final PlainLogFormatter plf, final Level level) {
+ this.plf = plf;
+ setFormatter(plf);
+ setLevel(level);
+ }
+ @Override
+ public java.util.logging.Formatter getFormatter() {
+ return plf;
+ }
+ }
+ static class PlainLogFormatter extends Formatter {
+ final String simpleClassName;
+ ASTLocusTag astLocus;
+ PlainLogFormatter(final String simpleClassName) {
+ this.simpleClassName = simpleClassName;
+ }
+ public void setASTLocusTag(final ASTLocusTag loc) { astLocus = loc; }
+ @Override
+ public String format(final LogRecord record) {
+ // Replace [Type, JavaType] -> its debug string!
+ final Object[] params = record.getParameters();
+ if( null != params ) {
+ for(int i=params.length-1; 0<=i; i--) {
+ final Object o = params[i];
+ if( o instanceof Type ) {
+ params[i] = ((Type)o).getDebugString();
+ } else if( o instanceof JavaType ) {
+ params[i] = ((JavaType)o).getDebugString();
+ } else if( o instanceof AliasedSymbol ) {
+ params[i] = ((AliasedSymbol)o).getAliasedString();
+ }
+ }
+ }
+ final StringBuilder sb = new StringBuilder(256);
+ if( null != astLocus ) {
+ astLocus.toString(sb, getCanonicalName(record.getLevel()), GlueGen.debug()).append(": ");
+ }
+ if( GlueGen.debug() ) {
+ sb.append(simpleClassName).append(": ");
+ }
+ sb.append(formatMessage(record)).append("\n");
+ return sb.toString();
+ }
+ }
+
+ private final static Map<String, LoggerIf> loggers;
+ private final static FQNLogger rootPackageLogger;
+ static {
+ loggers = new HashMap<String, LoggerIf>();
final String packageName = Logging.class.getPackage().getName();
final String property = PropertyAccess.getProperty(packageName+".level", true);
Level level;
if(property != null) {
level = Level.parse(property);
} else {
- level = Level.WARNING;
+ if( DEBUG || GlueGen.debug() ) {
+ level = Level.ALL;
+ } else {
+ level = Level.WARNING;
+ }
}
+ final String simpleClassName = Logging.class.getSimpleName();
+ final String fqnClassName = packageName+"."+simpleClassName;
+ rootPackageLogger = new FQNLogger(fqnClassName, simpleClassName, level);
+ loggers.put(fqnClassName, rootPackageLogger);
+ }
- final ConsoleHandler handler = new ConsoleHandler() {
- @Override
- public java.util.logging.Formatter getFormatter() {
- return new PlainLogFormatter();
- }
- };
- handler.setFormatter(new PlainLogFormatter());
- handler.setLevel(level);
-
- final Logger rootPackageLogger = Logger.getLogger(packageName);
- rootPackageLogger.setUseParentHandlers(false);
- rootPackageLogger.setLevel(level);
- rootPackageLogger.addHandler(handler);
+ /** provokes static initialization */
+ static void init() { }
+
+ public static String getCanonicalName(final Level level) {
+ if( Level.CONFIG == level ) {
+ return "config";
+ } else if( Level.FINER == level ) {
+ return "verbose";
+ } else if( Level.FINE == level ) {
+ return "debug";
+ } else if( Level.INFO == level ) {
+ return "info";
+ } else if( Level.WARNING == level ) {
+ return "warning";
+ } else if( Level.SEVERE == level ) {
+ return "error";
+ } else {
+ return level.getName().toLowerCase();
+ }
}
- /**
- * This log formatter needs usually one line per log record.
- * @author Michael Bien
- */
- private static class PlainLogFormatter extends Formatter {
+ /** Returns the <i>root package logger</i>. */
+ public static LoggerIf getLogger() {
+ return rootPackageLogger;
+ }
+ /** Returns the demanded logger, while aligning its log-level to the root logger's level. */
+ public static synchronized LoggerIf getLogger(final Class<?> clazz) {
+ return getLogger(clazz.getPackage().getName(), clazz.getSimpleName());
+ }
- @Override
- public String format(final LogRecord record) {
- final StringBuilder sb = new StringBuilder(128);
- sb.append("[").append(record.getLevel()).append(' ').append(record.getSourceClassName()).append("]: ");
- sb.append(formatMessage(record)).append("\n");
- return sb.toString();
+ /** Returns the demanded logger, while aligning its log-level to the root logger's level. */
+ public static synchronized LoggerIf getLogger(final String packageName, final String simpleClassName) {
+ final String fqnClassName = packageName+"."+simpleClassName;
+ LoggerIf res = loggers.get(fqnClassName);
+ if( null == res ) {
+ res = new FQNLogger(fqnClassName, simpleClassName, rootPackageLogger.getLevel());
+ loggers.put(fqnClassName, res);
}
+ return res;
+ }
+ /** Align log-level of given logger to the root logger's level. */
+ public static void alignLevel(final LoggerIf l) {
+ alignLevel(l, rootPackageLogger.getLevel());
+ }
+ /** Align log-level of given logger and all its handlers to the given level. */
+ public static void alignLevel(final LoggerIf l, final Level level) {
+ l.setLevel(level);
+ l.setLevelOfAllHandler(level);
}
}
diff --git a/src/java/com/jogamp/gluegen/MethodBinding.java b/src/java/com/jogamp/gluegen/MethodBinding.java
index 93c55d5..95a10c6 100644
--- a/src/java/com/jogamp/gluegen/MethodBinding.java
+++ b/src/java/com/jogamp/gluegen/MethodBinding.java
@@ -43,8 +43,6 @@ import com.jogamp.gluegen.cgram.types.FunctionSymbol;
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 +52,10 @@ import java.util.List;
public class MethodBinding {
private final FunctionSymbol sym;
- private String renamedMethodName;
- private final HashSet<String> aliasedNames;
+ private final String delegationImplName;
+ private final JavaType containingType;
+ private final Type containingCType;
+ private String nativeName;
private JavaType javaReturnType;
private List<JavaType> javaArgumentTypes;
private boolean computedSignatureProperties;
@@ -69,8 +69,6 @@ public class MethodBinding {
private boolean signatureUsesCArrays;
private boolean signatureUsesJavaPrimitiveArrays;
private boolean signatureRequiresStaticInitialization;
- private JavaType containingType;
- private Type containingCType;
private int thisPointerIndex = -1;
/**
@@ -79,12 +77,12 @@ public class MethodBinding {
* types. It's safe to modify this binding after construction.
*/
public MethodBinding(final MethodBinding bindingToCopy) {
- this.sym = bindingToCopy.sym;
-
- this.renamedMethodName = bindingToCopy.renamedMethodName;
- this.aliasedNames = new HashSet<String>(bindingToCopy.aliasedNames);
+ this.sym = bindingToCopy.sym;
+ this.delegationImplName = bindingToCopy.delegationImplName;
this.containingType = bindingToCopy.containingType;
this.containingCType = bindingToCopy.containingCType;
+
+ this.nativeName = bindingToCopy.nativeName;
this.javaReturnType = bindingToCopy.javaReturnType;
this.javaArgumentTypes = ( null != bindingToCopy.javaArgumentTypes ) ? new ArrayList<JavaType>(bindingToCopy.javaArgumentTypes) : null;
this.computedSignatureProperties = bindingToCopy.computedSignatureProperties;
@@ -101,19 +99,27 @@ public class MethodBinding {
this.thisPointerIndex = bindingToCopy.thisPointerIndex;
}
- /** 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
- struct. */
- public MethodBinding(final FunctionSymbol sym, final JavaType containingType, final Type containingCType) {
+ /**
+ * Constructor for calling a C function or a function pointer contained in a struct.
+ * <p>
+ * In case of the latter, a struct function pointer,
+ * the arguments {@code containingType} and {@code containingCType} must not be {@code null}!
+ * </p>
+ */
+ public MethodBinding(final FunctionSymbol sym,
+ final String delegationImplName,
+ final JavaType javaReturnType,
+ final List<JavaType> javaArgumentTypes,
+ final JavaType containingType,
+ final Type containingCType) {
this.sym = sym;
+ this.delegationImplName = delegationImplName;
this.containingType = containingType;
this.containingCType = containingCType;
- this.aliasedNames = new HashSet<String>();
+
+ this.nativeName = null;
+ this.javaReturnType = javaReturnType;
+ this.javaArgumentTypes = javaArgumentTypes;
}
public void setJavaReturnType(final JavaType type) {
@@ -149,6 +155,7 @@ public class MethodBinding {
return sym.getArgumentType(i);
}
+ /** Returns the {@link FunctionSymbol}. */
public FunctionSymbol getCSymbol() {
return sym;
}
@@ -166,33 +173,42 @@ public class MethodBinding {
return "arg" + i;
}
- public String getOrigName() {
- return sym.getName();
- }
-
+ /** Returns the {@link FunctionSymbol}'s current {@link FunctionSymbol#getName() aliased} API name. */
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);
+ /**
+ * The
+ * {@link JavaConfiguration#getDelegatedImplementation(com.jogamp.gluegen.cgram.types.AliasedSymbol) implementation delegation}
+ * name, or {@code null} for no delegation.
+ * @see #getImplName()
+ */
+ public String getDelegationImplName() {
+ return delegationImplName;
}
- public Collection<String> getAliasedNames() {
- return aliasedNames;
+ /** Returns the {@link FunctionSymbol}'s current {@link FunctionSymbol#getName() aliased} API name for the interface. */
+ public String getInterfaceName() {
+ return sym.getName();
}
+ /**
+ * Returns the {@link FunctionSymbol}'s name for the implementation,
+ * which is the current {@link FunctionSymbol#getName() aliased} API name per default,
+ * or the {@link #getDelegationImplName() delegation} name.
+ * @see #getDelegationImplName()
+ */
+ public String getImplName() {
+ return null != delegationImplName ? delegationImplName : sym.getName();
+ }
+ /**
+ * Returns the {@link FunctionSymbol}'s name for the native function
+ * which is the {@link FunctionSymbol#getOrigName() original} C API name per default,
+ * but may be overridden via {@link #setNativeName(String)}.
+ */
+ public String getNativeName() {
+ return null != nativeName ? nativeName : sym.getOrigName();
+ }
+ public void setNativeName(final String s) { nativeName = s; }
/** Creates a new MethodBinding replacing the specified Java
argument type with a new argument type. If argumentNumber is
diff --git a/src/java/com/jogamp/gluegen/ReferencedStructs.java b/src/java/com/jogamp/gluegen/ReferencedStructs.java
index d06d47f..26deb3a 100644
--- a/src/java/com/jogamp/gluegen/ReferencedStructs.java
+++ b/src/java/com/jogamp/gluegen/ReferencedStructs.java
@@ -44,31 +44,43 @@ import com.jogamp.gluegen.cgram.types.*;
public class ReferencedStructs implements TypeVisitor {
- private final Set<Type> results = new HashSet<Type>();
+ private final Map<String, Type> resultMap = new HashMap<String, Type>();
+ private final Set<CompoundType> layoutSet = new HashSet<CompoundType>();
+ private final Set<Type> skip = new HashSet<Type>();
- public void clear() {
- results.clear();
- }
+ public void clear() {
+ resultMap.clear();
+ }
- public Iterator<Type> results() {
- return results.iterator();
- }
+ public Iterator<Type> results() {
+ return resultMap.values().iterator();
+ }
+ public Iterator<CompoundType> layouts() {
+ return layoutSet.iterator();
+ }
- @Override
- public void visitType(final Type t) {
- if (t.isPointer()) {
- final PointerType p = t.asPointer();
- if (p.hasTypedefedName()) {
- final CompoundType c = p.getTargetType().asCompound();
- if (c != null && c.getName() == null) {
- // This otherwise-unnamed CompoundType is referred to by a
- // PointerType that has a typedef name. Assume that it is
- // referred to in the glue code and emit it.
- results.add(p);
+ @Override
+ public void visitType(final Type t) {
+ if( skip.contains(t) ) {
+ return;
+ }
+ if ( t.isPointer() ) {
+ final PointerType p = t.asPointer();
+ final CompoundType c = p.getTargetType().asCompound();
+ if( p.isTypedef() && null != c ) {
+ // If containing pointer is typedef, use it (preferred)
+ skip.add(c); // earmark to skip the compound!
+ resultMap.put(c.getName(), p);
+ layoutSet.add(c);
+ } else {
+ // .. otherwise skip pointer and use followup compound
+ }
+ } else if( t.isCompound() ) {
+ // Use compound if not yet mapped, e.g. by typedef'ed (preferred)
+ if( !resultMap.containsKey(t.getName()) ) {
+ resultMap.put(t.getName(), t);
+ }
+ layoutSet.add(t.asCompound()); // always: could be const/volatile variants ..
}
- }
- } else if (t.isCompound()) {
- results.add(t);
}
- }
}
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/ant/GlueGenTask.java b/src/java/com/jogamp/gluegen/ant/GlueGenTask.java
index dd57365..2b11d3f 100644
--- a/src/java/com/jogamp/gluegen/ant/GlueGenTask.java
+++ b/src/java/com/jogamp/gluegen/ant/GlueGenTask.java
@@ -73,7 +73,8 @@ import org.apache.tools.ant.util.JavaEnvUtils;
emitter="[emitter class name]"
config="[configuration file]"
dumpCPP="[optional boolean]"
- debug="[optional boolean]" /&gt;
+ debug="[optional boolean]"
+ logLevel="[optional string]" /&gt;
* </pre>
*
* @author Rob Grzywinski <a href="mailto:[email protected]">[email protected]</a>
@@ -101,6 +102,11 @@ public class GlueGenTask extends Task
private boolean debug=false;
/**
+ * <p>The optional logLevel.</p>
+ */
+ private String logLevel = null;
+
+ /**
* <p>The optional dumpCPP flag.</p>
*/
private boolean dumpCPP=false;
@@ -182,6 +188,15 @@ public class GlueGenTask extends Task
}
/**
+ * <p>Set the logLevel (optional). This is called by ANT.</p>
+ */
+ public void setLogLevel(final String logLevel)
+ {
+ log( ("Setting logLevel: " + logLevel), Project.MSG_VERBOSE);
+ this.logLevel=logLevel;
+ }
+
+ /**
* <p>Set the dumpCPP flag (optional). This is called by ANT.</p>
*/
public void setDumpCPP(final boolean dumpCPP)
@@ -456,6 +471,12 @@ public void setIncludeRefid(final Reference reference) {
gluegenCommandline.createArgument().setValue("--debug");
}
+ // add the logLevel if enabled
+ if(null != logLevel) {
+ gluegenCommandline.createArgument().setValue("--logLevel");
+ gluegenCommandline.createArgument().setValue(logLevel);
+ }
+
// add the debug flag if enabled
if(dumpCPP) {
gluegenCommandline.createArgument().setValue("--dumpCPP");
diff --git a/src/java/com/jogamp/gluegen/cgram/Define.java b/src/java/com/jogamp/gluegen/cgram/Define.java
index 797cf6f..23caabd 100644
--- a/src/java/com/jogamp/gluegen/cgram/Define.java
+++ b/src/java/com/jogamp/gluegen/cgram/Define.java
@@ -39,18 +39,32 @@
package com.jogamp.gluegen.cgram;
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+
/** Represents a #define of a literal to a value (a number represented
in string form.) */
-public class Define {
+public class Define implements ASTLocusTagProvider {
private final String name;
private final String value;
+ private final ASTLocusTag astLocus;
public Define(final String name, final String value) {
this.name = name;
this.value = value;
+ this.astLocus = null;
+ }
+
+ public Define(final String name, final String value, final ASTLocusTag astLocus) {
+ this.name = name;
+ this.value = value;
+ this.astLocus = astLocus;
}
public String getName() { return name; }
public String getValue() { return value; }
+
+ @Override
+ public ASTLocusTag getASTLocusTag() { return astLocus; }
}
diff --git a/src/java/com/jogamp/gluegen/cgram/TNode.java b/src/java/com/jogamp/gluegen/cgram/TNode.java
index a564c54..5a36945 100644
--- a/src/java/com/jogamp/gluegen/cgram/TNode.java
+++ b/src/java/com/jogamp/gluegen/cgram/TNode.java
@@ -3,10 +3,15 @@ package com.jogamp.gluegen.cgram;
import antlr.collections.AST;
import antlr.CommonAST;
import antlr.Token;
+
import java.lang.reflect.*;
import java.util.Hashtable;
import java.util.Enumeration;
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+import com.jogamp.gluegen.GlueGen;
+
/**
Class TNode is an implementation of the AST interface
and adds many useful features:
@@ -29,7 +34,8 @@ import java.util.Enumeration;
*/
-public class TNode extends CommonAST {
+@SuppressWarnings("serial")
+public class TNode extends CommonAST implements ASTLocusTagProvider {
protected int ttype;
protected String text;
protected int lineNum = 0;
@@ -40,7 +46,22 @@ public class TNode extends CommonAST {
protected Hashtable<String, Object> attributes = null;
static String tokenVocabulary;
-
+ /**
+ * {@inheritDoc}
+ * <p>
+ * If <i>source</i> is not available,
+ * implementation returns {@code null}.
+ * </p>
+ */
+ @Override
+ public ASTLocusTag getASTLocusTag() {
+ final Object s = getAttribute("source");
+ if( null != s ) {
+ return new ASTLocusTag(s, getLineNum(), -1, getText());
+ } else {
+ return null;
+ }
+ }
/** Set the token vocabulary to a tokentypes class
@@ -159,15 +180,87 @@ public void initialize(final AST tr) {
text = text_;
}
- /** Returns the text for this node and all children */
- public String getAllChildrenText() {
+ static class DebugASTVisitor {
+ protected int level;
+ private String tabs(final StringBuilder sb) {
+ sb.setLength(0);
+ for (int i = 0; i < level; i++) {
+ sb.append(" ");
+ }
+ return sb.toString();
+ }
+ DebugASTVisitor(final int level) {
+ this.level = level;
+ }
+ void visit(final AST node) {
+ final StringBuilder sb = new StringBuilder();
+ AST node2;
+ for (node2 = node; node2 != null; node2 = node2.getNextSibling()) {
+ if (node2.getText() == null) {
+ System.err.printf("%03d: %snil [%d]%n", level, tabs(sb), node2.getType());
+ } else {
+ System.err.printf("%03d: %s%s [%d]%n", level, tabs(sb), node2.getText(), node2.getType());
+ }
+ if (node2.getFirstChild() != null) {
+ level++;
+ visit(node2.getFirstChild());
+ level--;
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the text for this node, its children and siblings.
+ * <p>
+ * Implementation converts the AST LISP notation to serialized form.
+ * </p>
+ */
+ public String getAllChildrenText(final String name) {
+ if( GlueGen.debug() ) {
+ System.err.println("TNode.XXX: "+name);
+ new DebugASTVisitor(1).visit(getFirstChild());
+ }
final StringBuilder buf = new StringBuilder();
- buf.append(getText());
- for (TNode node = (TNode) getFirstChild(); node != null; node = (TNode) node.getNextSibling()) {
- buf.append(node.getText());
+ final TNode down = (TNode) this.getFirstChild();
+ if( null == down ) {
+ buf.append(this.getText());
+ } else {
+ getAllChildrenText(buf, this, down);
}
return buf.toString();
}
+ private static void getAllChildrenText(final StringBuilder buf,
+ final TNode upNode, TNode thisNode) {
+ boolean first = true;
+ while( null != thisNode ) {
+ final boolean isClosing = HeaderParserTokenTypes.RPAREN == thisNode.getType();
+ final boolean isGroupStart = HeaderParserTokenTypes.NExpressionGroup == thisNode.getType();
+
+ final TNode nextNode = (TNode) thisNode.getNextSibling();
+ final TNode downNode = (TNode) thisNode.getFirstChild();
+ if( !isClosing &&
+ ( null == downNode && null == nextNode || // unary
+ !first // binary
+ )
+ ) {
+ buf.append(" ").append(upNode.getText());
+ }
+ if( null != downNode ) {
+ if( !isGroupStart ) {
+ buf.append(" (");
+ }
+ getAllChildrenText(buf, thisNode, downNode);
+ if( !isGroupStart ) {
+ buf.append(" )");
+ }
+ } else if( !isClosing ) {
+ buf.append(" ").append(thisNode.getText());
+ }
+ thisNode = nextNode;
+ first = false;
+ }
+ }
/** return the last child of this node, or null if there is none */
public TNode getLastChild() {
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..869c658
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java
@@ -0,0 +1,185 @@
+/**
+ * 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>
+ * <p>
+ * Operation will be ignored if {@code newName} is {@code null}.
+ * </p>
+ * @param newName the new {@link #getName() current-name}, maybe {@code null}
+ */
+ void rename(final String newName);
+ /**
+ * Add the given {@code origName} to the list of {@link #getAliasedNames() aliases}
+ * if not equal {@link #getName() current-name}.
+ * <p>
+ * Operation will be ignored if {@code newName} is {@code null}.
+ * </p>
+ * @param origName the new alias to be added, maybe {@code null}
+ */
+ 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>
+ * Inclusive {@link #getOrigName() original-name}, if {@link #rename(String) renamed},
+ * </p>
+ * <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 original-name as set at creation.
+ */
+ String getOrigName();
+ /**
+ * Return the current-name, which is the last {@link #rename(String) renamed-name} if issued,
+ * or the {@link #getOrigName() 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 String origName;
+ private final HashSet<String> aliasedNames;
+ private String name;
+
+ public AliasedSymbolImpl(final String origName) {
+ if( null == origName ) {
+ throw new IllegalArgumentException("Null origName not allowed");
+ }
+ this.origName = origName;
+ this.aliasedNames=new HashSet<String>();
+ this.name = origName;
+ }
+ public AliasedSymbolImpl(final AliasedSymbolImpl o) {
+ this.origName = o.origName;
+ this.aliasedNames = new HashSet<String>(o.aliasedNames);
+ this.name = o.name;
+ }
+ @Override
+ public void rename(final String newName) {
+ if( null != newName && !name.equals(newName) ) {
+ aliasedNames.add(name);
+ aliasedNames.remove(newName);
+ name = newName;
+ }
+ }
+ @Override
+ public void addAliasedName(final String origName) {
+ if( null != origName && !name.equals(origName) ) {
+ aliasedNames.add(origName);
+ }
+ }
+ @Override
+ public boolean hasAliases() {
+ return aliasedNames.size() > 0;
+ }
+ @Override
+ public Set<String> getAliasedNames() {
+ return aliasedNames;
+ }
+ @Override
+ public String getOrigName() {
+ return origName;
+ }
+ @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 getOrigName() {
+ return name;
+ }
+ @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..ada34f7 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java
@@ -40,6 +40,8 @@
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
/** Represents an array type. This differs from a pointer type in C
syntax by the use of "[]" rather than "*". The length may or may
not be known; if the length is unknown then a negative number
@@ -48,50 +50,79 @@ 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);
+ public ArrayType(final Type elementType, final SizeThunk sizeInBytes, final int length,
+ final int cvAttributes) {
+ this(elementType, sizeInBytes, length, cvAttributes, null);
+ }
+ public ArrayType(final Type elementType, final SizeThunk sizeInBytes, final int length,
+ final int cvAttributes, final ASTLocusTag astLocus) {
+ super(elementType.getName() + " *", sizeInBytes, cvAttributes, astLocus);
this.elementType = elementType;
this.length = length;
}
+ private ArrayType(final ArrayType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
+ elementType = o.elementType;
+ length = o.length;
+ }
@Override
- public boolean equals(final Object arg) {
- if (arg == this) return true;
- if (arg == null || (!(arg instanceof ArrayType))) {
- return false;
- }
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new ArrayType(this, cvAttributes, astLocus);
+ }
+
+ @Override
+ 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 (super.equals(arg) && elementType.equals(t.elementType) && (length == t.length));
+ 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 elementType.equalSemantics(t.elementType) &&
+ length == t.length;
+ }
+
+ @Override
+ public boolean isAnon() { return elementType.isAnon(); }
+
+ @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
- public ArrayType asArray() { return this; }
+ public final ArrayType asArray() { return this; }
public Type getElementType() { return elementType; }
public int getLength() { return length; }
public boolean hasLength() { return length >= 0; }
@Override
- public Type getBaseElementType() {
- ArrayType t = this;
- while (t.getElementType().isArray()) {
- t = t.getElementType().asArray();
- }
- return t.getElementType();
- // return elementType.getBaseElementType();
+ public final Type getBaseElementType() {
+ return elementType.getBaseElementType();
+ }
+
+ @Override
+ public final int arrayDimension() {
+ return 1 + elementType.arrayDimension();
}
/** Recompute the size of this array if necessary. This needs to be
@@ -114,7 +145,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);
@@ -130,9 +161,4 @@ public class ArrayType extends MemoryLayoutType implements Cloneable {
super.visit(arg);
elementType.visit(arg);
}
-
- @Override
- Type newCVVariant(final int cvAttributes) {
- return new ArrayType(elementType, getSize(), length, cvAttributes);
- }
}
diff --git a/src/java/com/jogamp/gluegen/cgram/types/BitType.java b/src/java/com/jogamp/gluegen/cgram/types/BitType.java
index 2644551..834ff95 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.ASTLocusTag;
+
/** Represents a bitfield in a struct. */
public class BitType extends IntType implements Cloneable {
@@ -47,22 +49,60 @@ public class BitType extends IntType implements Cloneable {
private final int sizeInBits;
private final int offset;
- public BitType(final IntType underlyingType, final int sizeInBits, final int lsbOffset, final int cvAttributes) {
- super(underlyingType.getName(), underlyingType.getSize(), underlyingType.isUnsigned(), cvAttributes);
+ public BitType(final IntType underlyingType, final int sizeInBits, final int lsbOffset,
+ final int cvAttributes, final ASTLocusTag astLocus) {
+ super(underlyingType.getName(), underlyingType.getSize(), underlyingType.isUnsigned(), cvAttributes, astLocus);
this.underlyingType = underlyingType;
this.sizeInBits = sizeInBits;
this.offset = lsbOffset;
}
+ private BitType(final BitType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
+ underlyingType = o.underlyingType;
+ sizeInBits = o.sizeInBits;
+ offset = o.offset;
+ }
+
+ @Override
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new BitType(this, cvAttributes, astLocus);
+ }
+
+ @Override
+ protected int hashCodeImpl() {
+ // 31 * x == (x << 5) - x
+ int hash = super.hashCodeImpl();
+ hash = ((hash << 5) - hash) + underlyingType.hashCode();
+ hash = ((hash << 5) - hash) + sizeInBits;
+ return ((hash << 5) - hash) + offset;
+ }
+
@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 boolean equalsImpl(final Type arg) {
+ final BitType t = (BitType) arg;
+ return super.equalsImpl(arg) &&
+ underlyingType.equals(t.underlyingType) &&
+ sizeInBits == t.sizeInBits &&
+ offset == t.offset;
+ }
+
+ @Override
+ protected int hashCodeSemanticsImpl() {
+ // 31 * x == (x << 5) - x
+ int hash = super.hashCodeSemanticsImpl();
+ hash = ((hash << 5) - 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 super.equalSemanticsImpl(arg) &&
+ underlyingType.equalSemantics(t.underlyingType) &&
+ sizeInBits == t.sizeInBits &&
+ offset == t.offset;
}
@Override
@@ -84,9 +124,4 @@ public class BitType extends IntType implements Cloneable {
super.visit(arg);
underlyingType.visit(arg);
}
-
- @Override
- Type newCVVariant(final int cvAttributes) {
- return new BitType(underlyingType, sizeInBits, offset, cvAttributes);
- }
}
diff --git a/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java b/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java
index 9716f54..56bcdda 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java
@@ -42,73 +42,110 @@ package com.jogamp.gluegen.cgram.types;
import java.util.*;
+import com.jogamp.gluegen.ASTLocusTag;
+
/** Models all compound types, i.e., those containing fields: structs
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;
- CompoundType(final String name, final SizeThunk size, final int cvAttributes, final String structName) {
- super(name, size, cvAttributes);
- this.structName = structName;
+ @Override
+ public void rename(final String newName) {
+ throw new UnsupportedOperationException();
}
-
- public static CompoundType create(final String name, final SizeThunk size, final CompoundTypeKind kind, final int cvAttributes) {
+ @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();
+ }
+ @Override
+ public String getOrigName() {
+ return getName();
+ }
+ /**
+ * @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 ASTLocusTag astLocus)
+ {
+ final CompoundType res;
switch (kind) {
case STRUCT:
- return new StructType(name, size, cvAttributes);
+ res = new StructType(null, size, cvAttributes, structName, astLocus);
+ break;
case UNION:
- return new UnionType(name, size, cvAttributes);
+ res = new UnionType(null, size, cvAttributes, structName, astLocus);
+ break;
default:
throw new RuntimeException("OO relation "+kind+" / Compount not yet supported");
}
+ return res;
}
- @Override
- public Object clone() {
- final CompoundType n = (CompoundType) super.clone();
- if(null!=this.fields) {
- n.fields = new ArrayList<Field>(this.fields);
+ CompoundType(final String name, final SizeThunk size, final int cvAttributes,
+ final String structName, final ASTLocusTag astLocus) {
+ super(null == name ? structName : name, size, cvAttributes, astLocus);
+ this.structName = structName;
+ }
+
+ CompoundType(final CompoundType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
+ this.structName = o.structName;
+ if(null != o.fields) {
+ fields = new ArrayList<Field>(o.fields);
}
- return n;
+ bodyParsed = o.bodyParsed;
}
@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,22 +154,20 @@ 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);
- }
+ public CompoundType asCompound() { return this; }
@Override
- public CompoundType asCompound() { return this; }
+ public String getCName(final boolean includeCVAttrs) {
+ if( isTypedef() ) {
+ 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,17 +182,24 @@ 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.
+ * @throws IllegalStateException If called twice.
+ */
+ public void setBodyParsed() throws IllegalStateException {
+ if (bodyParsed) {
+ throw new IllegalStateException("Body of this CompoundType has been already closed");
+ }
bodyParsed = true;
}
@@ -169,8 +211,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 {
@@ -188,12 +231,12 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable
super.visit(arg);
final int n = getNumFields();
for (int i = 0; i < n; i++) {
- final Field f = getField(i);
- f.getType().visit(arg);
+ getField(i).getType().visit(arg);
}
} finally {
visiting = false;
}
+ return;
}
public String getStructString() {
diff --git a/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java b/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java
index de42522..133a322 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java
@@ -39,22 +39,22 @@
*/
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
/** Represents a double-word floating-point type (C type "double".) */
public class DoubleType extends PrimitiveType implements Cloneable {
- public DoubleType(final String name, final SizeThunk size, final int cvAttributes) {
- super(name, size, cvAttributes);
+ public DoubleType(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(name, size, cvAttributes, astLocus);
+ }
+
+ private DoubleType(final DoubleType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
}
@Override
- public boolean equals(final Object arg) {
- if (arg == this) {
- return true;
- }
- if (arg == null || (!(arg instanceof DoubleType))) {
- return false;
- }
- return super.equals(arg);
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new DoubleType(this, cvAttributes, astLocus);
}
@Override
@@ -63,7 +63,22 @@ public class DoubleType extends PrimitiveType implements Cloneable {
}
@Override
- Type newCVVariant(final int cvAttributes) {
- return new DoubleType(getName(), getSize(), cvAttributes);
+ 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/cgram/types/EnumType.java b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java
index 0b1193b..7c2fa73 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/EnumType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java
@@ -42,73 +42,132 @@ package com.jogamp.gluegen.cgram.types;
import java.util.ArrayList;
import java.util.NoSuchElementException;
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ConstantDefinition;
+import com.jogamp.gluegen.ConstantDefinition.CNumber;
+import com.jogamp.gluegen.GlueGenException;
+import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp;
+
/** Describes enumerated types. Enumerations are like ints except that
they have a set of named values. */
public class EnumType extends IntType implements Cloneable {
- private IntType underlyingType;
+ public static class Enumerator implements TypeComparator.SemanticEqualityOp {
+ private final String name;
+ private final String expr;
+ private final CNumber number;
- private static class Enum {
+ public Enumerator(final String name, final long value) {
+ this.name = name;
+ this.number = new CNumber(false, false, value);
+ this.expr = this.number.toJavaString();
+ }
+ public Enumerator(final String name, final CNumber number) {
+ this.name = name;
+ this.number = number;
+ this.expr = this.number.toJavaString();
+ }
+ public Enumerator(final String name, final String value) {
+ this.name = name;
+ this.expr = value;
+ this.number = ConstantDefinition.decodeIntegerNumber(value);
+ }
- String name;
- long value;
+ public String getName() { return name; }
+ public String getExpr() { return expr; }
+ public CNumber getNumber() { return number; }
+ public boolean hasNumber() { return null != number; }
- Enum(final String name, final long value) {
- this.name = name;
- this.value = value;
+ @Override
+ public int hashCode() {
+ // 31 * x == (x << 5) - x
+ final int hash = name.hashCode();
+ return ((hash << 5) - hash) + expr.hashCode();
}
- String getName() {
- return name;
+ @Override
+ public boolean equals(final Object arg) {
+ if (arg == this) {
+ return true;
+ } else if ( !(arg instanceof Enumerator) ) {
+ return false;
+ }
+ final Enumerator t = (Enumerator) arg;
+ return name.equals(t.name) &&
+ expr.equals(t.expr);
}
- long getValue() {
- return value;
+ @Override
+ public int hashCodeSemantics() {
+ return hashCode();
}
+
+ @Override
+ public boolean equalSemantics(final SemanticEqualityOp arg) {
+ return equals(arg);
+ }
+
+ @Override
+ public String toString() { return "["+name+" = ["+expr+", "+number+"]"; }
}
- private ArrayList<Enum> enums;
+ private final IntType underlyingType;
+ private ArrayList<Enumerator> enums;
public EnumType(final String name) {
super(name, SizeThunk.LONG, false, CVAttributes.CONST);
this.underlyingType = new IntType(name, SizeThunk.LONG, false, CVAttributes.CONST);
}
- public EnumType(final String name, final SizeThunk enumSizeInBytes) {
- super(name, enumSizeInBytes, false, CVAttributes.CONST);
- this.underlyingType = new IntType(name, enumSizeInBytes, false, CVAttributes.CONST);
+ public EnumType(final String name, final SizeThunk enumSizeInBytes, final ASTLocusTag astLocus) {
+ super(name, enumSizeInBytes, false, CVAttributes.CONST, astLocus);
+ this.underlyingType = new IntType(name, enumSizeInBytes, false, CVAttributes.CONST, astLocus);
}
- protected EnumType(final String name, final IntType underlyingType, final int cvAttributes) {
- super(name, underlyingType.getSize(), underlyingType.isUnsigned(), cvAttributes);
- this.underlyingType = underlyingType;
+ private EnumType(final EnumType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
+ underlyingType = o.underlyingType;
+ if(null != o.enums) {
+ enums = new ArrayList<Enumerator>(o.enums);
+ }
}
@Override
- public Object clone() {
- final EnumType n = (EnumType) super.clone();
- if(null!=this.underlyingType) {
- n.underlyingType = (IntType) this.underlyingType.clone();
- }
- if(null!=this.enums) {
- n.enums = new ArrayList<Enum>(this.enums);
- }
- return n;
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new EnumType(this, cvAttributes, astLocus);
}
@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
+ int hash = super.hashCodeImpl();
+ hash = ((hash << 5) - hash) + underlyingType.hashCode();
+ return ((hash << 5) - hash) + TypeComparator.listsHashCode(enums);
+ }
+
+ @Override
+ protected boolean equalsImpl(final Type arg) {
+ final EnumType t = (EnumType) arg;
+ return super.equalsImpl(arg) &&
+ underlyingType.equals(t.underlyingType) &&
+ TypeComparator.listsEqual(enums, t.enums);
+ }
+
+ @Override
+ protected int hashCodeSemanticsImpl() {
+ // 31 * x == (x << 5) - x
+ int hash = super.hashCodeSemanticsImpl();
+ hash = ((hash << 5) - hash) + underlyingType.hashCodeSemantics();
+ return ((hash << 5) - hash) + TypeComparator.listsHashCodeSemantics(enums);
+ }
+
+ @Override
+ protected boolean equalSemanticsImpl(final Type arg) {
final EnumType t = (EnumType) arg;
- return (super.equals(arg)
- && underlyingType.equals(t.underlyingType)
- && listsEqual(enums, t.enums));
+ return super.equalSemanticsImpl(arg) &&
+ underlyingType.equalSemantics(t.underlyingType) &&
+ TypeComparator.listsEqualSemantics(enums, t.enums);
}
@Override
@@ -116,11 +175,14 @@ public class EnumType extends IntType implements Cloneable {
return this;
}
- public void addEnum(final String name, final long val) {
+ public Type getUnderlyingType() { return this.underlyingType; }
+
+ public void addEnum(final String name, final Enumerator newEnum) {
if (enums == null) {
- enums = new ArrayList<Enum>();
+ enums = new ArrayList<Enumerator>();
}
- enums.add(new Enum(name, val));
+ enums.add(newEnum);
+ clearCache();
}
/** Number of enumerates defined in this enum. */
@@ -128,22 +190,17 @@ public class EnumType extends IntType implements Cloneable {
return enums.size();
}
- /** Fetch <i>i</i>th (0..getNumEnumerates() - 1) name */
- public String getEnumName(final int i) {
- return (enums.get(i)).getName();
+ /** Fetch <i>i</i>th (0..getNumEnumerates() - 1) {@link Enumerator} */
+ public Enumerator getEnum(final int i) {
+ return enums.get(i);
}
- /** Fetch <i>i</i>th (0..getNumEnumerates() - 1) value */
- public long getEnumValue(final int i) {
- return (enums.get(i)).getValue();
- }
-
- /** Fetch the value of the enumerate with the given name. */
- public long getEnumValue(final String name) {
+ /** Fetch the enumerate with the given name. */
+ public Enumerator getEnum(final String name) {
for (int i = 0; i < enums.size(); ++i) {
- final Enum n = (enums.get(i));
+ final Enumerator n = (enums.get(i));
if (n.getName().equals(name)) {
- return n.getValue();
+ return n;
}
}
throw new NoSuchElementException(
@@ -166,25 +223,30 @@ public class EnumType extends IntType implements Cloneable {
*/
public boolean removeEnumerate(final String name) {
for (int i = 0; i < enums.size(); ++i) {
- final Enum e = enums.get(i);
+ final Enumerator 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);
underlyingType.visit(arg);
}
-
- @Override
- Type newCVVariant(final int cvAttributes) {
- final EnumType t = new EnumType(getName(), underlyingType, cvAttributes);
- t.enums = enums;
- return t;
- }
}
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..2e7a2cf 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/FloatType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/FloatType.java
@@ -40,29 +40,44 @@
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
/** Represents a single-word floating-point type (C type "float".) */
public class FloatType extends PrimitiveType implements Cloneable {
- public FloatType(final String name, final SizeThunk size, final int cvAttributes) {
- super(name, size, cvAttributes);
+ public FloatType(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(name, size, cvAttributes, astLocus);
+ }
+
+ private FloatType(final FloatType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
}
@Override
- public boolean equals(final Object arg) {
- if (arg == this) {
- return true;
- }
- if (arg == null || (!(arg instanceof FloatType))) {
- return false;
- }
- return super.equals(arg);
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new FloatType(this, cvAttributes, astLocus);
}
@Override
public FloatType asFloat() { return this; }
@Override
- Type newCVVariant(final int cvAttributes) {
- return new FloatType(getName(), getSize(), cvAttributes);
+ 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/cgram/types/FunctionSymbol.java b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java
index d41f2fd..91a0a5a 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java
@@ -38,6 +38,14 @@
*/
package com.jogamp.gluegen.cgram.types;
+import java.util.List;
+
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+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 +59,37 @@ 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, ASTLocusTagProvider {
- private final String name;
private final FunctionType type;
+ private final ASTLocusTag astLocus;
public FunctionSymbol(final String name, final FunctionType type) {
- this.name = name;
+ super(name);
+ this.type = type;
+ this.astLocus = null;
+ }
+
+ public FunctionSymbol(final String name, final FunctionType type, final ASTLocusTag locus) {
+ super(name);
this.type = type;
+ this.astLocus = locus;
}
- public String getName() {
- return name;
+ /** Shallow'ish copy, only aliased names are re-created. */
+ public static FunctionSymbol cloneWithDeepAliases(final FunctionSymbol o) {
+ return new FunctionSymbol(o);
+ }
+ /** Warning: Shallow'ish copy, only aliased names are re-created. */
+ private FunctionSymbol(final FunctionSymbol o) {
+ super(o);
+ this.type = o.type;
+ this.astLocus = o.astLocus;
}
+ @Override
+ public ASTLocusTag getASTLocusTag() { return astLocus; }
+
/** Returns the type of this function. Do not add arguments to it
directly; use addArgument instead. */
public FunctionType getType() {
@@ -99,7 +124,7 @@ public class FunctionSymbol {
@Override
public String toString() {
- return getType().toString(getName());
+ return getType().toString(getName(), false);
}
/** Helper routine for emitting native javadoc tags */
@@ -109,10 +134,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 +145,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..2b9dec7 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.ASTLocusTag;
+
/** Describes a function type, used to model both function
declarations and (via PointerType) function pointers. */
public class FunctionType extends Type implements Cloneable {
@@ -49,35 +51,63 @@ public class FunctionType extends Type implements Cloneable {
private ArrayList<Type> argumentTypes;
private ArrayList<String> argumentNames;
- public FunctionType(final String name, final SizeThunk size, final Type returnType, final int cvAttributes) {
- super(name, size, cvAttributes);
+ public FunctionType(final String name, final SizeThunk size, final Type returnType,
+ final int cvAttributes) {
+ this(name, size, returnType, cvAttributes, null);
+ }
+ public FunctionType(final String name, final SizeThunk size, final Type returnType,
+ final int cvAttributes, final ASTLocusTag astLocus) {
+ super(name, size, cvAttributes, astLocus);
this.returnType = returnType;
}
- @Override
- public Object clone() {
- final FunctionType n = (FunctionType) super.clone();
- if(null!=this.argumentTypes) {
- n.argumentTypes = new ArrayList<Type>(this.argumentTypes);
+ private FunctionType(final FunctionType o, final ASTLocusTag astLocus) {
+ super(o, o.getCVAttributes(), astLocus);
+ returnType = o.returnType;
+ if(null != o.argumentTypes) {
+ argumentTypes = new ArrayList<Type>(o.argumentTypes);
}
- if(null!=this.argumentNames) {
- n.argumentNames = new ArrayList<String>(this.argumentNames);
+ if(null != o.argumentNames) {
+ argumentNames = new ArrayList<String>(o.argumentNames);
}
- return n;
}
@Override
- public boolean equals(final Object arg) {
- if (arg == this) {
- return true;
- }
- if (arg == null || (!(arg instanceof FunctionType))) {
- return false;
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ if( newCVVariant ) {
+ // Functions don't have const/volatile attributes
+ return this;
+ } else {
+ return new FunctionType(this, astLocus);
}
+ }
+
+ @Override
+ 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 (super.equals(arg)
- && returnType.equals(t.returnType)
- && listsEqual(argumentTypes, t.argumentTypes));
+ 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 returnType.equalSemantics(t.returnType) &&
+ TypeComparator.listsEqualSemantics(argumentTypes, t.argumentTypes);
}
@Override
@@ -115,28 +145,27 @@ 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
public String toString() {
- return toString(null);
- }
-
- public String toString(final String functionName) {
- return toString(functionName, false);
+ return toString(null, false);
}
public String toString(final String functionName, final boolean emitNativeTag) {
return toString(functionName, null, emitNativeTag, false);
}
- String toString(final String functionName, final String callingConvention, final boolean emitNativeTag, final boolean isPointer) {
+ 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 +198,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(" ");
@@ -193,10 +222,4 @@ public class FunctionType extends Type implements Cloneable {
getArgumentType(i).visit(arg);
}
}
-
- @Override
- Type newCVVariant(final int cvAttributes) {
- // Functions don't have const/volatile attributes
- return this;
- }
}
diff --git a/src/java/com/jogamp/gluegen/cgram/types/IntType.java b/src/java/com/jogamp/gluegen/cgram/types/IntType.java
index 3f8dddc..2433fc6 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/IntType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/IntType.java
@@ -39,37 +39,95 @@
*/
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
public class IntType extends PrimitiveType implements Cloneable {
private final boolean unsigned;
- private boolean typedefedUnsigned;
+ private boolean typedefUnsigned;
public IntType(final String name, final SizeThunk size, final boolean unsigned, final int cvAttributes) {
- this(name, size, unsigned, cvAttributes, false);
+ this(name, size, unsigned, cvAttributes, null);
}
- public IntType(final String name, final SizeThunk size, final boolean unsigned, final int cvAttributes, final boolean typedefedUnsigned) {
- super(name, size, cvAttributes);
+ public IntType(final String name, final SizeThunk size,
+ final boolean unsigned, final int cvAttributes,
+ final ASTLocusTag astLocus) {
+ super(name, size, cvAttributes, astLocus);
this.unsigned = unsigned;
- this.typedefedUnsigned = typedefedUnsigned;
+ this.typedefUnsigned = false;
}
- @Override
- public boolean equals(final Object arg) {
- if (arg == this) {
- return true;
- }
- if (arg == null || (!(arg instanceof IntType))) {
- return false;
+ /**
+ * Only for HeaderParser!
+ *
+ * @param name the name
+ * @param size the size
+ * @param unsigned true if this instance is unsigned, not the <i>typedef</i>!
+ * @param cvAttributes the cvAttributes for this instance, not for the <i>typedef</i>!
+ * @param isTypedef true if this instance is a <i>typedef</i> variant
+ * @param typedefUnsigned true if the <i>typedef</i> itself is unsigned
+ * @param astLocus the location in source code
+ */
+ public IntType(final String name, final SizeThunk size,
+ final boolean unsigned, final int cvAttributes,
+ final boolean isTypedef, final boolean typedefUnsigned,
+ final ASTLocusTag astLocus) {
+ super(name, size, cvAttributes, astLocus);
+ this.unsigned = unsigned;
+ if( isTypedef ) {
+ // the 'cvAttributes' are intended for this instance, not the 'typedef cvAttributes'!
+ setTypedef(0);
+ this.typedefUnsigned = typedefUnsigned;
+ } else {
+ this.typedefUnsigned = false;
}
+ }
+
+ IntType(final IntType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
+ this.unsigned = o.unsigned;
+ this.typedefUnsigned = o.typedefUnsigned;
+ }
+
+ @Override
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new IntType(this, cvAttributes, astLocus);
+ }
+
+ @Override
+ protected int hashCodeImpl() {
+ // 31 * x == (x << 5) - x
+ int hash = 1;
+ hash = ((hash << 5) - hash) + ( unsigned ? 1 : 0 );
+ return ((hash << 5) - hash) + ( typedefUnsigned ? 1 : 0 );
+ }
+
+ @Override
+ protected boolean equalsImpl(final Type arg) {
final IntType t = (IntType) arg;
- return (super.equals(arg) && (unsigned == t.unsigned));
+ return unsigned == t.unsigned &&
+ typedefUnsigned == t.typedefUnsigned;
}
@Override
- public void setName(final String name) {
- super.setName(name);
- typedefedUnsigned = unsigned;
+ protected int hashCodeSemanticsImpl() {
+ // 31 * x == (x << 5) - x
+ int hash = 1;
+ if( !relaxedEqSem ) {
+ hash = ((hash << 5) - hash) + ( unsigned ? 1 : 0 );
+ hash = ((hash << 5) - hash) + ( typedefUnsigned ? 1 : 0 );
+ }
+ return hash;
+ }
+
+ @Override
+ protected boolean equalSemanticsImpl(final Type arg) {
+ final IntType t = (IntType) arg;
+ return relaxedEqSem ||
+ ( unsigned == t.unsigned &&
+ typedefUnsigned == t.typedefUnsigned
+ );
}
@Override
@@ -82,18 +140,27 @@ public class IntType extends PrimitiveType implements Cloneable {
return unsigned;
}
- /** Indicates whether this type is an unsigned primitive type, as opposed to a typedef type that's unsigned. */
- public boolean isPrimitiveUnsigned() {
- return unsigned && !typedefedUnsigned;
+ @Override
+ public String getCName(final boolean includeCVAttrs) {
+ if ( !unsigned || typedefUnsigned ) {
+ return super.getCName(includeCVAttrs);
+ } else {
+ return "unsigned "+super.getCName(includeCVAttrs);
+ }
}
@Override
public String toString() {
- return getCVAttributesString() + ((isUnsigned() & (!typedefedUnsigned)) ? "unsigned " : "") + getName();
+ return getCVAttributesString() + ( unsigned && !typedefUnsigned ? "unsigned " : "") + getCName();
}
@Override
- Type newCVVariant(final int cvAttributes) {
- return new IntType(getName(), getSize(), isUnsigned(), cvAttributes, typedefedUnsigned);
+ public boolean setTypedefName(final String name) {
+ if( super.setTypedefName(name) ) {
+ typedefUnsigned = unsigned;
+ return true;
+ } else {
+ return false;
+ }
}
}
diff --git a/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java b/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java
index 25d2d1d..8b06a7e 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java
@@ -27,15 +27,23 @@
*/
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
public abstract class MemoryLayoutType extends Type {
private boolean isLayouted;
- protected MemoryLayoutType(final String name, final SizeThunk size, final int cvAttributes) {
- super(name, size, cvAttributes);
+ protected MemoryLayoutType(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(name, size, cvAttributes, astLocus);
isLayouted = false;
}
+ MemoryLayoutType(final MemoryLayoutType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
+ isLayouted = o.isLayouted;
+ }
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..5707b5c 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/PointerType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/PointerType.java
@@ -39,111 +39,124 @@
*/
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
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) {
+ this(size, targetType, cvAttributes, null);
+ }
+ public PointerType(final SizeThunk size, final Type targetType, final int cvAttributes, final ASTLocusTag astLocus) {
// can pass null for the final name parameter because the PointerType's getName()
// completely replaces superclass behavior
- this(size, targetType, cvAttributes, false, null);
+ super(targetType.getName() + " *", size, cvAttributes, astLocus);
+ this.targetType = targetType;
}
- 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);
- }
+ private PointerType(final PointerType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
+ targetType = o.targetType;
}
@Override
- public int hashCode() {
- return targetType.hashCode();
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new PointerType(this, cvAttributes, astLocus);
}
@Override
- public boolean equals(final Object arg) {
- if (arg == this) {
- return true;
- }
- if (arg == null || (!(arg instanceof PointerType))) {
- return false;
- }
+ protected int hashCodeImpl() {
+ return targetType.hashCode();
+ }
+
+ @Override
+ 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
- public void setName(final String name) {
- super.setName(name);
- hasTypedefedName = true;
+ protected boolean equalSemanticsImpl(final Type arg) {
+ final PointerType pt = (PointerType) arg;
+ return targetType.equalSemantics(pt.targetType);
+ }
+
+ @Override
+ public boolean isAnon() {
+ if ( isTypedef() ) {
+ return super.isAnon();
+ } else {
+ return targetType.isAnon();
+ }
}
@Override
public String getName(final boolean includeCVAttrs) {
- if (hasTypedefedName) {
+ if ( isTypedef() ) {
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 ( isTypedef() ) {
+ return super.getCName(includeCVAttrs);
+ } else if (!includeCVAttrs) {
+ return targetType.getCName(includeCVAttrs) + " *";
+ } else {
+ return targetType.getCName(includeCVAttrs) + " * " + getCVAttributesString();
+ }
}
@Override
- public PointerType asPointer() {
+ public final PointerType asPointer() {
return this;
}
- public Type getTargetType() {
+ @Override
+ public final Type getTargetType() {
return targetType;
}
@Override
- public Type getBaseElementType() {
- /**
- if(targetType.isPointer()) {
- return ((PointerType)targetType).getBaseElementType();
- } else {
- return targetType;
- } */
+ public final Type getBaseElementType() {
return targetType.getBaseElementType();
}
@Override
- public boolean isFunctionPointer() {
+ public final boolean isFunctionPointer() {
return targetType.isFunction();
}
@Override
+ public final int pointerDepth() {
+ return 1 + targetType.pointerDepth();
+ }
+
+ @Override
public String toString() {
- if (hasTypedefedName) {
- return super.getName(true);
+ if ( isTypedef() ) {
+ 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);
}
}
@@ -162,9 +175,4 @@ public class PointerType extends Type implements Cloneable {
super.visit(arg);
targetType.visit(arg);
}
-
- @Override
- Type newCVVariant(final int cvAttributes) {
- return new PointerType(getSize(), targetType, cvAttributes, hasTypedefedName, (hasTypedefedName ? getName() : null));
- }
}
diff --git a/src/java/com/jogamp/gluegen/cgram/types/PrimitiveType.java b/src/java/com/jogamp/gluegen/cgram/types/PrimitiveType.java
index 8a86337..76f3ff1 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/PrimitiveType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/PrimitiveType.java
@@ -39,10 +39,16 @@
*/
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
public abstract class PrimitiveType extends Type implements Cloneable {
- protected PrimitiveType(final String name, final SizeThunk size, final int cvAttributes) {
- super(name, size, cvAttributes);
+ protected PrimitiveType(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(name, size, cvAttributes, astLocus);
+ }
+
+ PrimitiveType(final PrimitiveType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
}
@Override
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..fa78006 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/StructType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/StructType.java
@@ -27,34 +27,25 @@
*/
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
public class StructType extends CompoundType {
- public StructType(final String name, final SizeThunk size, final int cvAttributes) {
- this(name, size, cvAttributes, null);
+ StructType(final String name, final SizeThunk size, final int cvAttributes, final String structName, final ASTLocusTag astLocus) {
+ super (name, size, cvAttributes, structName, astLocus);
}
- StructType(final String name, final SizeThunk size, final int cvAttributes, final String structName) {
- super (name, size, cvAttributes, structName);
+ private StructType(final StructType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
}
@Override
- public boolean equals(final Object arg) {
- if (arg == null || !(arg instanceof StructType)) {
- return false;
- }
- return super.equals(arg);
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new StructType(this, cvAttributes, astLocus);
}
@Override
public final boolean isStruct() { return true; }
@Override
public final boolean isUnion() { return false; }
-
- @Override
- Type newCVVariant(final int cvAttributes) {
- final StructType t = new StructType(getName(), getSize(), cvAttributes, getStructName());
- t.setFields(getFields());
- 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..04c46af 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/Type.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/Type.java
@@ -40,46 +40,110 @@
package com.jogamp.gluegen.cgram.types;
-import java.util.List;
-
import com.jogamp.common.os.MachineDataInfo;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+import com.jogamp.gluegen.ASTLocusTag;
+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 SemanticEqualityOp, ASTLocusTagProvider {
+ public final boolean relaxedEqSem;
+ private final int cvAttributes;
+ final ASTLocusTag astLocus;
private String name;
private SizeThunk size;
- private final int cvAttributes;
- private int typedefedCVAttributes;
- private boolean hasTypedefName;
-
- protected Type(final String name, final SizeThunk size, final int cvAttributes) {
- setName(name);
+ private int typedefCVAttributes;
+ private boolean isTypedef;
+ private boolean hasCachedHash;
+ private int cachedHash;
+ private boolean hasCachedSemanticHash;
+ private int cachedSemanticHash;
+
+ protected Type(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+ setName(name); // -> clearCache()
+ this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest();
+ this.cvAttributes = cvAttributes;
+ this.astLocus = astLocus;
this.size = size;
+ this.typedefCVAttributes = 0;
+ this.isTypedef = false;
+ }
+ Type(final Type o, final int cvAttributes, final ASTLocusTag astLocus) {
+ this.relaxedEqSem = o.relaxedEqSem;
this.cvAttributes = cvAttributes;
- hasTypedefName = false;
+ this.astLocus = astLocus;
+ this.name = o.name;
+ this.size = o.size;
+ this.typedefCVAttributes = o.typedefCVAttributes;
+ this.isTypedef = o.isTypedef;
+ clearCache();
}
- @Override
- public Object clone() {
- try {
- return super.clone();
- } catch (final CloneNotSupportedException ex) {
- throw new InternalError();
+ protected final void clearCache() {
+ hasCachedHash = false;
+ cachedHash = 0;
+ hasCachedSemanticHash = false;
+ cachedSemanticHash = 0;
+ }
+
+ /**
+ * Return a variant of this type matching the given const/volatile
+ * attributes. May return this object if the attributes match.
+ */
+ public final Type newCVVariant(final int cvAttributes) {
+ if (this.cvAttributes == cvAttributes) {
+ return this;
+ } else {
+ return newVariantImpl(true, cvAttributes, astLocus);
}
}
+ /**
+ * Clones this instance using a new {@link ASTLocusTag}.
+ */
+ public Type clone(final ASTLocusTag newLoc) {
+ return newVariantImpl(true, cvAttributes, newLoc);
+ }
+
+ /**
+ * Create a new variant of this type matching the given parameter
+ * <p>
+ * Implementation <i>must</i> use {@link Type}'s copy-ctor: {@link #Type(Type, int, ASTLocusTag)}!
+ * </p>
+ * @param newCVVariant true if new variant is intended to have new <i>cvAttributes</i>
+ * @param cvAttributes the <i>cvAttributes</i> to be used
+ * @param astLocus the {@link ASTLocusTag} to be used
+ */
+ abstract Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus);
+
+ @Override
+ public final ASTLocusTag getASTLocusTag() { return astLocus; }
+
+ public boolean isAnon() { return null == name; }
+
/** 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 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 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,26 +151,53 @@ public abstract class Type implements Cloneable {
return getCVAttributesString() + name;
}
- private void append(final StringBuilder sb, final String val, final boolean prepComma) {
+ /**
+ * 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 static StringBuilder append(final StringBuilder sb, final String val, final boolean prepComma) {
if( prepComma ) {
sb.append(", ");
}
sb.append(val);
+ return sb;
}
// For debugging
- public String getDebugString() {
+ public final String getDebugString() {
final StringBuilder sb = new StringBuilder();
boolean prepComma = false;
sb.append("CType[");
+ sb.append("(").append(getClass().getSimpleName()).append(") ");
+ if( isTypedef() ) {
+ 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");
+ }
+ 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( hasTypedefName() ) {
- sb.append(" (typedef)");
+ if( GlueGen.debug() ) {
+ sb.append(", o=0x"+Integer.toHexString(objHash()));
}
- append(sb, "size ", prepComma); prepComma=true;
+ sb.append(", size ");
+ prepComma=true;
if( null != size ) {
final long mdSize;
{
@@ -121,67 +212,135 @@ public abstract class Type implements Cloneable {
sb.append(" ZERO");
}
append(sb, "[", prepComma); prepComma=false;
- if( isConst() ) {
- append(sb, "const ", false);
- }
- if( isVolatile() ) {
- append(sb, "volatile ", false);
- }
- if( isPointer() ) {
- append(sb, "pointer*"+pointerDepth(), prepComma); prepComma=true;
- }
- if( isArray() ) {
- append(sb, "array*"+arrayDimension(), prepComma); prepComma=true;
- }
- if( isBit() ) {
- append(sb, "bit", prepComma); prepComma=true;
- }
- if( isCompound() ) {
- sb.append("struct{").append(asCompound().getNumFields());
- append(sb, "}", prepComma); prepComma=true;
- }
- if( isDouble() ) {
- append(sb, "double", prepComma); prepComma=true;
- }
- if( isEnum() ) {
- append(sb, "enum", prepComma); prepComma=true;
- }
- if( isFloat() ) {
- append(sb, "float", prepComma); prepComma=true;
- }
- if( isFunction() ) {
- append(sb, "function", prepComma); prepComma=true;
- }
- if( isFunctionPointer() ) {
- append(sb, "funcPointer", prepComma); prepComma=true;
- }
- if( isInt() ) {
- append(sb, "int", prepComma); prepComma=true;
- }
- if( isVoid() ) {
- append(sb, "void", prepComma); prepComma=true;
+ {
+ append(sb, "const[", prepComma); prepComma=false;
+ {
+ if( isConstTypedef() ) {
+ append(sb, "type ", prepComma); prepComma=true;
+ }
+ if( isConstRaw() ) {
+ append(sb, "inst -> ", prepComma); prepComma=false;
+ }
+ if( isConst() ) {
+ append(sb, "true]", prepComma);
+ } else {
+ append(sb, "false]", prepComma);
+ }
+ prepComma=true;
+ }
+ if( isVolatile() ) {
+ append(sb, "volatile ", prepComma); prepComma=true;
+ }
+ if( isPointer() ) {
+ append(sb, "pointer*"+pointerDepth(), prepComma); prepComma=true;
+ }
+ if( isArray() ) {
+ append(sb, "array*"+arrayDimension(), prepComma); prepComma=true;
+ }
+ if( isBit() ) {
+ append(sb, "bit", prepComma); prepComma=true;
+ }
+ if( isCompound() ) {
+ append(sb, "struct{", prepComma).append(asCompound().getStructName()).append(": ").append(asCompound().getNumFields());
+ append(sb, "}", prepComma); prepComma=true;
+ }
+ if( isDouble() ) {
+ append(sb, "double", prepComma); prepComma=true;
+ }
+ if( isEnum() ) {
+ final EnumType eT = asEnum();
+ append(sb, "enum ", prepComma).append(" [").append(eT.getUnderlyingType()).append("] {").append(eT.getNumEnumerates()).append(": ");
+ eT.appendEnums(sb, false);
+ prepComma=true;
+ }
+ if( isFloat() ) {
+ append(sb, "float", prepComma); prepComma=true;
+ }
+ if( isFunction() ) {
+ append(sb, "function", prepComma); prepComma=true;
+ }
+ if( isFunctionPointer() ) {
+ append(sb, "funcPointer", prepComma); prepComma=true;
+ }
+ if( isInt() ) {
+ append(sb, "int", prepComma); prepComma=true;
+ }
+ if( isVoid() ) {
+ append(sb, "void", prepComma); prepComma=true;
+ }
+ sb.append("]");
}
- sb.append("]]");
+ 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) {
- if (name == null) {
+ /**
+ * Returns {@code true} if given {@code name} is not {@code null}
+ * and has a length &gt; 0. In this case this instance's names will
+ * be set to the internalized version.
+ * <p>
+ * Otherwise method returns {@code false}
+ * and this instance's name will be set to {@code null}.
+ * </p>
+ * <p>
+ * Method issues {@link #clearCache()}, to force re-evaluation
+ * of hashes.
+ * </p>
+ */
+ private final boolean setName(final String name) {
+ clearCache();
+ if( null == name || 0 == name.length() ) {
this.name = name;
+ return false;
} else {
this.name = name.intern();
+ return true;
+ }
+ }
+
+ /**
+ * Set the typedef name of this type and renders this type a typedef,
+ * if given {@code name} has a length.
+ * <p>
+ * Method issues {@link #clearCache()}, to force re-evaluation
+ * of hashes.
+ * </p>
+ */
+ public boolean setTypedefName(final String name) {
+ if( setName(name) ) {
+ // Capture the const/volatile attributes at the time of typedef so
+ // we don't redundantly repeat them in the CV attributes string
+ typedefCVAttributes = cvAttributes;
+ isTypedef = true;
+ return true;
+ } else {
+ return false;
}
- // 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;
+ }
+ final void setTypedef(final int typedefedCVAttributes) {
+ this.name = this.name.intern(); // just make sure ..
+ this.typedefCVAttributes = typedefedCVAttributes;
+ this.isTypedef = true;
+ clearCache();
+ }
+ final int getTypedefCVAttributes() {
+ return typedefCVAttributes;
+ }
+
+ /**
+ * Indicates whether this type is a typedef type,
+ * i.e. declared via {@link #setTypedefName(String)}.
+ */
+ public final boolean isTypedef() {
+ return isTypedef;
}
/** SizeThunk which computes size of this type in bytes. */
- public SizeThunk getSize() { return size; }
+ public final SizeThunk getSize() { return size; }
/** Size of this type in bytes according to the given MachineDataInfo. */
- public long getSize(final MachineDataInfo machDesc) {
+ public final long getSize(final MachineDataInfo machDesc) {
final SizeThunk thunk = getSize();
if (thunk == null) {
throw new RuntimeException("No size set for type \"" + getName() + "\"");
@@ -189,7 +348,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; }
+ final 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; }
@@ -213,82 +375,153 @@ public abstract class Type implements Cloneable {
public VoidType asVoid() { return null; }
/** Indicates whether this is a BitType. */
- public boolean isBit() { return (asBit() != null); }
+ public final boolean isBit() { return (asBit() != null); }
/** Indicates whether this is an IntType. */
- public boolean isInt() { return (asInt() != null); }
+ public final boolean isInt() { return (asInt() != null); }
/** Indicates whether this is an EnumType. */
- public boolean isEnum() { return (asEnum() != null); }
+ public final boolean isEnum() { return (asEnum() != null); }
/** Indicates whether this is a FloatType. */
- public boolean isFloat() { return (asFloat() != null); }
+ public final boolean isFloat() { return (asFloat() != null); }
/** Indicates whether this is a DoubleType. */
- public boolean isDouble() { return (asDouble() != null); }
+ public final boolean isDouble() { return (asDouble() != null); }
/** Indicates whether this is a PointerType. */
- public boolean isPointer() { return (asPointer() != null); }
+ public final boolean isPointer() { return (asPointer() != null); }
/** Indicates whether this is an ArrayType. */
- public boolean isArray() { return (asArray() != null); }
+ public final boolean isArray() { return (asArray() != null); }
/** Indicates whether this is a CompoundType. */
- public boolean isCompound() { return (asCompound() != null); }
+ public final boolean isCompound() { return (asCompound() != null); }
/** Indicates whether this is a FunctionType. */
- public boolean isFunction() { return (asFunction() != null); }
+ public final boolean isFunction() { return (asFunction() != null); }
/** Indicates whether this is a VoidType. */
- public boolean isVoid() { return (asVoid() != null); }
+ public final boolean isVoid() { return (asVoid() != null); }
- /** Indicates whether this type is const. */
- public boolean isConst() { return (((cvAttributes & ~typedefedCVAttributes) & CVAttributes.CONST) != 0); }
/** Indicates whether this type is volatile. */
- public boolean isVolatile() { return (((cvAttributes & ~typedefedCVAttributes) & CVAttributes.VOLATILE) != 0); }
+ public final boolean isVolatile() { return 0 != ( ( cvAttributes & ~typedefCVAttributes ) & CVAttributes.VOLATILE ); }
+ /** Indicates whether this type is const. */
+ public final boolean isConst() { return 0 != ( ( cvAttributes & ~typedefCVAttributes ) & CVAttributes.CONST ); }
+
+ private final boolean isConstTypedef() { return 0 != ( typedefCVAttributes & CVAttributes.CONST ); }
+ private final boolean isConstRaw() { return 0 != ( cvAttributes & CVAttributes.CONST ); }
/** Indicates whether this type is a primitive type. */
- public boolean isPrimitive(){ return false; }
+ public boolean isPrimitive(){ return false; }
/** Convenience routine indicating whether this Type is a pointer to
a function. */
public boolean isFunctionPointer() {
- return (isPointer() && asPointer().getTargetType().isFunction());
+ return false;
+ }
+
+ /**
+ * Checks the base type of pointer-to-pointer, pointer, array or plain for const-ness.
+ * <p>
+ * Note: Intermediate 'const' qualifier are not considered, e.g. const pointer.
+ * </p>
+ */
+ public final boolean isBaseTypeConst() {
+ return getBaseElementType().isConst();
}
/** 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 + ( isTypedef ? 1 : 0 );
+ hash = ((hash << 5) - hash) + ( null != size ? size.hashCode() : 0 );
+ hash = ((hash << 5) - hash) + cvAttributes;
+ hash = ((hash << 5) - hash) + typedefCVAttributes;
+ hash = ((hash << 5) - hash) + ( null != name ? name.hashCode() : 0 );
+ if( !isTypedef ) {
+ 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( isTypedef == t.isTypedef &&
+ ( ( null != size && size.equals(t.size) ) ||
+ ( null == size && null == t.size )
+ ) &&
+ cvAttributes == t.cvAttributes &&
+ typedefCVAttributes == t.typedefCVAttributes &&
+ ( null == name ? null == t.name : name.equals(t.name) )
+ )
+ {
+ if( !isTypedef ) {
+ 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) + typedefCVAttributes;
+ }
+ 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 &&
+ typedefCVAttributes == t.typedefCVAttributes
+ )
+ )
+ )
+ {
+ 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. */
+ /**
+ * Traverse this {@link Type} and all of its component types; for
+ * example, the return type and argument types of a FunctionType.
+ */
public void visit(final TypeVisitor visitor) {
visitor.visitType(this);
}
@@ -306,45 +539,18 @@ public abstract class Type implements Cloneable {
return "";
}
- /** Return a variant of this type matching the given const/volatile
- attributes. May return this object if the attributes match. */
- public final Type getCVVariant(final int cvAttributes) {
- if (this.cvAttributes == cvAttributes) {
- return this;
- }
- return newCVVariant(cvAttributes);
- }
-
- /** Create a new variant of this type matching the given
- 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. */
public int pointerDepth() {
- final PointerType pt = asPointer();
- if (pt == null) {
- return 0;
- }
- return 1 + pt.getTargetType().pointerDepth();
+ return 0;
}
/** Helper method for determining how many array dimentions this
type represents (i.e., "char[][]" returns 2). Returns 0 if this
type is not an array type. */
public int arrayDimension() {
- final ArrayType arrayType = asArray();
- if (arrayType == null) {
- return 0;
- }
- return 1 + arrayType.getElementType().arrayDimension();
+ return 0;
}
/**
@@ -358,8 +564,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/TypeVisitor.java b/src/java/com/jogamp/gluegen/cgram/types/TypeVisitor.java
index 89c014b..ed5cfa9 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/TypeVisitor.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/TypeVisitor.java
@@ -39,6 +39,12 @@
package com.jogamp.gluegen.cgram.types;
+/**
+ * A visitor for {@link Type}'s visitor model.
+ */
public interface TypeVisitor {
+ /**
+ * Visiting the given {@link Type}.
+ */
public void visitType(Type t);
}
diff --git a/src/java/com/jogamp/gluegen/cgram/types/UnionType.java b/src/java/com/jogamp/gluegen/cgram/types/UnionType.java
index 99d2fed..8c6d9dd 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/UnionType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/UnionType.java
@@ -27,34 +27,25 @@
*/
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
public class UnionType extends CompoundType {
- public UnionType(final String name, final SizeThunk size, final int cvAttributes) {
- this(name, size, cvAttributes, null);
+ UnionType(final String name, final SizeThunk size, final int cvAttributes, final String structName, final ASTLocusTag astLocus) {
+ super (name, size, cvAttributes, structName, astLocus);
}
- UnionType(final String name, final SizeThunk size, final int cvAttributes, final String structName) {
- super (name, size, cvAttributes, structName);
+ private UnionType(final UnionType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
}
@Override
- public boolean equals(final Object arg) {
- if (arg == null || !(arg instanceof UnionType)) {
- return false;
- }
- return super.equals(arg);
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new UnionType(this, cvAttributes, astLocus);
}
@Override
public final boolean isStruct() { return false; }
@Override
public final boolean isUnion() { return true; }
-
- @Override
- Type newCVVariant(final int cvAttributes) {
- final UnionType t = new UnionType(getName(), getSize(), cvAttributes, getStructName());
- t.setFields(getFields());
- 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..bf51523 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/VoidType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/VoidType.java
@@ -39,14 +39,25 @@
*/
package com.jogamp.gluegen.cgram.types;
+import com.jogamp.gluegen.ASTLocusTag;
+
public class VoidType extends Type implements Cloneable {
- public VoidType(final int cvAttributes) {
- this("void", cvAttributes);
+ public VoidType(final int cvAttributes, final ASTLocusTag astLocus) {
+ this("void", cvAttributes, astLocus);
+ }
+
+ private VoidType(final String name, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(name, null, cvAttributes, astLocus);
+ }
+
+ private VoidType(final VoidType o, final int cvAttributes, final ASTLocusTag astLocus) {
+ super(o, cvAttributes, astLocus);
}
- private VoidType(final String name, final int cvAttributes) {
- super(name, null, cvAttributes);
+ @Override
+ Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+ return new VoidType(this, cvAttributes, astLocus);
}
@Override
@@ -55,7 +66,22 @@ public class VoidType extends Type implements Cloneable {
}
@Override
- Type newCVVariant(final int cvAttributes) {
- return new VoidType(getName(), cvAttributes);
+ 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..c766634 100644
--- a/src/java/com/jogamp/gluegen/pcpp/PCPP.java
+++ b/src/java/com/jogamp/gluegen/pcpp/PCPP.java
@@ -56,16 +56,24 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.logging.Logger;
+import java.util.logging.Level;
+
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ConstantDefinition;
+import com.jogamp.gluegen.GenericCPP;
+import com.jogamp.gluegen.GlueGenException;
+import com.jogamp.gluegen.Logging;
+import com.jogamp.gluegen.Logging.LoggerIf;
+
import static java.util.logging.Level.*;
/** A minimal pseudo-C-preprocessor designed in particular to preserve
#define statements defining constants so they can be observed by a
glue code generator. */
-public class PCPP {
+public class PCPP implements GenericCPP {
- private static final Logger LOG = Logger.getLogger(PCPP.class.getPackage().getName());
+ private final LoggerIf LOG;
/** Map containing the results of #define statements. We must
evaluate certain very simple definitions (to properly handle
@@ -86,13 +94,15 @@ 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(), PCPP.class.getSimpleName());
this.includePaths = includePaths;
setOut(System.out);
enableDebugPrint = debug;
enableCopyOutput2Stderr = copyOutput2Stderr;
}
- public void run(final Reader reader, final String filename) throws IOException {
+ @Override
+ public void run(final Reader reader, final String filename) throws GlueGenException {
StreamTokenizer tok = null;
BufferedReader bufReader = null;
if (reader instanceof BufferedReader) {
@@ -108,13 +118,29 @@ public class PCPP {
final ParseState oldState = state;
state = curState;
lineDirective();
- parse();
+ try {
+ parse();
+ } catch (final Exception e) {
+ final StringBuilder buf = new StringBuilder("Preprocessor failed");
+ LOG.log(Level.SEVERE, buf.toString(), e);
+ if( e instanceof GlueGenException ) {
+ throw (GlueGenException)e;
+ } else {
+ throw new GlueGenException("Preprocessor failed",
+ new ASTLocusTag(filename(), lineNumber(), -1, null), e);
+ }
+ }
state = oldState;
if (state != null) {
lineDirective();
}
}
+ @Override
+ public List<ConstantDefinition> getConstantDefinitions() throws GlueGenException {
+ return new ArrayList<ConstantDefinition>(); // NOP
+ }
+
private void initTokenizer(final StreamTokenizer tok) {
tok.resetSyntax();
tok.wordChars('a', 'z');
@@ -131,6 +157,7 @@ public class PCPP {
tok.slashStarComments(true);
}
+ @Override
public String findFile(final String filename) {
final String sep = File.separator;
for (final String inclPath : includePaths) {
@@ -143,10 +170,12 @@ public class PCPP {
return null;
}
+ @Override
public OutputStream out() {
return out;
}
+ @Override
public void setOut(final OutputStream out) {
this.out = out;
writer = new PrintWriter(out);
@@ -375,7 +404,7 @@ public class PCPP {
}
}
- if(isIdentifier(value)) {
+ if(ConstantDefinition.isIdentifier(value)) {
newS +=" ";
}
@@ -459,28 +488,30 @@ public class PCPP {
if (enabled()) {
final String oldDef = defineMap.remove(name);
if (oldDef == null) {
- LOG.log(WARNING, "ignoring redundant \"#undef {0}\", at \"{1}\" line {2}: \"{3}\" was not previously defined",
- new Object[]{name, filename(), lineNumber(), name});
+ LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, name),
+ "ignoring redundant \"#undef {0}\" - was not previously defined",
+ name);
} else {
// System.err.println("UNDEFINED: '" + name + "' (line " + lineNumber() + " file " + filename() + ")");
}
nonConstantDefines.remove(name);
} else {
- LOG.log(WARNING, "FAILED TO UNDEFINE: ''{0}'' (line {1} file {2})", new Object[]{name, lineNumber(), filename()});
+ LOG.log(INFO, new ASTLocusTag(filename(), lineNumber(), -1, name),
+ "DISABLED UNDEFINE: ''{0}''", name);
}
}
private void handleWarning() throws IOException {
final String msg = nextWordOrString();
if (enabled()) {
- LOG.log(WARNING, "#warning {0} at \"{1}\" line \"{2}\"", new Object[]{msg, filename(), lineNumber()});
+ LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null), msg);
}
}
- private void handleError() throws IOException {
+ private void handleError() throws IOException, GlueGenException {
final String msg = nextWordOrString();
if (enabled()) {
- throw new RuntimeException("#error "+msg+" at \""+filename()+"\" line "+lineNumber());
+ throw new GlueGenException(msg, new ASTLocusTag(filename(), lineNumber(), -1, null));
}
}
@@ -520,6 +551,7 @@ public class PCPP {
addDefine(name, macroDefinition, values);
}
+ @Override
public void addDefine(final String name, final String value) {
final List<String> values = new ArrayList<String>();
values.add(value);
@@ -541,7 +573,8 @@ public class PCPP {
final String value = "";
final String oldDef = defineMap.put(name, value);
if (oldDef != null && !oldDef.equals(value)) {
- LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"\"", new Object[]{name, oldDef});
+ LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null),
+ "\"{0}\" redefined from \"{1}\" to \"\"", name, oldDef);
}
// We don't want to emit the define, because it would serve no purpose
// and cause GlueGen errors (confuse the GnuCParser)
@@ -551,12 +584,13 @@ public class PCPP {
// See whether the value is a constant
final String value = values.get(0);
- if (isConstant(value)) {
+ if (ConstantDefinition.isNumber(value)) {
// Value is numeric constant like "#define FOO 5".
// Put it in the #define map
final String oldDef = defineMap.put(name, value);
if (oldDef != null && !oldDef.equals(value)) {
- LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"{2}\"", new Object[]{name, oldDef, value});
+ LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null),
+ "\"{0}\" redefined from \"{1}\" to \"{2}\"", name, oldDef, value);
}
debugPrint(true, "DEFINE " + name + " ["+oldDef+" ] -> "+value + " CONST");
//System.err.println("//---DEFINED: " + name + " to \"" + value + "\"");
@@ -606,7 +640,8 @@ public class PCPP {
final Macro macro = new Macro(params, values);
final Macro oldDef = macroMap.put(name, macro);
if (oldDef != null) {
- LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"{2}\"", new Object[]{name, oldDef, macro});
+ LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null),
+ "\"{0}\" redefined from \"{1}\" to \"{2}\"", name, oldDef, macro);
}
emitDefine = false;
@@ -618,7 +653,7 @@ public class PCPP {
boolean containsIdentifier = false;
for (final String value : values) {
- if(isIdentifier(value)) {
+ if(ConstantDefinition.isIdentifier(value)) {
containsIdentifier = true;
break;
}
@@ -657,7 +692,8 @@ public class PCPP {
final String oldDef = defineMap.put(name, value);
if (oldDef != null && !oldDef.equals(value)) {
- LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"{2}\"", new Object[]{name, oldDef, value});
+ LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null),
+ "\"{0}\" redefined from \"{1}\" to \"{2}\"", name, oldDef, value);
}
debugPrint(true, "DEFINE " + name + " ["+oldDef+" ] -> "+value + " CONST");
// System.err.println("#define " + name +" "+value + " CONST EXPRESSION");
@@ -681,68 +717,6 @@ public class PCPP {
//System.err.println("OUT HANDLE_DEFINE: " + name);
}
- private boolean isIdentifier(final String value) {
-
- boolean identifier = false;
-
- final char[] chars = value.toCharArray();
-
- for (int i = 0; i < chars.length; i++) {
- final char c = chars[i];
- if (i == 0) {
- if (Character.isJavaIdentifierStart(c)) {
- identifier = true;
- }
- } else {
- if (!Character.isJavaIdentifierPart(c)) {
- identifier = false;
- break;
- }
- }
- }
- return identifier;
- }
-
- private boolean isConstant(final String s) {
- if (s.startsWith("0x") || s.startsWith("0X")) {
- return checkHex(s);
- } else {
- return checkDecimal(s);
- }
- }
-
- private boolean checkHex(final String s) {
- char c='\0';
- int i;
- for (i = 2; i < s.length(); i++) {
- c = s.charAt(i);
- if (!((c >= '0' && c <= '9') ||
- (c >= 'a' && c <= 'f') ||
- (c >= 'A' && c <= 'F'))) {
- break;
- }
- }
- if(i==s.length()) {
- return true;
- } else if(i==s.length()-1) {
- // Const qualifier ..
- return c == 'l' || c == 'L' ||
- c == 'f' || c == 'F' ||
- c == 'u' || c == 'U' ;
- }
- return false;
- }
-
- private boolean checkDecimal(final String s) {
- try {
- Float.valueOf(s);
- } catch (final NumberFormatException e) {
- // not parsable as a number
- return false;
- }
- return true;
- }
-
private String resolveDefine(final String word, final boolean returnNullIfNotFound) {
String lastWord = defineMap.get(word);
if (lastWord == null) {
@@ -920,6 +894,27 @@ public class PCPP {
ifValue = false;
}
break;
+ case '*':
+ {
+ // NOTE: we don't handle expressions like this properly
+ final boolean rhs = handleIfRecursive(false);
+ ifValue = false;
+ }
+ break;
+ case '+':
+ {
+ // NOTE: we don't handle expressions like this properly
+ final boolean rhs = handleIfRecursive(false);
+ ifValue = false;
+ }
+ break;
+ case '-':
+ {
+ // NOTE: we don't handle expressions like this properly
+ final boolean rhs = handleIfRecursive(false);
+ ifValue = false;
+ }
+ break;
case '=':
{
// NOTE: we don't handle expressions like this properly
@@ -1008,7 +1003,8 @@ public class PCPP {
buf.append(curTokenAsString());
}
if (t == StreamTokenizer.TT_EOF) {
- LOG.warning("unexpected EOF while processing #include directive");
+ LOG.warning(new ASTLocusTag(filename(), lineNumber(), -1, null),
+ "unexpected EOF while processing #include directive");
}
filename = buf.toString();
}
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
index 5c059c9..37a39e1 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
@@ -42,30 +42,35 @@ 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 {
private boolean callThroughProcAddress;
- private boolean needsLocalTypedef;
+ private boolean hasProcAddrTypedef;
private String localTypedefCallingConvention;
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 hasProcAddrTypedef,
+ final String localTypedefCallingConvention,
+ final ProcAddressEmitter emitter) {
super(
new MethodBinding(methodToWrap.getBinding()) {
@Override
- public String getName() {
+ public String getImplName() {
if (callThroughProcAddress) {
- return ProcAddressEmitter.WRAP_PREFIX + super.getName();
+ return ProcAddressEmitter.WRAP_PREFIX + super.getImplName();
} else {
- return super.getName();
+ return super.getImplName();
}
}
},
@@ -76,9 +81,9 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
methodToWrap.getIsJavaMethodStatic(),
true,
methodToWrap.forIndirectBufferAndArrayImplementation(),
- methodToWrap.getMachineDataInfo()
+ methodToWrap.getMachineDataInfo(),
+ emitter.getConfiguration()
);
-
if (methodToWrap.getReturnValueCapacityExpression() != null) {
setReturnValueCapacityExpression(methodToWrap.getReturnValueCapacityExpression());
}
@@ -91,7 +96,7 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
setCommentEmitter(defaultCommentEmitter);
this.callThroughProcAddress = callThroughProcAddress;
- this.needsLocalTypedef = needsLocalTypedef;
+ this.hasProcAddrTypedef = hasProcAddrTypedef;
this.localTypedefCallingConvention = localTypedefCallingConvention;
this.emitter = emitter;
}
@@ -116,28 +121,31 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
if (callThroughProcAddress) {
// create variable for the function pointer with the right type, and set
// it to the value of the passed-in proc address
- final FunctionSymbol cSym = getBinding().getCSymbol();
- String funcPointerTypedefName =
- emitter.getFunctionPointerTypedefName(cSym);
-
- if (needsLocalTypedef) {
- // 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);
- // Just for safety, emit this name slightly differently than
- // the mangling would otherwise produce
- funcPointerTypedefName = "_local_" + funcPointerTypedefName;
-
- writer.print(" typedef ");
- writer.print(funcPtrType.toString(funcPointerTypedefName, localTypedefCallingConvention));
- writer.println(";");
+ final FunctionSymbol cSym = binding.getCSymbol();
+
+ // Always emit the local typedef, based on our parsing results.
+ // In case we do have the public typedef from the original header,
+ // we use it for the local var and assign our proc-handle to it,
+ // cast to the local typedef.
+ // This allows the native C compiler to validate our types!
+ final String funcPointerTypedefBaseName = emitter.getFunctionPointerTypedefName(cSym);
+ final String funcPointerTypedefLocalName = "_local_" + funcPointerTypedefBaseName;
+ final String funcPointerTypedefName;
+ if (hasProcAddrTypedef) {
+ funcPointerTypedefName = funcPointerTypedefBaseName;
+ } else {
+ funcPointerTypedefName = funcPointerTypedefLocalName;
}
+ final PointerType funcPtrType = new PointerType(null, cSym.getType(), 0);
+
+ writer.print(" typedef ");
+ writer.print(funcPtrType.toString(funcPointerTypedefLocalName, localTypedefCallingConvention));
+ writer.println(";");
writer.print(" ");
- writer.print(funcPointerTypedefName);
+ writer.print(funcPointerTypedefName); // Uses public typedef if available!
writer.print(" ptr_");
- writer.print(cSym.getName());
+ writer.print(getNativeName());
writer.println(";");
}
@@ -150,18 +158,25 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
if (callThroughProcAddress) {
// set the function pointer to the value of the passed-in procAddress
- final FunctionSymbol cSym = getBinding().getCSymbol();
- String funcPointerTypedefName = emitter.getFunctionPointerTypedefName(cSym);
- if (needsLocalTypedef) {
- funcPointerTypedefName = "_local_" + funcPointerTypedefName;
+ // See above notes in emitBodyVariableDeclarations(..)!
+ final String funcPointerTypedefBaseName = emitter.getFunctionPointerTypedefName(binding.getCSymbol());
+ final String funcPointerTypedefLocalName = "_local_" + funcPointerTypedefBaseName;
+ final String funcPointerTypedefName;
+ if (hasProcAddrTypedef) {
+ funcPointerTypedefName = funcPointerTypedefBaseName;
+ } else {
+ funcPointerTypedefName = funcPointerTypedefLocalName;
}
- final String ptrVarName = "ptr_" + cSym.getName();
+ final String ptrVarName = "ptr_" + getNativeName();
+ if (hasProcAddrTypedef) {
+ writer.println(" // implicit type validation of "+funcPointerTypedefLocalName+" -> "+funcPointerTypedefName);
+ }
writer.print(" ");
writer.print(ptrVarName);
writer.print(" = (");
- writer.print(funcPointerTypedefName);
+ writer.print(funcPointerTypedefLocalName);
writer.println(") (intptr_t) procAddress;");
writer.println(" assert(" + ptrVarName + " != NULL);");
@@ -181,7 +196,12 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
final Type cReturnType = binding.getCReturnType();
if (!cReturnType.isVoid()) {
- writer.print("_res = ");
+ // Note we respect const/volatile in the function return type.
+ // However, we cannot have it 'const' for our local variable.
+ // See return type in CMethodBindingEmitter.emitBodyVariableDeclarations(..)!
+ writer.print("_res = (");
+ writer.print(cReturnType.getCName(false));
+ writer.print(") ");
}
final MethodBinding mBinding = getBinding();
if (mBinding.hasContainingType()) {
@@ -192,7 +212,7 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
// call throught the run-time function pointer
writer.print("(* ptr_");
- writer.print(mBinding.getCSymbol().getName());
+ writer.print(getNativeName());
writer.print(") ");
writer.print("(");
emitBodyPassCArguments(writer);
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java
index 0c5692b..36d433a 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java
@@ -38,7 +38,12 @@
*/
package com.jogamp.gluegen.procaddress;
+import static java.util.logging.Level.INFO;
+
import com.jogamp.gluegen.JavaConfiguration;
+import com.jogamp.gluegen.cgram.types.AliasedSymbol;
+import com.jogamp.gluegen.cgram.types.FunctionSymbol;
+
import java.io.*;
import java.text.*;
import java.util.*;
@@ -269,8 +274,15 @@ public class ProcAddressConfiguration extends JavaConfiguration {
return tableClassName;
}
- public boolean skipProcAddressGen(final String name) {
- return skipProcAddressGen.contains(name);
+ public boolean skipProcAddressGen(final FunctionSymbol symbol) {
+ if ( skipProcAddressGen.contains( symbol.getName() ) ||
+ oneInSet(skipProcAddressGen, symbol.getAliasedNames())
+ )
+ {
+ LOG.log(INFO, symbol.getASTLocusTag(), "Skip ProcAddress: {0}", symbol);
+ return true;
+ }
+ return false;
}
public boolean isForceProcAddressGen4All() {
@@ -298,9 +310,25 @@ public class ProcAddressConfiguration extends JavaConfiguration {
return procAddressNameConverter.convert(funcName);
}
- public boolean forceProcAddressGen(final String funcName) {
- return forceProcAddressGen4All || forceProcAddressGenSet.contains(funcName);
+ public boolean forceProcAddressGen(final FunctionSymbol symbol) {
+ if( forceProcAddressGen4All ) {
+ if(!forceProcAddressGen4AllOnce) {
+ forceProcAddressGen4AllOnce = true;
+ LOG.log(INFO, symbol.getASTLocusTag(), "Force ALL ProcAddress");
+ }
+ return true;
+ }
+
+ if ( forceProcAddressGenSet.contains( symbol.getName() ) ||
+ oneInSet(forceProcAddressGenSet, symbol.getAliasedNames())
+ )
+ {
+ LOG.log(INFO, symbol.getASTLocusTag(), "Force ProcAddress: {0}", symbol);
+ return true;
+ }
+ return false;
}
+ private static boolean forceProcAddressGen4AllOnce = false;
public void addForceProcAddressGen(final String funcName) {
forceProcAddressGen.add(funcName);
@@ -311,11 +339,15 @@ public class ProcAddressConfiguration extends JavaConfiguration {
localProcAddressCallingConventionMap.put(funcName, callingConvention);
}
- public String getLocalProcAddressCallingConvention(final String funcName) {
- if (isLocalProcAddressCallingConvention4All()) {
+ public String getLocalProcAddressCallingConvention(final FunctionSymbol symbol) {
+ if ( isLocalProcAddressCallingConvention4All() ) {
return getLocalProcAddressCallingConvention4All();
}
- return localProcAddressCallingConventionMap.get(funcName);
+ final String res = localProcAddressCallingConventionMap.get(symbol.getName());
+ if( null != res ) {
+ return res;
+ }
+ return oneInMap(localProcAddressCallingConventionMap, symbol.getAliasedNames());
}
public boolean isLocalProcAddressCallingConvention4All() {
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java
index 4145cc4..ec29b08 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java
@@ -47,6 +47,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.logging.Level;
import com.jogamp.gluegen.CMethodBindingEmitter;
import com.jogamp.gluegen.CodeGenUtils;
@@ -54,7 +55,6 @@ import com.jogamp.gluegen.FunctionEmitter;
import com.jogamp.gluegen.JavaConfiguration;
import com.jogamp.gluegen.JavaEmitter;
import com.jogamp.gluegen.JavaMethodBindingEmitter;
-import com.jogamp.gluegen.MethodBinding;
import com.jogamp.gluegen.cgram.types.FunctionSymbol;
import com.jogamp.gluegen.cgram.types.Type;
import com.jogamp.gluegen.cgram.types.TypeDictionary;
@@ -114,40 +114,45 @@ public class ProcAddressEmitter extends JavaEmitter {
}
@Override
- protected List<? extends FunctionEmitter> generateMethodBindingEmitters(final Set<MethodBinding> methodBindingSet, final FunctionSymbol sym) throws Exception {
- return generateMethodBindingEmittersImpl(methodBindingSet, sym);
+ protected List<? extends FunctionEmitter> generateMethodBindingEmitters(final FunctionSymbol sym) throws Exception {
+ return generateMethodBindingEmittersImpl(sym);
}
protected boolean needsModifiedEmitters(final FunctionSymbol sym) {
- if (!needsProcAddressWrapper(sym) || getConfig().isUnimplemented(getAliasedSymName(sym))) {
+ if ( !callThroughProcAddress(sym) || getConfig().isUnimplemented(sym) ) {
return false;
+ } else {
+ return true;
}
-
- return true;
}
- private List<? extends FunctionEmitter> generateMethodBindingEmittersImpl(final Set<MethodBinding> methodBindingSet, final FunctionSymbol sym) throws Exception {
- final List<? extends FunctionEmitter> defaultEmitters = super.generateMethodBindingEmitters(methodBindingSet, sym);
+ private List<? extends FunctionEmitter> generateMethodBindingEmittersImpl(final FunctionSymbol sym) throws Exception {
+ final List<? extends FunctionEmitter> defaultEmitters = super.generateMethodBindingEmitters(sym);
// if the superclass didn't generate any bindings for the symbol, let's
// honor that (for example, the superclass might have caught an Ignore
// direction that matched the symbol's name).
if (defaultEmitters.isEmpty()) {
+ LOG.log(Level.INFO, sym.getASTLocusTag(), "genModProcAddrEmitter: SKIP, empty binding set: {0}", sym);
return defaultEmitters;
}
- // Don't do anything special if this symbol doesn't require
- // modifications
- if (!needsModifiedEmitters(sym)) {
+ final boolean callThroughProcAddress = callThroughProcAddress(sym);
+ final boolean isUnimplemented = getConfig().isUnimplemented(sym);
+
+ // Don't do anything special if this symbol doesn't require modifications
+ if( !callThroughProcAddress || isUnimplemented ) {
+ LOG.log(Level.INFO, sym.getASTLocusTag(), "genModProcAddrEmitter: SKIP, not needed: callThrough {0}, isUnimplemented {1}: {2}",
+ callThroughProcAddress, isUnimplemented, sym);
return defaultEmitters;
}
final ArrayList<FunctionEmitter> modifiedEmitters = new ArrayList<FunctionEmitter>(defaultEmitters.size());
- if (needsProcAddressWrapper(sym)) {
+ if ( callThroughProcAddress ) {
if (getProcAddressConfig().emitProcAddressTable()) {
// emit an entry in the GL proc address table for this method.
- emitProcAddressTableEntryForString(getAliasedSymName(sym));
+ emitProcAddressTableEntryForString(sym.getName());
}
}
for (final FunctionEmitter emitter : defaultEmitters) {
@@ -172,7 +177,7 @@ public class ProcAddressEmitter extends JavaEmitter {
* whether or not the typedef is actually defined.
*/
protected String getFunctionPointerTypedefName(final FunctionSymbol sym) {
- return getProcAddressConfig().convertToFunctionPointerName(sym.getName());
+ return getProcAddressConfig().convertToFunctionPointerName(sym.getOrigName());
}
//----------------------------------------------------------------------
@@ -194,20 +199,14 @@ public class ProcAddressEmitter extends JavaEmitter {
protected void generateModifiedEmitters(final JavaMethodBindingEmitter baseJavaEmitter, final List<FunctionEmitter> emitters) {
// See whether we need a proc address entry for this one
- final boolean callThroughProcAddress = needsProcAddressWrapper(baseJavaEmitter.getBinding().getCSymbol());
+ final boolean callThroughProcAddress = callThroughProcAddress(baseJavaEmitter.getBinding().getCSymbol());
// If this emitter doesn't have a body (i.e., is a direct native
// call with no intervening argument processing), we need to force
- // it to emit a body, and produce another one to act as the entry
- // point
- // FIXME: the negative test against the PRIVATE modifier is a
- // nasty hack to prevent the ProcAddressJavaMethodBindingEmitter
- // from incorrectly introducing method bodies to the private
- // native implementing methods; want this to work at least for
- // public and package-private methods
+ // it to emit a body, and produce another one to act as the entry point
final boolean needsJavaWrapper = baseJavaEmitter.signatureOnly() &&
- !baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.PRIVATE) &&
- baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.NATIVE) &&
+ baseJavaEmitter.isNativeMethod() &&
+ !baseJavaEmitter.isPrivateNativeMethod() &&
callThroughProcAddress;
@@ -215,7 +214,7 @@ public class ProcAddressEmitter extends JavaEmitter {
final ProcAddressJavaMethodBindingEmitter emitter = new ProcAddressJavaMethodBindingEmitter(baseJavaEmitter,
callThroughProcAddress,
getProcAddressConfig().getProcAddressTableExpr(),
- baseJavaEmitter.isForImplementingMethodCall(),
+ baseJavaEmitter.isPrivateNativeMethod(),
this);
if( needsJavaWrapper ) {
emitter.setEmitBody(true);
@@ -232,7 +231,7 @@ public class ProcAddressEmitter extends JavaEmitter {
getProcAddressConfig().getProcAddressTableExpr(),
true,
this);
- emitter.setForImplementingMethodCall(true);
+ emitter.setPrivateNativeMethod(true);
fixSecurityModifiers(emitter);
emitters.add(emitter);
}
@@ -243,13 +242,13 @@ public class ProcAddressEmitter extends JavaEmitter {
final FunctionSymbol cSymbol = baseCEmitter.getBinding().getCSymbol();
// See whether we need a proc address entry for this one
- final boolean callThroughProcAddress = needsProcAddressWrapper(cSymbol);
- final boolean forceProcAddress = getProcAddressConfig().forceProcAddressGen(cSymbol.getName());
+ final boolean hasProcAddrTypedef = hasFunctionPointerTypedef(cSymbol);
+ final boolean callThroughProcAddress = hasProcAddrTypedef || callThroughProcAddress(cSymbol);
+ final String localProcCallingConvention = getProcAddressConfig().getLocalProcAddressCallingConvention(cSymbol);
+
+ LOG.log(Level.INFO, cSymbol.getASTLocusTag(), "genModProcAddrEmitter: callThrough {0}, hasTypedef {1}, localCallConv {2}: {3}",
+ callThroughProcAddress, hasProcAddrTypedef, localProcCallingConvention, cSymbol);
- String forcedCallingConvention = null;
- if (forceProcAddress) {
- forcedCallingConvention = getProcAddressConfig().getLocalProcAddressCallingConvention(cSymbol.getName());
- }
// Note that we don't care much about the naming of the C argument
// variables so to keep things simple we ignore the buffer object
// property for the binding
@@ -258,7 +257,7 @@ public class ProcAddressEmitter extends JavaEmitter {
// extra final argument, which is the address (the OpenGL procedure
// address) of the function it needs to call
final ProcAddressCMethodBindingEmitter res = new ProcAddressCMethodBindingEmitter(
- baseCEmitter, callThroughProcAddress, forceProcAddress, forcedCallingConvention, this);
+ baseCEmitter, callThroughProcAddress, hasProcAddrTypedef, localProcCallingConvention, this);
final MessageFormat exp = baseCEmitter.getReturnValueCapacityExpression();
if (exp != null) {
@@ -267,34 +266,30 @@ public class ProcAddressEmitter extends JavaEmitter {
emitters.add(res);
}
- private String getAliasedSymName(final FunctionSymbol sym) {
- String symName = getConfig().getJavaSymbolRename(sym.getName());
- if (null == symName) {
- symName = sym.getName();
+ protected boolean callThroughProcAddress(final FunctionSymbol sym) {
+ final ProcAddressConfiguration cfg = getProcAddressConfig();
+ boolean res = false;
+ int mode = 0;
+ if (cfg.forceProcAddressGen(sym)) {
+ res = true;
+ mode = 1;
+ } else {
+ if (cfg.skipProcAddressGen(sym)) {
+ res = false;
+ mode = 2;
+ } else {
+ res = hasFunctionPointerTypedef(sym);
+ mode = 3;
+ }
}
- return symName;
+ LOG.log(Level.INFO, sym.getASTLocusTag(), "callThroughProcAddress: {0} [m {1}]: {2}", res, mode, sym);
+ return res;
}
-
- protected boolean needsProcAddressWrapper(final FunctionSymbol sym) {
- final String symName = getAliasedSymName(sym);
-
- final ProcAddressConfiguration config = getProcAddressConfig();
-
- // We should only generate code to call through a function pointer
- // if the symbol has an associated function pointer typedef.
+ protected boolean hasFunctionPointerTypedef(final FunctionSymbol sym) {
final String funcPointerTypedefName = getFunctionPointerTypedefName(sym);
- boolean shouldWrap = typedefDictionary.containsKey(funcPointerTypedefName);
- //System.err.println(funcPointerTypedefName + " defined: " + shouldWrap);
-
- if (config.skipProcAddressGen(symName)) {
- shouldWrap = false;
- }
-
- if (config.forceProcAddressGen(symName)) {
- shouldWrap = true;
- }
-
- return shouldWrap;
+ final boolean res = typedefDictionary.containsKey(funcPointerTypedefName);
+ LOG.log(Level.INFO, sym.getASTLocusTag(), "hasFunctionPointerTypedef: {0}: {1}", res, sym);
+ return res;
}
protected void beginProcAddressTable() throws Exception {
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
index a70c18d..5298a8d 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
@@ -41,6 +41,7 @@ package com.jogamp.gluegen.procaddress;
import com.jogamp.gluegen.MethodBinding;
import com.jogamp.gluegen.FunctionEmitter;
import com.jogamp.gluegen.JavaMethodBindingEmitter;
+
import java.io.*;
/** A specialization of JavaMethodBindingEmitter with knowledge of how
@@ -76,12 +77,12 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte
public ProcAddressJavaMethodBindingEmitter(final ProcAddressJavaMethodBindingEmitter methodToWrap) {
this(methodToWrap, methodToWrap.callThroughProcAddress, methodToWrap.getProcAddressTableExpr,
- methodToWrap.changeNameAndArguments, methodToWrap.emitter);
+ methodToWrap.changeNameAndArguments, methodToWrap.emitter);
}
@Override
- public String getName() {
- final String res = super.getName();
+ public String getImplName() {
+ final String res = super.getImplName();
if (changeNameAndArguments) {
return ProcAddressEmitter.WRAP_PREFIX + res;
}
@@ -106,8 +107,8 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte
}
@Override
- protected String getImplMethodName() {
- final String name = super.getImplMethodName();
+ protected String getNativeImplMethodName() {
+ final String name = super.getNativeImplMethodName();
if (callThroughProcAddress) {
return ProcAddressEmitter.WRAP_PREFIX + name;
}
@@ -119,7 +120,7 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte
super.emitPreCallSetup(binding, writer);
if (callThroughProcAddress) {
- final String procAddressVariable = ProcAddressEmitter.PROCADDRESS_VAR_PREFIX + binding.getName();
+ final String procAddressVariable = ProcAddressEmitter.PROCADDRESS_VAR_PREFIX + binding.getNativeName();
writer.println(" final long __addr_ = " + getProcAddressTableExpr + "." + procAddressVariable + ";");
writer.println(" if (__addr_ == 0) {");
writer.format(" throw new %s(String.format(\"Method \\\"%%s\\\" not available\", \"%s\"));%n",
diff --git a/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java b/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java
index c4dedb7..7ccfd1b 100644
--- a/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java
+++ b/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java
@@ -131,7 +131,11 @@ public class CStructAnnotationProcessor extends AbstractProcessor {
if( f.exists() ) {
return f;
}
- } catch (final IOException e) { if(DEBUG) { System.err.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage()); /* e.printStackTrace(); */ } }
+ } catch (final IOException e) {
+ if(DEBUG) {
+ System.err.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage()); /* e.printStackTrace(); */
+ }
+ }
return null;
}
@@ -263,6 +267,9 @@ public class CStructAnnotationProcessor extends AbstractProcessor {
} catch (final FileNotFoundException ex) {
throw new RuntimeException("input file not found", ex);
}
+ if( DEBUG ) {
+ GlueGen.setDebug(true);
+ }
new GlueGen().run(reader, filename, AnnotationProcessorJavaStructEmitter.class,
includePaths, cfgFiles, outputPath1, false /* copyCPPOutput2Stderr */);
diff --git a/src/java/jogamp/android/launcher/MainLauncher.java b/src/java/jogamp/android/launcher/MainLauncher.java
index 0dc6b4a..e0eff7d 100644
--- a/src/java/jogamp/android/launcher/MainLauncher.java
+++ b/src/java/jogamp/android/launcher/MainLauncher.java
@@ -33,6 +33,8 @@ import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
+import com.jogamp.common.util.InterruptSource;
+
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
@@ -117,17 +119,17 @@ public class MainLauncher extends Activity {
public void onResume() {
Log.d(TAG, "onResume - S - "+Thread.currentThread().getName());
super.onResume();
- final Thread mainThread = new Thread("Main") {
+ final Thread mainThread = new InterruptSource.Thread(null, null, "Main") {
public void run() {
try {
- Log.d(TAG, "onResume - main.0 - "+Thread.currentThread().getName());
+ Log.d(TAG, "onResume - main.0 - "+java.lang.Thread.currentThread().getName());
mainClazzMain.invoke(null, new Object[] { mainClassArgs } );
} catch (final InvocationTargetException ite) {
ite.getTargetException().printStackTrace();
} catch (final Throwable t) {
t.printStackTrace();
}
- Log.d(TAG, "onResume - main.X -> finish() - "+Thread.currentThread().getName());
+ Log.d(TAG, "onResume - main.X -> finish() - "+java.lang.Thread.currentThread().getName());
finish();
} };
mainThread.start();
diff --git a/src/java/jogamp/common/os/PlatformPropsImpl.java b/src/java/jogamp/common/os/PlatformPropsImpl.java
index 2d8bdec..fdd6b7f 100644
--- a/src/java/jogamp/common/os/PlatformPropsImpl.java
+++ b/src/java/jogamp/common/os/PlatformPropsImpl.java
@@ -63,6 +63,10 @@ public abstract class PlatformPropsImpl {
public static final VersionNumber Version16;
/** Version 1.7. As a JVM version, it enables certain JVM 1.7 features. */
public static final VersionNumber Version17;
+ /** Version 1.8. As a JVM version, it enables certain JVM 1.8 features. */
+ public static final VersionNumber Version18;
+ /** Version 1.9. As a JVM version, it enables certain JVM 1.9 features. */
+ public static final VersionNumber Version19;
public static final String OS;
public static final String OS_lower;
@@ -101,6 +105,8 @@ public abstract class PlatformPropsImpl {
static {
Version16 = new VersionNumber(1, 6, 0);
Version17 = new VersionNumber(1, 7, 0);
+ Version18 = new VersionNumber(1, 8, 0);
+ Version19 = new VersionNumber(1, 9, 0);
// We don't seem to need an AccessController.doPrivileged() block
// here as these system properties are visible even to unsigned Applets.
diff --git a/src/java/jogamp/common/util/Int32ArrayBitfield.java b/src/java/jogamp/common/util/Int32ArrayBitfield.java
new file mode 100644
index 0000000..5bc95eb
--- /dev/null
+++ b/src/java/jogamp/common/util/Int32ArrayBitfield.java
@@ -0,0 +1,207 @@
+/**
+ * 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 jogamp.common.util;
+
+import com.jogamp.common.util.Bitfield;
+
+/**
+ * Simple bitfield interface for efficient storage access in O(1).
+ * <p>
+ * Implementation uses a 32bit integer array for storage.
+ * </p>
+ */
+public class Int32ArrayBitfield implements Bitfield {
+ private static final int UNIT_SHIFT = 5;
+ private final int[] storage;
+ private final int bitSize;
+
+ /**
+ * @param storageBitSize
+ */
+ public Int32ArrayBitfield(final int storageBitSize) {
+ final int units = Math.max(1, ( storageBitSize + 31 ) >>> UNIT_SHIFT);
+ this.storage = new int[units]; // initialized w/ default '0'
+ this.bitSize = units << UNIT_SHIFT;
+ }
+
+ @Override
+ public int size() {
+ return bitSize;
+ }
+
+ @Override
+ public final void clearField(final boolean bit) {
+ final int v;
+ if( bit ) {
+ v = Bitfield.UNSIGNED_INT_MAX_VALUE;
+ } else {
+ v = 0;
+ }
+ for(int i=storage.length-1; i>=0; i--) {
+ storage[i] = v;
+ }
+ }
+
+ private static final void check(final int size, final int bitnum) throws IndexOutOfBoundsException {
+ if( 0 > bitnum || bitnum >= size ) {
+ throw new IndexOutOfBoundsException("Bitnum should be within [0.."+(size-1)+"], but is "+bitnum);
+ }
+ }
+
+ @Override
+ public final int get32(final int lowBitnum, final int length) throws IndexOutOfBoundsException {
+ if( 0 > length || length > 32 ) {
+ throw new IndexOutOfBoundsException("length should be within [0..32], but is "+length);
+ }
+ check(bitSize-length+1, lowBitnum);
+ final int u = lowBitnum >>> UNIT_SHIFT;
+ final int left = 32 - ( lowBitnum - ( u << UNIT_SHIFT ) ); // remaining bits of first chunk storage
+ if( 32 == left ) {
+ // fast path
+ final int m = Util.getBitMask(length); // mask of chunk
+ return m & storage[u];
+ } else {
+ // slow path
+ final int l = Math.min(length, left); // length of first chunk < 32
+ final int m = ( 1 << l ) - 1; // mask of first chunk
+ final int d = m & ( storage[u] >>> lowBitnum );
+ final int l2 = length - l; // length of last chunk < 32
+ if( l2 > 0 ) {
+ final int m2 = ( 1 << l2 ) - 1; // mask of last chunk
+ return d | ( ( m2 & storage[u+1] ) << l );
+ } else {
+ return d;
+ }
+ }
+ }
+ @Override
+ public final void put32(final int lowBitnum, final int length, final int data) throws IndexOutOfBoundsException {
+ if( 0 > length || length > 32 ) {
+ throw new IndexOutOfBoundsException("length should be within [0..32], but is "+length);
+ }
+ check(bitSize-length+1, lowBitnum);
+ final int u = lowBitnum >>> UNIT_SHIFT;
+ final int left = 32 - ( lowBitnum - ( u << UNIT_SHIFT ) ); // remaining bits of first chunk storage
+ if( 32 == left ) {
+ // fast path
+ final int m = Util.getBitMask(length); // mask of chunk
+ storage[u] = ( ( ~m ) & storage[u] ) // keep non-written storage bits
+ | ( m & data ); // overwrite storage w/ used data bits
+ } else {
+ // slow path
+ final int l = Math.min(length, left); // length of first chunk < 32
+ final int m = ( 1 << l ) - 1; // mask of first chunk
+ storage[u] = ( ( ~( m << lowBitnum ) ) & storage[u] ) // keep non-written storage bits
+ | ( ( m & data ) << lowBitnum ); // overwrite storage w/ used data bits
+ final int l2 = length - l; // length of last chunk < 32
+ if( l2 > 0 ) {
+ final int m2 = ( 1 << l2 ) - 1; // mask of last chunk
+ storage[u+1] = ( ( ~m2 ) & storage[u+1] ) // keep non-written storage bits
+ | ( m2 & ( data >>> l ) ); // overwrite storage w/ used data bits
+ }
+ }
+ }
+ @Override
+ public final int copy32(final int srcBitnum, final int dstBitnum, final int length) throws IndexOutOfBoundsException {
+ final int data = get32(srcBitnum, length);
+ put32(dstBitnum, length, data);
+ return data;
+ }
+
+ @Override
+ public final boolean get(final int bitnum) throws IndexOutOfBoundsException {
+ check(bitSize, bitnum);
+ final int u = bitnum >>> UNIT_SHIFT;
+ final int b = bitnum - ( u << UNIT_SHIFT );
+ return 0 != ( storage[u] & ( 1 << b ) ) ;
+ }
+
+ @Override
+ public final boolean put(final int bitnum, final boolean bit) throws IndexOutOfBoundsException {
+ check(bitSize, bitnum);
+ final int u = bitnum >>> UNIT_SHIFT;
+ final int b = bitnum - ( u << UNIT_SHIFT );
+ final int m = 1 << b;
+ final boolean prev = 0 != ( storage[u] & m ) ;
+ if( prev != bit ) {
+ if( bit ) {
+ storage[u] |= m;
+ } else {
+ storage[u] &= ~m;
+ }
+ }
+ return prev;
+ }
+ @Override
+ public final void set(final int bitnum) throws IndexOutOfBoundsException {
+ check(bitSize, bitnum);
+ final int u = bitnum >>> UNIT_SHIFT;
+ final int b = bitnum - ( u << UNIT_SHIFT );
+ final int m = 1 << b;
+ storage[u] |= m;
+ }
+ @Override
+ public final void clear(final int bitnum) throws IndexOutOfBoundsException {
+ check(bitSize, bitnum);
+ final int u = bitnum >>> UNIT_SHIFT;
+ final int b = bitnum - ( u << UNIT_SHIFT );
+ final int m = 1 << b;
+ storage[u] &= ~m;
+ }
+ @Override
+ public final boolean copy(final int srcBitnum, final int dstBitnum) throws IndexOutOfBoundsException {
+ check(bitSize, srcBitnum);
+ check(bitSize, dstBitnum);
+ final boolean bit;
+ // get
+ {
+ final int u = srcBitnum >>> UNIT_SHIFT;
+ final int b = srcBitnum - ( u << UNIT_SHIFT );
+ bit = 0 != ( storage[u] & ( 1 << b ) ) ;
+ }
+ // put
+ final int u = dstBitnum >>> UNIT_SHIFT;
+ final int b = dstBitnum - ( u << UNIT_SHIFT );
+ final int m = 1 << b;
+ if( bit ) {
+ storage[u] |= m;
+ } else {
+ storage[u] &= ~m;
+ }
+ return bit;
+ }
+
+ @Override
+ public int bitCount() {
+ int c = 0;
+ for(int i = storage.length-1; i>=0; i--) {
+ c += Bitfield.Util.bitCount(storage[i]);
+ }
+ return c;
+ }
+}
diff --git a/src/java/jogamp/common/util/Int32Bitfield.java b/src/java/jogamp/common/util/Int32Bitfield.java
new file mode 100644
index 0000000..7b55a59
--- /dev/null
+++ b/src/java/jogamp/common/util/Int32Bitfield.java
@@ -0,0 +1,163 @@
+/**
+ * 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 jogamp.common.util;
+
+import com.jogamp.common.util.Bitfield;
+
+/**
+ * Simple bitfield interface for efficient storage access in O(1).
+ * <p>
+ * Implementation uses one 32bit integer field for storage.
+ * </p>
+ */
+public class Int32Bitfield implements Bitfield {
+ /** Unit size in bits, here 32 bits for one int unit. */
+ private static final int UNIT_SIZE = 32;
+ private int storage;
+
+ public Int32Bitfield() {
+ this.storage = 0;
+ }
+
+ @Override
+ public int size() {
+ return UNIT_SIZE;
+ }
+
+ @Override
+ public final void clearField(final boolean bit) {
+ if( bit ) {
+ storage = Bitfield.UNSIGNED_INT_MAX_VALUE;
+ } else {
+ storage = 0;
+ }
+ }
+
+ private static final void check(final int size, final int bitnum) throws IndexOutOfBoundsException {
+ if( 0 > bitnum || bitnum >= size ) {
+ throw new IndexOutOfBoundsException("Bitnum should be within [0.."+(size-1)+"], but is "+bitnum);
+ }
+ }
+
+ @Override
+ public final int get32(final int lowBitnum, final int length) throws IndexOutOfBoundsException {
+ if( 0 > length || length > 32 ) {
+ throw new IndexOutOfBoundsException("length should be within [0..32], but is "+length);
+ }
+ check(UNIT_SIZE-length+1, lowBitnum);
+ final int left = 32 - lowBitnum; // remaining bits of first chunk
+ if( 32 == left ) {
+ // fast path
+ final int m = Util.getBitMask(length); // mask of chunk
+ return m & storage;
+ } else {
+ // slow path
+ final int l = Math.min(length, left); // length of first chunk < 32
+ final int m = ( 1 << l ) - 1; // mask of first chunk
+ return m & ( storage >>> lowBitnum );
+ }
+ }
+ @Override
+ public final void put32(final int lowBitnum, final int length, final int data) throws IndexOutOfBoundsException {
+ if( 0 > length || length > 32 ) {
+ throw new IndexOutOfBoundsException("length should be within [0..32], but is "+length);
+ }
+ check(UNIT_SIZE-length+1, lowBitnum);
+ final int left = 32 - lowBitnum; // remaining bits of first chunk storage
+ if( 32 == left ) {
+ // fast path
+ final int m = Util.getBitMask(length); // mask of chunk
+ storage = ( ( ~m ) & storage ) // keep non-written storage bits
+ | ( m & data ); // overwrite storage w/ used data bits
+ } else {
+ // slow path
+ final int l = Math.min(length, left); // length of first chunk < 32
+ final int m = ( 1 << l ) - 1; // mask of first chunk
+ storage = ( ( ~( m << lowBitnum ) ) & storage ) // keep non-written storage bits
+ | ( ( m & data ) << lowBitnum ); // overwrite storage w/ used data bits
+ }
+ }
+ @Override
+ public final int copy32(final int srcBitnum, final int dstBitnum, final int length) throws IndexOutOfBoundsException {
+ final int data = get32(srcBitnum, length);
+ put32(dstBitnum, length, data);
+ return data;
+ }
+
+ @Override
+ public final boolean get(final int bitnum) throws IndexOutOfBoundsException {
+ check(UNIT_SIZE, bitnum);
+ return 0 != ( storage & ( 1 << bitnum ) ) ;
+ }
+ @Override
+ public final boolean put(final int bitnum, final boolean bit) throws IndexOutOfBoundsException {
+ check(UNIT_SIZE, bitnum);
+ final int m = 1 << bitnum;
+ final boolean prev = 0 != ( storage & m ) ;
+ if( prev != bit ) {
+ if( bit ) {
+ storage |= m;
+ } else {
+ storage &= ~m;
+ }
+ }
+ return prev;
+ }
+ @Override
+ public final void set(final int bitnum) throws IndexOutOfBoundsException {
+ check(UNIT_SIZE, bitnum);
+ final int m = 1 << bitnum;
+ storage |= m;
+ }
+ @Override
+ public final void clear (final int bitnum) throws IndexOutOfBoundsException {
+ check(UNIT_SIZE, bitnum);
+ final int m = 1 << bitnum;
+ storage &= ~m;
+ }
+ @Override
+ public final boolean copy(final int srcBitnum, final int dstBitnum) throws IndexOutOfBoundsException {
+ check(UNIT_SIZE, srcBitnum);
+ check(UNIT_SIZE, dstBitnum);
+ // get
+ final boolean bit = 0 != ( storage & ( 1 << srcBitnum ) ) ;
+ // put
+ final int m = 1 << dstBitnum;
+ if( bit ) {
+ storage |= m;
+ } else {
+ storage &= ~m;
+ }
+ return bit;
+ }
+
+ @Override
+ public int bitCount() {
+ return Bitfield.Util.bitCount(storage);
+ }
+}
diff --git a/src/java/jogamp/common/util/SyncedBitfield.java b/src/java/jogamp/common/util/SyncedBitfield.java
new file mode 100644
index 0000000..49c27b0
--- /dev/null
+++ b/src/java/jogamp/common/util/SyncedBitfield.java
@@ -0,0 +1,96 @@
+/**
+ * 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 jogamp.common.util;
+
+import com.jogamp.common.util.Bitfield;
+
+/**
+ * Simple synchronized {@link Bitfield} by wrapping an existing {@link Bitfield}.
+ */
+public class SyncedBitfield implements Bitfield {
+ private final Bitfield impl;
+
+ public SyncedBitfield(final Bitfield impl) {
+ this.impl = impl;
+ }
+
+ @Override
+ public final synchronized int size() {
+ return impl.size();
+ }
+
+ @Override
+ public final synchronized void clearField(final boolean bit) {
+ impl.clearField(bit);
+ }
+
+ @Override
+ public final synchronized int get32(final int lowBitnum, final int length) throws IndexOutOfBoundsException {
+ return impl.get32(lowBitnum, length);
+ }
+
+ @Override
+ public final synchronized void put32(final int lowBitnum, final int length, final int data) throws IndexOutOfBoundsException {
+ impl.put32(lowBitnum, length, data);
+ }
+
+ @Override
+ public final synchronized int copy32(final int srcLowBitnum, final int dstLowBitnum, final int length) throws IndexOutOfBoundsException {
+ return impl.copy32(srcLowBitnum, dstLowBitnum, length);
+ }
+
+ @Override
+ public final synchronized boolean get(final int bitnum) throws IndexOutOfBoundsException {
+ return impl.get(bitnum);
+ }
+
+ @Override
+ public final synchronized boolean put(final int bitnum, final boolean bit) throws IndexOutOfBoundsException {
+ return impl.put(bitnum, bit);
+ }
+
+ @Override
+ public final synchronized void set(final int bitnum) throws IndexOutOfBoundsException {
+ impl.set(bitnum);
+ }
+
+ @Override
+ public final synchronized void clear(final int bitnum) throws IndexOutOfBoundsException {
+ impl.clear(bitnum);
+ }
+
+ @Override
+ public final synchronized boolean copy(final int srcBitnum, final int dstBitnum) throws IndexOutOfBoundsException {
+ return impl.copy(srcBitnum, dstBitnum);
+ }
+
+ @Override
+ public final synchronized int bitCount() {
+ return impl.bitCount();
+ }
+} \ No newline at end of file
diff --git a/src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java b/src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java
index c930dff..1286924 100644
--- a/src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java
+++ b/src/java/jogamp/common/util/locks/RecursiveLockImpl01CompleteFair.java
@@ -32,6 +32,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.AbstractOwnableSynchronizer;
+import com.jogamp.common.util.SourcedInterruptedException;
import com.jogamp.common.util.locks.RecursiveLock;
/**
@@ -197,7 +198,7 @@ public class RecursiveLockImpl01CompleteFair implements RecursiveLock {
} catch (final InterruptedException e) {
if( !wCur.signaledByUnlock ) {
sync.queue.remove(wCur); // O(n)
- throw e; // propagate interruption not send by unlock
+ throw SourcedInterruptedException.wrap(e); // propagate interruption not send by unlock
} else if( cur != sync.getOwner() ) {
// Issued by unlock, but still locked by other thread
//
@@ -215,6 +216,7 @@ public class RecursiveLockImpl01CompleteFair implements RecursiveLock {
} // else: Issued by unlock, owning lock .. expected!
}
} while ( cur != sync.getOwner() && 0 < timeout ) ;
+ Thread.interrupted(); // clear slipped interrupt
if( 0 >= timeout && cur != sync.getOwner() ) {
// timed out
diff --git a/src/java/jogamp/common/util/locks/RecursiveThreadGroupLockImpl01Unfairish.java b/src/java/jogamp/common/util/locks/RecursiveThreadGroupLockImpl01Unfairish.java
index 77f73d8..fc5f739 100644
--- a/src/java/jogamp/common/util/locks/RecursiveThreadGroupLockImpl01Unfairish.java
+++ b/src/java/jogamp/common/util/locks/RecursiveThreadGroupLockImpl01Unfairish.java
@@ -42,6 +42,7 @@ public class RecursiveThreadGroupLockImpl01Unfairish
threadNum = 0;
threads = null;
holdCountAdditionOwner = 0;
+ waitingOrigOwner = null;
}
@Override
public final void incrHoldCount(final Thread t) {
@@ -64,6 +65,12 @@ public class RecursiveThreadGroupLockImpl01Unfairish
public final boolean isOriginalOwner(final Thread t) {
return super.isOwner(t);
}
+ public final void setWaitingOrigOwner(final Thread origOwner) {
+ waitingOrigOwner = origOwner;
+ }
+ public final Thread getWaitingOrigOwner() {
+ return waitingOrigOwner;
+ }
@Override
public final boolean isOwner(final Thread t) {
if(getExclusiveOwnerThread()==t) {
@@ -133,6 +140,7 @@ public class RecursiveThreadGroupLockImpl01Unfairish
private int holdCountAdditionOwner;
private Thread[] threads;
private int threadNum;
+ private Thread waitingOrigOwner;
}
public RecursiveThreadGroupLockImpl01Unfairish() {
@@ -157,10 +165,10 @@ public class RecursiveThreadGroupLockImpl01Unfairish
final Thread cur = Thread.currentThread();
final ThreadGroupSync tgSync = (ThreadGroupSync)sync;
if(!tgSync.isOriginalOwner(cur)) {
- throw new IllegalArgumentException("Current thread is not the original owner: orig-owner: "+tgSync.getOwner()+", current "+cur);
+ throw new IllegalArgumentException("Current thread is not the original owner: orig-owner: "+tgSync.getOwner()+", current "+cur+": "+toString());
}
if(tgSync.isOriginalOwner(t)) {
- throw new IllegalArgumentException("Passed thread is original owner: "+t);
+ throw new IllegalArgumentException("Passed thread is original owner: "+t+", "+toString());
}
tgSync.addOwner(t);
}
@@ -179,19 +187,25 @@ public class RecursiveThreadGroupLockImpl01Unfairish
// original locking owner thread
if( tgSync.getHoldCount() - tgSync.getAdditionalOwnerHoldCount() == 1 ) {
// release orig. lock
- while ( tgSync.getAdditionalOwnerHoldCount() > 0 ) {
- try {
- sync.wait();
- } catch (final InterruptedException e) {
- // regular wake up!
+ tgSync.setWaitingOrigOwner(cur);
+ try {
+ while ( tgSync.getAdditionalOwnerHoldCount() > 0 ) {
+ try {
+ sync.wait();
+ } catch (final InterruptedException e) {
+ // regular wake up!
+ }
}
+ } finally {
+ tgSync.setWaitingOrigOwner(null);
+ Thread.interrupted(); // clear slipped interrupt
}
tgSync.removeAllOwners();
}
} else if( tgSync.getAdditionalOwnerHoldCount() == 1 ) {
- // last additional owner thread wakes up original owner
- final Thread originalOwner = tgSync.getOwner();
- if(originalOwner.getState() == Thread.State.WAITING) {
+ // last additional owner thread wakes up original owner if waiting in unlock(..)
+ final Thread originalOwner = tgSync.getWaitingOrigOwner();
+ if( null != originalOwner ) {
originalOwner.interrupt();
}
}
diff --git a/src/java/jogamp/common/util/locks/SingletonInstanceFileLock.java b/src/java/jogamp/common/util/locks/SingletonInstanceFileLock.java
index 44a5d28..9fe7966 100644
--- a/src/java/jogamp/common/util/locks/SingletonInstanceFileLock.java
+++ b/src/java/jogamp/common/util/locks/SingletonInstanceFileLock.java
@@ -32,6 +32,8 @@ import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
+
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.common.util.locks.SingletonInstance;
public class SingletonInstanceFileLock extends SingletonInstance {
@@ -76,7 +78,7 @@ public class SingletonInstanceFileLock extends SingletonInstance {
private void setupFileCleanup() {
file.deleteOnExit();
- Runtime.getRuntime().addShutdownHook(new Thread() {
+ Runtime.getRuntime().addShutdownHook(new InterruptSource.Thread() {
@Override
public void run() {
if(isLocked()) {
diff --git a/src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java b/src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java
index b1b42c3..6219b5c 100644
--- a/src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java
+++ b/src/java/jogamp/common/util/locks/SingletonInstanceServerSocket.java
@@ -33,10 +33,16 @@ import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
+
+import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.common.util.InterruptedRuntimeException;
+import com.jogamp.common.util.SourcedInterruptedException;
import com.jogamp.common.util.locks.SingletonInstance;
public class SingletonInstanceServerSocket extends SingletonInstance {
+ private static int serverInstanceCount = 0;
private final Server singletonServer;
private final String fullName;
@@ -71,7 +77,7 @@ public class SingletonInstanceServerSocket extends SingletonInstance {
fullName = ilh.toString()+":"+portNumber;
singletonServer = new Server(ilh, portNumber);
- Runtime.getRuntime().addShutdownHook(new Thread() {
+ Runtime.getRuntime().addShutdownHook(new InterruptSource.Thread() {
@Override
public void run() {
singletonServer.kill();
@@ -139,38 +145,58 @@ public class SingletonInstanceServerSocket extends SingletonInstance {
public final boolean start() {
if(alive) return true;
+ final String sname;
+ synchronized (Server.class) {
+ serverInstanceCount++;
+ sname = "SingletonServerSocket"+serverInstanceCount+"-"+fullName;
+ }
synchronized (syncOnStartStop) {
- serverThread = new Thread(this);
+ shallQuit = false;
+ serverThread = new InterruptSource.Thread(null, this, sname);
serverThread.setDaemon(true); // be a daemon, don't keep the JVM running
serverThread.start();
try {
- syncOnStartStop.wait();
+ while( !alive && !shallQuit ) {
+ syncOnStartStop.wait();
+ }
} catch (final InterruptedException ie) {
- ie.printStackTrace();
+ final InterruptedException ie2 = SourcedInterruptedException.wrap(ie);
+ shutdown(false);
+ throw new InterruptedRuntimeException(ie2);
}
}
final boolean ok = isBound();
if(!ok) {
- shutdown();
+ shutdown(true);
}
return ok;
}
public final boolean shutdown() {
+ return shutdown(true);
+ }
+ private final boolean shutdown(final boolean wait) {
if(!alive) return true;
- synchronized (syncOnStartStop) {
- shallQuit = true;
- connect();
- try {
- syncOnStartStop.wait();
- } catch (final InterruptedException ie) {
- ie.printStackTrace();
+ try {
+ synchronized (syncOnStartStop) {
+ shallQuit = true;
+ connect();
+ if( wait ) {
+ try {
+ while( alive ) {
+ syncOnStartStop.wait();
+ }
+ } catch (final InterruptedException ie) {
+ throw new InterruptedRuntimeException(ie);
+ }
+ }
+ }
+ } finally {
+ if(alive) {
+ System.err.println(infoPrefix()+" EEE "+getName()+" - Unable to remove lock: ServerThread still alive ?");
+ kill();
}
- }
- if(alive) {
- System.err.println(infoPrefix()+" EEE "+getName()+" - Unable to remove lock: ServerThread still alive ?");
- kill();
}
return true;
}
@@ -185,7 +211,8 @@ public class SingletonInstanceServerSocket extends SingletonInstance {
System.err.println(infoPrefix()+" XXX "+getName()+" - Kill @ JVM Shutdown");
}
alive = false;
- if(null != serverThread) {
+ shallQuit = false;
+ if(null != serverThread && serverThread.isAlive() ) {
try {
serverThread.stop();
} catch(final Throwable t) { }
@@ -214,47 +241,49 @@ public class SingletonInstanceServerSocket extends SingletonInstance {
@Override
public void run() {
- {
- final Thread currentThread = Thread.currentThread();
- currentThread.setName(currentThread.getName() + " - SISock: "+getName());
- if(DEBUG) {
- System.err.println(currentThread.getName()+" - started");
- }
+ if(DEBUG) {
+ System.err.println(infoPrefix()+" III - Start");
}
- alive = false;
- synchronized (syncOnStartStop) {
- try {
- serverSocket = new ServerSocket(portNumber, 1, localInetAddress);
- serverSocket.setReuseAddress(true); // reuse same port w/ subsequent instance, i.e. overcome TO state when JVM crashed
- alive = true;
- } catch (final IOException e) {
- System.err.println(infoPrefix()+" III - Unable to install ServerSocket: "+e.getMessage());
- shallQuit = true;
- } finally {
- syncOnStartStop.notifyAll();
+ try {
+ synchronized (syncOnStartStop) {
+ try {
+ serverSocket = new ServerSocket(portNumber, 1, localInetAddress);
+ serverSocket.setReuseAddress(true); // reuse same port w/ subsequent instance, i.e. overcome TO state when JVM crashed
+ alive = true;
+ } catch (final IOException e) {
+ System.err.println(infoPrefix()+" III - Unable to install ServerSocket: "+e.getMessage());
+ shallQuit = true;
+ } finally {
+ syncOnStartStop.notifyAll();
+ }
}
- }
- while (!shallQuit) {
- try {
- final Socket clientSocket = serverSocket.accept();
- clientSocket.close();
- } catch (final IOException ioe) {
- System.err.println(infoPrefix()+" EEE - Exception during accept: " + ioe.getMessage());
+ while (!shallQuit) {
+ try {
+ final Socket clientSocket = serverSocket.accept();
+ clientSocket.close();
+ } catch (final IOException ioe) {
+ System.err.println(infoPrefix()+" EEE - Exception during accept: " + ioe.getMessage());
+ }
}
- }
-
- synchronized (syncOnStartStop) {
- try {
+ } catch(final ThreadDeath td) {
+ if( DEBUG ) {
+ ExceptionUtils.dumpThrowable("", td);
+ }
+ } finally {
+ synchronized (syncOnStartStop) {
+ if(DEBUG) {
+ System.err.println(infoPrefix()+" III - Stopping: alive "+alive+", shallQuit "+shallQuit+", hasSocket "+(null!=serverSocket));
+ }
if(null != serverSocket) {
- serverSocket.close();
+ try {
+ serverSocket.close();
+ } catch (final IOException e) {
+ System.err.println(infoPrefix()+" EEE - Exception during close: " + e.getMessage());
+ }
}
- } catch (final IOException e) {
- System.err.println(infoPrefix()+" EEE - Exception during close: " + e.getMessage());
- } finally {
serverSocket = null;
alive = false;
- shallQuit = false;
syncOnStartStop.notifyAll();
}
}
diff --git a/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java b/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java
index 5167abb..1bb88c5 100644
--- a/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java
+++ b/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java
@@ -38,7 +38,7 @@ public class AssetURLConnectionUnregisteredTest extends AssetURLConnectionBase {
@Test
public void assetUnregisteredIOUtilGetResourceRel0_RT() throws IOException, URISyntaxException {
- final URLConnection urlConn0 = IOUtil.getResource(this.getClass(), test_asset_test2_rel.get());
+ final URLConnection urlConn0 = IOUtil.getResource(test_asset_test2_rel.get(), this.getClass().getClassLoader(), this.getClass());
testAssetConnection(urlConn0, test_asset_test2_entry);
final Uri uri1 = Uri.valueOf(urlConn0.getURL()).getRelativeOf(test_asset_test3_rel);
diff --git a/src/junit/com/jogamp/common/net/TestUri01.java b/src/junit/com/jogamp/common/net/TestUri01.java
index 1173610..4205de1 100644
--- a/src/junit/com/jogamp/common/net/TestUri01.java
+++ b/src/junit/com/jogamp/common/net/TestUri01.java
@@ -248,6 +248,20 @@ public class TestUri01 extends SingletonJunitCase {
@Test
public void test08NormalizedHierarchy() throws IOException, URISyntaxException {
{
+ final Uri input = Uri.cast("./dummy/nop/../a.txt");
+ final Uri expected = Uri.cast("dummy/a.txt");
+ URIDumpUtil.showUri(input);
+ final Uri normal = input.getNormalized();
+ Assert.assertEquals(expected, normal);
+ }
+ {
+ final Uri input = Uri.cast("../dummy/nop/../a.txt");
+ final Uri expected = Uri.cast("../dummy/a.txt");
+ URIDumpUtil.showUri(input);
+ final Uri normal = input.getNormalized();
+ Assert.assertEquals(expected, normal);
+ }
+ {
final Uri input = Uri.cast("http://localhost/dummy/../");
final Uri expected = Uri.cast("http://localhost/");
URIDumpUtil.showUri(input);
@@ -255,7 +269,21 @@ public class TestUri01 extends SingletonJunitCase {
Assert.assertEquals(expected, normal);
}
{
- final Uri input = Uri.cast("http://localhost/test/dummy/../text.txt");
+ final Uri input = Uri.cast("http://localhost/dummy/./../");
+ final Uri expected = Uri.cast("http://localhost/");
+ URIDumpUtil.showUri(input);
+ final Uri normal = input.getNormalized();
+ Assert.assertEquals(expected, normal);
+ }
+ {
+ final Uri input = Uri.cast("http://localhost/dummy/../aa/././../");
+ final Uri expected = Uri.cast("http://localhost/");
+ URIDumpUtil.showUri(input);
+ final Uri normal = input.getNormalized();
+ Assert.assertEquals(expected, normal);
+ }
+ {
+ final Uri input = Uri.cast("http://localhost/test/dummy/./../text.txt");
final Uri expected = Uri.cast("http://localhost/test/text.txt");
URIDumpUtil.showUri(input);
final Uri normal = input.getNormalized();
@@ -280,7 +308,7 @@ public class TestUri01 extends SingletonJunitCase {
Assert.assertEquals(expected, normal);
}
{
- final Uri input = Uri.cast("jar:http://localhost/test/dummy/../abc.jar!/");
+ final Uri input = Uri.cast("jar:http://localhost/test/./dummy/../abc.jar!/");
final Uri expected = Uri.cast("jar:http://localhost/test/abc.jar!/");
URIDumpUtil.showUri(input);
final Uri normal = input.getNormalized();
diff --git a/src/junit/com/jogamp/common/nio/BuffersTest.java b/src/junit/com/jogamp/common/nio/BuffersTest.java
index c6a89f1..c267100 100644
--- a/src/junit/com/jogamp/common/nio/BuffersTest.java
+++ b/src/junit/com/jogamp/common/nio/BuffersTest.java
@@ -31,7 +31,15 @@
*/
package com.jogamp.common.nio;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+
import org.junit.Test;
import com.jogamp.junit.util.SingletonJunitCase;
@@ -48,7 +56,66 @@ import org.junit.runners.MethodSorters;
public class BuffersTest extends SingletonJunitCase {
@Test
- public void slice() {
+ public void test01PositionLimitCapacityAfterArrayAllocation() {
+ final byte[] byteData = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ final ByteBuffer byteBuffer = Buffers.newDirectByteBuffer(byteData);
+ assertEquals(0, byteBuffer.position());
+ assertEquals(8, byteBuffer.limit());
+ assertEquals(8, byteBuffer.capacity());
+ assertEquals(8, byteBuffer.remaining());
+ assertEquals(5, byteBuffer.get(4));
+
+ final double[] doubleData = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 };
+ final DoubleBuffer doubleBuffer = Buffers.newDirectDoubleBuffer(doubleData);
+ assertEquals(0, doubleBuffer.position());
+ assertEquals(8, doubleBuffer.limit());
+ assertEquals(8, doubleBuffer.capacity());
+ assertEquals(8, doubleBuffer.remaining());
+ assertEquals(5.0, doubleBuffer.get(4), 0.1);
+
+ final float[] floatData = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };
+ final FloatBuffer floatBuffer = Buffers.newDirectFloatBuffer(floatData);
+ assertEquals(0, floatBuffer.position());
+ assertEquals(8, floatBuffer.limit());
+ assertEquals(8, floatBuffer.capacity());
+ assertEquals(8, floatBuffer.remaining());
+ assertEquals(5.0f, floatBuffer.get(4), 0.1f);
+
+ final int[] intData = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ final IntBuffer intBuffer = Buffers.newDirectIntBuffer(intData);
+ assertEquals(0, intBuffer.position());
+ assertEquals(8, intBuffer.limit());
+ assertEquals(8, intBuffer.capacity());
+ assertEquals(8, intBuffer.remaining());
+ assertEquals(5, intBuffer.get(4));
+
+ final long[] longData = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ final LongBuffer longBuffer = Buffers.newDirectLongBuffer(longData);
+ assertEquals(0, longBuffer.position());
+ assertEquals(8, longBuffer.limit());
+ assertEquals(8, longBuffer.capacity());
+ assertEquals(8, longBuffer.remaining());
+ assertEquals(5, longBuffer.get(4));
+
+ final short[] shortData = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ final ShortBuffer shortBuffer = Buffers.newDirectShortBuffer(shortData);
+ assertEquals(0, shortBuffer.position());
+ assertEquals(8, shortBuffer.limit());
+ assertEquals(8, shortBuffer.capacity());
+ assertEquals(8, shortBuffer.remaining());
+ assertEquals(5, shortBuffer.get(4));
+
+ final char[] charData = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ final CharBuffer charBuffer = Buffers.newDirectCharBuffer(charData);
+ assertEquals(0, charBuffer.position());
+ assertEquals(8, charBuffer.limit());
+ assertEquals(8, charBuffer.capacity());
+ assertEquals(8, charBuffer.remaining());
+ assertEquals(5, charBuffer.get(4));
+ }
+
+ @Test
+ public void test10Slice() {
final IntBuffer buffer = Buffers.newDirectIntBuffer(6);
buffer.put(new int[]{1,2,3,4,5,6}).rewind();
@@ -87,8 +154,10 @@ public class BuffersTest extends SingletonJunitCase {
assertEquals(42, buffer.get(2));
assertEquals(42, onetwothree.get(2));
-
-
}
+ public static void main(final String args[]) throws IOException {
+ final String tstname = BuffersTest.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
}
diff --git a/src/junit/com/jogamp/common/nio/TestByteBufferCopyStream.java b/src/junit/com/jogamp/common/nio/TestByteBufferCopyStream.java
index bef813b..9524e91 100644
--- a/src/junit/com/jogamp/common/nio/TestByteBufferCopyStream.java
+++ b/src/junit/com/jogamp/common/nio/TestByteBufferCopyStream.java
@@ -35,6 +35,7 @@ import java.nio.channels.FileChannel;
import org.junit.Assert;
import org.junit.Test;
+import com.jogamp.common.os.Platform;
import com.jogamp.junit.util.SingletonJunitCase;
import org.junit.FixMethodOrder;
@@ -171,27 +172,42 @@ public class TestByteBufferCopyStream extends SingletonJunitCase {
@Test
public void test00() throws IOException {
+ final long size;
+ if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+ size = quaterGiB;
+ } else {
+ size = twoPlusGiB;
+ }
final int srcSliceShift = MappedByteBufferInputStream.DEFAULT_SLICE_SHIFT;
final int dstSliceShift = MappedByteBufferInputStream.DEFAULT_SLICE_SHIFT;
- final long size = twoPlusGiB;
testImpl(getSimpleTestName(".")+"_In.bin", size, MappedByteBufferInputStream.CacheMode.FLUSH_PRE_HARD, srcSliceShift,
- getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_HARD, dstSliceShift );
+ getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_HARD, dstSliceShift );
}
@Test
public void test01() throws IOException {
+ final long size;
+ if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+ size = quaterGiB;
+ } else {
+ size = twoPlusGiB;
+ }
final int srcSliceShift = MappedByteBufferInputStream.DEFAULT_SLICE_SHIFT;
final int dstSliceShift = MappedByteBufferInputStream.DEFAULT_SLICE_SHIFT;
- final long size = twoPlusGiB;
testImpl(getSimpleTestName(".")+"_In.bin", size, MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, srcSliceShift,
getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, dstSliceShift );
}
@Test
public void test02() throws IOException {
+ final long size;
+ if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+ size = quaterPlusGiB;
+ } else {
+ size = halfPlusGiB;
+ }
final int srcSliceShift = 27; // 125M bytes per slice
final int dstSliceShift = 27; // 125M bytes per slice
- final long size = halfPlusGiB;
testImpl(getSimpleTestName(".")+"_In.bin", size, MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, srcSliceShift,
getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, dstSliceShift );
}
@@ -214,7 +230,14 @@ public class TestByteBufferCopyStream extends SingletonJunitCase {
getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, dstSliceShift );
}
+ static boolean manualTest = false;
+
public static void main(final String args[]) throws IOException {
+ for(int i=0; i<args.length; i++) {
+ if(args[i].equals("-manual")) {
+ manualTest = true;
+ }
+ }
final String tstname = TestByteBufferCopyStream.class.getName();
org.junit.runner.JUnitCore.main(tstname);
}
diff --git a/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java b/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java
index 53ebac9..90a954b 100644
--- a/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java
+++ b/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java
@@ -41,6 +41,7 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
+import com.jogamp.common.os.Platform;
import com.jogamp.common.util.IOUtil;
import com.jogamp.junit.util.SingletonJunitCase;
@@ -144,20 +145,32 @@ public class TestByteBufferInputStream extends SingletonJunitCase {
@Test
public void test11MMap1GiBFlushNone() throws IOException {
- testCopyIntSize1Impl2(0, SrcType.MMAP2_NONE, 0, fileOneGiB, oneGiB);
- // testCopyIntSize1Impl2(0, SrcType.MMAP2_NONE, 0, fileTwoPlusGiB, twoPlusGiB);
+ if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+ testCopyIntSize1Impl2(0, SrcType.MMAP2_NONE, 0, fileOneMiB, oneMiB);
+ } else {
+ testCopyIntSize1Impl2(0, SrcType.MMAP2_NONE, 0, fileOneGiB, oneGiB);
+ // testCopyIntSize1Impl2(0, SrcType.MMAP2_NONE, 0, fileTwoPlusGiB, twoPlusGiB);
+ }
}
@Test
public void test12MMap1GiBFlushSoft() throws IOException {
- testCopyIntSize1Impl2(0, SrcType.MMAP2_SOFT, 0, fileOneGiB, oneGiB);
- // testCopyIntSize1Impl2(0, SrcType.MMAP2_SOFT, 0, fileTwoPlusGiB, twoPlusGiB);
+ if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+ testCopyIntSize1Impl2(0, SrcType.MMAP2_SOFT, 0, fileOneMiB, oneMiB);
+ } else {
+ testCopyIntSize1Impl2(0, SrcType.MMAP2_SOFT, 0, fileOneGiB, oneGiB);
+ // testCopyIntSize1Impl2(0, SrcType.MMAP2_SOFT, 0, fileTwoPlusGiB, twoPlusGiB);
+ }
}
@Test
public void test13MMap2GiBFlushHard() throws IOException {
- // testCopyIntSize1Impl2(0, SrcType.MMAP2_HARD, 0, fileOneGiB, oneGiB);
- testCopyIntSize1Impl2(0, SrcType.MMAP2_HARD, 0, fileTwoPlusGiB, twoPlusGiB);
+ if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+ testCopyIntSize1Impl2(0, SrcType.MMAP2_HARD, 0, fileOneMiB, oneMiB);
+ } else {
+ // testCopyIntSize1Impl2(0, SrcType.MMAP2_HARD, 0, fileOneGiB, oneGiB);
+ testCopyIntSize1Impl2(0, SrcType.MMAP2_HARD, 0, fileTwoPlusGiB, twoPlusGiB);
+ }
}
void testCopyIntSize1Impl(final String testFileName, final long expSize) throws IOException {
@@ -336,7 +349,14 @@ public class TestByteBufferInputStream extends SingletonJunitCase {
System.err.println(" MiB"); */
}
+ static boolean manualTest = false;
+
public static void main(final String args[]) throws IOException {
+ for(int i=0; i<args.length; i++) {
+ if(args[i].equals("-manual")) {
+ manualTest = true;
+ }
+ }
final String tstname = TestByteBufferInputStream.class.getName();
org.junit.runner.JUnitCore.main(tstname);
}
diff --git a/src/junit/com/jogamp/common/nio/TestByteBufferOutputStream.java b/src/junit/com/jogamp/common/nio/TestByteBufferOutputStream.java
index 8686b46..b0d7baf 100644
--- a/src/junit/com/jogamp/common/nio/TestByteBufferOutputStream.java
+++ b/src/junit/com/jogamp/common/nio/TestByteBufferOutputStream.java
@@ -284,7 +284,14 @@ public class TestByteBufferOutputStream extends SingletonJunitCase {
testImpl(getSimpleTestName(".")+".bin", payLoad, 3021L, 6301L, "EOF".getBytes(), sliceShift);
}
+ static boolean manualTest = false;
+
public static void main(final String args[]) throws IOException {
+ for(int i=0; i<args.length; i++) {
+ if(args[i].equals("-manual")) {
+ manualTest = true;
+ }
+ }
final String tstname = TestByteBufferOutputStream.class.getName();
org.junit.runner.JUnitCore.main(tstname);
}
diff --git a/src/junit/com/jogamp/common/util/BitstreamData.java b/src/junit/com/jogamp/common/util/BitDemoData.java
index a5a0bd9..9d605fc 100644
--- a/src/junit/com/jogamp/common/util/BitstreamData.java
+++ b/src/junit/com/jogamp/common/util/BitDemoData.java
@@ -30,11 +30,49 @@ package com.jogamp.common.util;
import java.nio.ByteBuffer;
-public class BitstreamData {
+public class BitDemoData {
+ public static final long UNSIGNED_INT_MAX_VALUE = 0xffffffffL;
+
+ public static final String[] pyramid32bit_one = {
+ "00000000000000000000000000000001",
+ "00000000000000000000000000000010",
+ "00000000000000000000000000000100",
+ "00000000000000000000000000001000",
+ "00000000000000000000000000010000",
+ "00000000000000000000000000100000",
+ "00000000000000000000000001000000",
+ "00000000000000000000000010000000",
+ "00000000000000000000000100000000",
+ "00000000000000000000001000000000",
+ "00000000000000000000010000000000",
+ "00000000000000000000100000000000",
+ "00000000000000000001000000000000",
+ "00000000000000000010000000000000",
+ "00000000000000000100000000000000",
+ "00000000000000001000000000000000",
+ "00000000000000010000000000000000",
+ "00000000000000100000000000000000",
+ "00000000000001000000000000000000",
+ "00000000000010000000000000000000",
+ "00000000000100000000000000000000",
+ "00000000001000000000000000000000",
+ "00000000010000000000000000000000",
+ "00000000100000000000000000000000",
+ "00000001000000000000000000000000",
+ "00000010000000000000000000000000",
+ "00000100000000000000000000000000",
+ "00001000000000000000000000000000",
+ "00010000000000000000000000000000",
+ "00100000000000000000000000000000",
+ "01000000000000000000000000000000",
+ "10000000000000000000000000000000"
+ };
+
//
// MSB -> LSB over whole data
//
public static final byte[] testBytesMSB = new byte[] { (byte)0xde, (byte)0xaf, (byte)0xca, (byte)0xfe };
+ public static final int testIntMSB = 0xdeafcafe; // 11011110 10101111 11001010 11111110
public static final String[] testStringsMSB = new String[] { "11011110", "10101111", "11001010", "11111110" };
public static final String testStringMSB = testStringsMSB[0]+testStringsMSB[1]+testStringsMSB[2]+testStringsMSB[3];
@@ -42,6 +80,7 @@ public class BitstreamData {
// MSB -> LSB, reverse bit-order over each byte of testBytesLSB
//
public static final byte[] testBytesMSB_rev = new byte[] { (byte)0xfe, (byte)0xca, (byte)0xaf, (byte)0xde };
+ public static final int testIntMSB_rev = 0xfecaafde;
public static final String[] testStringsMSB_rev = new String[] { "11111110", "11001010", "10101111", "11011110" };
public static final String testStringMSB_rev = testStringsMSB_rev[0]+testStringsMSB_rev[1]+testStringsMSB_rev[2]+testStringsMSB_rev[3];
@@ -49,6 +88,7 @@ public class BitstreamData {
// LSB -> MSB over whole data
//
public static final byte[] testBytesLSB = new byte[] { (byte)0x7f, (byte)0x53, (byte)0xf5, (byte)0x7b };
+ public static final int testIntLSB = 0x7f53f57b;
public static final String[] testStringsLSB = new String[] { "01111111", "01010011", "11110101", "01111011" };
public static final String testStringLSB = testStringsLSB[0]+testStringsLSB[1]+testStringsLSB[2]+testStringsLSB[3];
@@ -56,6 +96,7 @@ public class BitstreamData {
// LSB -> MSB, reverse bit-order over each byte of testBytesMSB
//
public static final byte[] testBytesLSB_revByte = new byte[] { (byte)0x7b, (byte)0xf5, (byte)0x53, (byte)0x7f };
+ public static final int testIntLSB_revByte = 0x7bf5537f;
public static final String[] testStringsLSB_revByte = new String[] { "01111011", "11110101", "01010011", "01111111" };
public static final String testStringLSB_revByte = testStringsLSB_revByte[0]+testStringsLSB_revByte[1]+testStringsLSB_revByte[2]+testStringsLSB_revByte[3];
@@ -80,6 +121,26 @@ public class BitstreamData {
}
}
+ public static int getOneBitCount(final String pattern) {
+ int c=0;
+ for(int i=0; i<pattern.length(); i++) {
+ if( '1' == pattern.charAt(i) ) {
+ c++;
+ }
+ }
+ return c;
+ }
+ public static long toLong(final String bitPattern) {
+ return Long.valueOf(bitPattern, 2).longValue();
+ }
+ public static int toInteger(final String bitPattern) {
+ final long res = Long.valueOf(bitPattern, 2).longValue();
+ if( res > UNSIGNED_INT_MAX_VALUE ) {
+ throw new NumberFormatException("Exceeds "+toHexString(UNSIGNED_INT_MAX_VALUE)+": "+toHexString(res)+" - source "+bitPattern);
+ }
+ return (int)res;
+ }
+
public static String toHexString(final int v) {
return "0x"+Integer.toHexString(v);
}
diff --git a/src/junit/com/jogamp/common/util/CustomDeflate.java b/src/junit/com/jogamp/common/util/CustomDeflate.java
new file mode 100644
index 0000000..d4682e8
--- /dev/null
+++ b/src/junit/com/jogamp/common/util/CustomDeflate.java
@@ -0,0 +1,115 @@
+/**
+ * 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.common.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class CustomDeflate {
+ public static void main(final String[] args) {
+ if (args.length != 2) {
+ System.err.println("Usage: java "+CustomDeflate.class.getName()+" file-in file-out");
+ } else {
+ final File fileIn = new File(args[0]);
+ final File fileOut = new File(args[1]);
+ final int inSize;
+ {
+ final long _inSize = fileIn.length();
+ if( 0 >= _inSize || _inSize > Integer.MAX_VALUE ) {
+ throw new IllegalArgumentException("");
+ }
+ inSize = (int) _inSize;
+ }
+ final byte[] input = new byte[inSize];
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = new FileInputStream(fileIn);
+ int numBytes = 0;
+ try {
+ while (true) {
+ final int remBytes = inSize - numBytes;
+ int count;
+ if ( 0 >= remBytes || (count = in.read(input, numBytes, remBytes)) == -1 ) {
+ break;
+ }
+ numBytes += count;
+ }
+ } finally {
+ in.close();
+ }
+ if( inSize != numBytes ) {
+ throw new IOException("Got "+numBytes+" bytes != expected "+inSize);
+ }
+ out = new FileOutputStream(fileOut);
+ CustomCompress.deflateToStream(input, 0, inSize, 9, out);
+ } catch (final IOException ioe) {
+ ioe.printStackTrace();
+ } finally {
+ if( null != in ) {
+ try { in.close(); } catch (final IOException e) { }
+ }
+ if( null != out ) {
+ try { out.close(); } catch (final IOException e) { }
+ }
+ }
+
+ //
+ // Test
+ //
+ in = null;
+ out = null;
+ try {
+ in = new FileInputStream(fileOut);
+ final byte[] compare = CustomCompress.inflateFromStream(in);
+ if( compare.length != inSize ) {
+ throw new InternalError("Inflated Size Mismatch: Has "+compare.length+", expected "+inSize);
+ }
+ for(int i=0; i<inSize; i++) {
+ if( input[i] != compare[i] ) {
+ throw new InternalError("Inflated Bytes Mismatch at "+i+"/"+inSize+": Has "+Integer.toHexString(compare[i])+", expected "+Integer.toHexString(input[i]));
+ }
+ }
+ } catch (final IOException ioe) {
+ ioe.printStackTrace();
+ } finally {
+ if( null != in ) {
+ try { in.close(); } catch (final IOException e) { }
+ }
+ if( null != out ) {
+ try { out.close(); } catch (final IOException e) { }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/junit/com/jogamp/common/util/CustomInflate.java b/src/junit/com/jogamp/common/util/CustomInflate.java
new file mode 100644
index 0000000..477439e
--- /dev/null
+++ b/src/junit/com/jogamp/common/util/CustomInflate.java
@@ -0,0 +1,68 @@
+/**
+ * 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.common.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class CustomInflate {
+ public static final int magic = 0xDEF1A7E0;
+
+ public static void main(final String[] args) {
+ if (args.length != 2) {
+ System.err.println("Usage: java "+CustomCompress.class.getName()+" file-in file-out");
+ } else {
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ final File fileIn = new File(args[0]);
+ in = new FileInputStream(fileIn);
+
+ final byte[] output = CustomCompress.inflateFromStream(in);
+
+ final File fileOut = new File(args[1]);
+ out = new FileOutputStream(fileOut);
+ out.write(output, 0, output.length);
+ out.flush();
+ } catch (final IOException ioe) {
+ ioe.printStackTrace();
+ } finally {
+ if( null != in ) {
+ try { in.close(); } catch (final IOException e) { }
+ }
+ if( null != out ) {
+ try { out.close(); } catch (final IOException e) { }
+ }
+ }
+ }
+ }
+}
diff --git a/src/junit/com/jogamp/common/util/TestArrayHashMap01.java b/src/junit/com/jogamp/common/util/TestArrayHashMap01.java
new file mode 100644
index 0000000..529612c
--- /dev/null
+++ b/src/junit/com/jogamp/common/util/TestArrayHashMap01.java
@@ -0,0 +1,186 @@
+/**
+ * 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.common.util;
+
+import java.util.*;
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestArrayHashMap01 extends SingletonJunitCase {
+
+ public static class Dummy {
+ int i1, i2, i3;
+
+ public Dummy(final int i1, final int i2, final int i3) {
+ this.i1 = i1;
+ this.i2 = i2;
+ this.i3 = i3;
+ }
+
+ public boolean equals(final Object o) {
+ if(o instanceof Dummy) {
+ final Dummy d = (Dummy)o;
+ return this.i1 == d.i1 &&
+ this.i2 == d.i2 &&
+ this.i3 == d.i3 ;
+ }
+ return false;
+ }
+
+ public final int hashCode() {
+ // 31 * x == (x << 5) - x
+ int hash = 31 + i1;
+ hash = ((hash << 5) - hash) + i2;
+ hash = ((hash << 5) - hash) + i3;
+ return hash;
+ }
+
+ public String toString() {
+ return "Dummy["+super.toString()+": "+i1+", "+i2+", "+i3+"]";
+ }
+ }
+
+ void populate(final Map<Integer, Dummy> l, final int start, final int len,
+ final int i2, final int i3, final int expectedPlusSize) {
+ final int oldSize = l.size();
+ for(int pos = start+len-1; pos>=start; pos--) {
+ l.put(pos, new Dummy(pos, i2, i3));
+ }
+ Assert.assertEquals(expectedPlusSize, l.size() - oldSize);
+ }
+ boolean checkOrder(final List<Dummy> l, final int startIdx, final int start, final int len) {
+ for(int i=0; i<len; i++) {
+ final Dummy d = l.get(startIdx+i);
+ final int i1 = start+len-1-i;
+ if( d.i1 != i1 ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Test
+ public void test01ArrayHashMapWithNullValue() {
+ testArrayHashMapImpl(true);
+ }
+ @Test
+ public void test02ArrayHashSetWithoutNullValue() {
+ testArrayHashMapImpl(false);
+ }
+ void testArrayHashMapImpl(final boolean supportNullValue) {
+ final ArrayHashMap<Integer, Dummy> l =
+ new ArrayHashMap<Integer, Dummy>(supportNullValue,
+ ArrayHashSet.DEFAULT_INITIAL_CAPACITY,
+ ArrayHashSet.DEFAULT_LOAD_FACTOR);
+ Assert.assertEquals(supportNullValue, l.supportsNullValue());
+ final int p7_22_34_key, p7_22_34_idx;
+ final Dummy p7_22_34_orig;
+ final int p6_22_34_key, p6_22_34_idx;
+ final Dummy p6_22_34_orig;
+ {
+ populate(l, 10, 100, 22, 34, 100); // [109 .. 10]
+ Assert.assertTrue(checkOrder(l.getData(), 0, 10, 100));
+ populate(l, 10, 100, 22, 34, 0); // [109 .. 10]
+ Assert.assertTrue(checkOrder(l.getData(), 0, 10, 100));
+ populate(l, 6, 5, 22, 34, 4); // [ 9 .. 6], 10 already exists
+ Assert.assertTrue(checkOrder(l.getData(), 100, 6, 4));
+ p7_22_34_idx = l.size() - 2;
+ p7_22_34_key = 7;
+ p7_22_34_orig = l.get(p7_22_34_key);
+ p6_22_34_idx = l.size() - 1;
+ p6_22_34_key = 6;
+ p6_22_34_orig = l.get(p6_22_34_key);
+ }
+ Assert.assertNotNull(p7_22_34_orig);
+ Assert.assertEquals(7, p7_22_34_orig.i1);
+ Assert.assertEquals(l.getData().get(p7_22_34_idx), p7_22_34_orig);
+ Assert.assertNotNull(p6_22_34_orig);
+ Assert.assertEquals(6, p6_22_34_orig.i1);
+ Assert.assertEquals(l.getData().get(p6_22_34_idx), p6_22_34_orig);
+
+ final Dummy p7_22_34_other = new Dummy(7, 22, 34);
+ Assert.assertEquals(p7_22_34_other, p7_22_34_orig);
+ Assert.assertTrue(p7_22_34_other.hashCode() == p7_22_34_orig.hashCode());
+ Assert.assertTrue(p7_22_34_other != p7_22_34_orig); // diff reference
+ final Dummy p6_22_34_other = new Dummy(6, 22, 34);
+ Assert.assertEquals(p6_22_34_other, p6_22_34_orig);
+ Assert.assertTrue(p6_22_34_other.hashCode() == p6_22_34_orig.hashCode());
+ Assert.assertTrue(p6_22_34_other != p6_22_34_orig); // diff reference
+
+ // fast identity ..
+ Dummy q = l.get(p6_22_34_key);
+ Assert.assertNotNull(q);
+ Assert.assertEquals(p6_22_34_other, q);
+ Assert.assertTrue(p6_22_34_other.hashCode() == q.hashCode());
+ Assert.assertTrue(p6_22_34_other != q); // diff reference
+ Assert.assertTrue(p6_22_34_orig == q); // same reference
+
+ Assert.assertTrue(l.containsValue(q));
+ Assert.assertTrue(l.containsValue(p6_22_34_other)); // add equivalent
+
+ q = l.put(p6_22_34_key, p6_22_34_other); // override w/ diff hash-obj
+ Assert.assertNotNull(q);
+ Assert.assertEquals(p6_22_34_other, q);
+ Assert.assertTrue(p6_22_34_other.hashCode() == q.hashCode());
+ Assert.assertTrue(p6_22_34_other != q); // diff reference new != old (q)
+ Assert.assertTrue(p6_22_34_orig == q); // same reference orig == old (q)
+ Assert.assertTrue(checkOrder(l.getData(), 0, 10, 100));
+ Assert.assertTrue(checkOrder(l.getData(), 100, 6, 4));
+
+ final Dummy p1_2_3 = new Dummy(1, 2, 3); // a new one ..
+ q = l.put(1, p1_2_3); // added test
+ Assert.assertNull(q);
+
+ final Dummy pNull = null;
+ NullPointerException npe = null;
+ try {
+ q = l.put(0, pNull);
+ Assert.assertNull(q);
+ } catch (final NullPointerException _npe) { npe = _npe; }
+ if( l.supportsNullValue() ) {
+ Assert.assertNull(npe);
+ } else {
+ Assert.assertNotNull(npe);
+ }
+ }
+
+ public static void main(final String args[]) throws IOException {
+ final String tstname = TestArrayHashMap01.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+}
diff --git a/src/junit/com/jogamp/common/util/TestArrayHashSet01.java b/src/junit/com/jogamp/common/util/TestArrayHashSet01.java
index 51db2c7..3e8fbc0 100644
--- a/src/junit/com/jogamp/common/util/TestArrayHashSet01.java
+++ b/src/junit/com/jogamp/common/util/TestArrayHashSet01.java
@@ -74,47 +74,99 @@ public class TestArrayHashSet01 extends SingletonJunitCase {
}
}
- public void populate(final List<Dummy> l, final int start, final int len, final int i2, final int i3, final int expectedPlusSize) {
+ void populate(final List<Dummy> l, final int start, final int len,
+ final int i2, final int i3, final int expectedPlusSize) {
final int oldSize = l.size();
- int pos = start+len-1;
- while(pos>=start) {
- l.add(new Dummy(pos--, i2, i3));
+ for(int pos = start+len-1; pos>=start; pos--) {
+ l.add(new Dummy(pos, i2, i3));
}
Assert.assertEquals(expectedPlusSize, l.size() - oldSize);
}
+ boolean checkOrder(final List<Dummy> l, final int startIdx, final int start, final int len) {
+ for(int i=0; i<len; i++) {
+ final Dummy d = l.get(startIdx+i);
+ final int i1 = start+len-1-i;
+ if( d.i1 != i1 ) {
+ return false;
+ }
+ }
+ return true;
+ }
@Test
- public void test01ArrayHashSet() {
- final ArrayHashSet<Dummy> l = new ArrayHashSet<Dummy>();
- populate(l, 10, 100, 22, 34, 100); // [10 .. 109]
- populate(l, 10, 100, 22, 34, 0); // [10 .. 109]
- populate(l, 6, 5, 22, 34, 4); // [ 6 .. 9], 10 already exists
-
- final Dummy p6_22_34 = new Dummy(6, 22, 34);
+ public void test01ArrayHashSetWithNullValue() {
+ testArrayHashSetImpl(true);
+ }
+ @Test
+ public void test02ArrayHashSetWithoutNullValue() {
+ testArrayHashSetImpl(false);
+ }
+ void testArrayHashSetImpl(final boolean supportNullValue) {
+ final ArrayHashSet<Dummy> l =
+ new ArrayHashSet<Dummy>(supportNullValue,
+ ArrayHashSet.DEFAULT_INITIAL_CAPACITY,
+ ArrayHashSet.DEFAULT_LOAD_FACTOR);
+ Assert.assertEquals(supportNullValue, l.supportsNullValue());
+ final int p7_22_34_idx;
+ final Dummy p7_22_34_orig;
+ final int p6_22_34_idx;
+ final Dummy p6_22_34_orig;
+ {
+ populate(l, 10, 100, 22, 34, 100); // [109 .. 10]
+ Assert.assertTrue(checkOrder(l, 0, 10, 100));
+ populate(l, 10, 100, 22, 34, 0); // [109 .. 10]
+ Assert.assertTrue(checkOrder(l, 0, 10, 100));
+ populate(l, 6, 5, 22, 34, 4); // [ 9 .. 6], 10 already exists
+ Assert.assertTrue(checkOrder(l, 100, 6, 4));
+ p7_22_34_idx = l.size() - 2;
+ p7_22_34_orig = l.get(p7_22_34_idx);
+ p6_22_34_idx = l.size() - 1;
+ p6_22_34_orig = l.get(p6_22_34_idx);
+ }
+ Assert.assertNotNull(p7_22_34_orig);
+ Assert.assertEquals(7, p7_22_34_orig.i1);
+ Assert.assertEquals(l.getData().get(p7_22_34_idx), p7_22_34_orig);
+ Assert.assertNotNull(p6_22_34_orig);
+ Assert.assertEquals(6, p6_22_34_orig.i1);
+ Assert.assertEquals(l.getData().get(p6_22_34_idx), p6_22_34_orig);
+
+ final Dummy p7_22_34_other = new Dummy(7, 22, 34);
+ Assert.assertEquals(p7_22_34_other, p7_22_34_orig);
+ Assert.assertTrue(p7_22_34_other.hashCode() == p7_22_34_orig.hashCode());
+ Assert.assertTrue(p7_22_34_other != p7_22_34_orig); // diff reference
+ final Dummy p6_22_34_other = new Dummy(6, 22, 34);
+ Assert.assertEquals(p6_22_34_other, p6_22_34_orig);
+ Assert.assertTrue(p6_22_34_other.hashCode() == p6_22_34_orig.hashCode());
+ Assert.assertTrue(p6_22_34_other != p6_22_34_orig); // diff reference
// slow get on position ..
- final int i = l.indexOf(p6_22_34);
+ final int i = l.indexOf(p6_22_34_other);
Dummy q = l.get(i);
Assert.assertNotNull(q);
- Assert.assertEquals(p6_22_34, q);
- Assert.assertTrue(p6_22_34.hashCode() == q.hashCode());
- Assert.assertTrue(p6_22_34 != q); // diff reference
+ Assert.assertEquals(p6_22_34_other, q);
+ Assert.assertTrue(p6_22_34_other.hashCode() == q.hashCode());
+ Assert.assertTrue(p6_22_34_other != q); // diff reference
+ Assert.assertTrue(p6_22_34_orig == q); // same reference
// fast identity ..
- q = l.get(p6_22_34);
+ q = l.get(p6_22_34_other);
Assert.assertNotNull(q);
- Assert.assertEquals(p6_22_34, q);
- Assert.assertTrue(p6_22_34.hashCode() == q.hashCode());
- Assert.assertTrue(p6_22_34 != q); // diff reference
+ Assert.assertEquals(p6_22_34_other, q);
+ Assert.assertTrue(p6_22_34_other.hashCode() == q.hashCode());
+ Assert.assertTrue(p6_22_34_other != q); // diff reference
+ Assert.assertTrue(p6_22_34_orig == q); // same reference
Assert.assertTrue(!l.add(q)); // add same
- Assert.assertTrue(!l.add(p6_22_34)); // add equivalent
+ Assert.assertTrue(!l.add(p6_22_34_other)); // add equivalent
- q = l.getOrAdd(p6_22_34); // not added test
+ q = l.getOrAdd(p6_22_34_other); // not added test w/ diff hash-obj
Assert.assertNotNull(q);
- Assert.assertEquals(p6_22_34, q);
- Assert.assertTrue(p6_22_34.hashCode() == q.hashCode());
- Assert.assertTrue(p6_22_34 != q); // diff reference
+ Assert.assertEquals(p6_22_34_other, q);
+ Assert.assertTrue(p6_22_34_other.hashCode() == q.hashCode());
+ Assert.assertTrue(p6_22_34_other != q); // diff reference
+ Assert.assertTrue(p6_22_34_orig == q); // same reference
+ Assert.assertTrue(checkOrder(l, 0, 10, 100));
+ Assert.assertTrue(checkOrder(l, 100, 6, 4));
final Dummy p1_2_3 = new Dummy(1, 2, 3); // a new one ..
q = l.getOrAdd(p1_2_3); // added test
@@ -122,6 +174,29 @@ public class TestArrayHashSet01 extends SingletonJunitCase {
Assert.assertEquals(p1_2_3, q);
Assert.assertTrue(p1_2_3.hashCode() == q.hashCode());
Assert.assertTrue(p1_2_3 == q); // _same_ reference, since getOrAdd added it
+ Assert.assertTrue(checkOrder(l, 0, 10, 100));
+ Assert.assertTrue(checkOrder(l, 100, 6, 4));
+
+ final Dummy pNull = null;
+ NullPointerException npe = null;
+ try {
+ q = l.getOrAdd(pNull);
+ Assert.assertNull(q);
+ } catch (final NullPointerException _npe) { npe = _npe; }
+ if( l.supportsNullValue() ) {
+ Assert.assertNull(npe);
+ } else {
+ Assert.assertNotNull(npe);
+ }
+
+ try {
+ Assert.assertTrue(l.remove(pNull));
+ } catch (final NullPointerException _npe) { npe = _npe; }
+ if( l.supportsNullValue() ) {
+ Assert.assertNull(npe);
+ } else {
+ Assert.assertNotNull(npe);
+ }
}
public static void main(final String args[]) throws IOException {
diff --git a/src/junit/com/jogamp/common/util/TestBitfield00.java b/src/junit/com/jogamp/common/util/TestBitfield00.java
new file mode 100644
index 0000000..9ace743
--- /dev/null
+++ b/src/junit/com/jogamp/common/util/TestBitfield00.java
@@ -0,0 +1,431 @@
+/**
+ * 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.common.util;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.junit.Assert;
+
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+/**
+ * Test basic bitfield operations for {@link Bitfield}
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestBitfield00 extends SingletonJunitCase {
+
+ @Test
+ public void test01_BitCount32_One() {
+ final String[] pyramid32bit_one = BitDemoData.pyramid32bit_one;
+ for(int i=0; i<pyramid32bit_one.length; i++) {
+ final int val0 = 1 << i;
+ final int oneBitCountI = Integer.bitCount(val0);
+ final String pattern0 = pyramid32bit_one[i];
+ final int val1 = BitDemoData.toInteger(pattern0);
+ final String pattern1 = BitDemoData.toBinaryString(val0, 32);
+ final int oneBitCount0 = BitDemoData.getOneBitCount(pattern0);
+ final int oneBitCount1 = Bitfield.Util.bitCount(val0);
+ final String msg = String.format("Round %02d: 0x%08x %s, c %d / %d%n : 0x%08x %s, c %d%n",
+ i, val0, pattern0, oneBitCount0, oneBitCountI, val1, pattern1, oneBitCount1);
+
+ Assert.assertEquals(msg, val0, val1);
+ Assert.assertEquals(msg, pattern0, pattern1);
+
+ Assert.assertEquals(msg, oneBitCount0, oneBitCountI);
+ Assert.assertEquals(msg, oneBitCount0, oneBitCount1);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @Test
+ public void test02_BitCount32_Samples() {
+ final long MAX = BitDemoData.UNSIGNED_INT_MAX_VALUE;
+ final long MAX_minus = MAX-0x1FF;
+ final long MAX_half = MAX/2;
+ final long MAX_half_minus = MAX_half-0x1FF;
+ final long MAX_half_plus = MAX_half+0x1FF;
+
+ if( false ) {
+ for(long l=0; l<=MAX; l++) {
+ test_BitCount32_Samples(l);
+ }
+ }
+ for(long l=0; l>=0x1FF; l++) {
+ test_BitCount32_Samples(l);
+ }
+ for(long l=MAX_half_minus; l<=MAX_half_plus; l++) {
+ test_BitCount32_Samples(l);
+ }
+ for(long l=MAX_minus; l<=MAX; l++) {
+ test_BitCount32_Samples(l);
+ }
+ }
+ static void test_BitCount32_Samples(final long l) {
+ final int oneBitCountL = Long.bitCount(l);
+ final int val0 = (int)l;
+ final int oneBitCountI = Integer.bitCount(val0);
+ final int oneBitCount1 = Bitfield.Util.bitCount(val0);
+ final String msg = String.format("Round 0x%08x, c %d / %d / %d", val0,
+ oneBitCountL, oneBitCountI, oneBitCount1);
+ Assert.assertEquals(msg, oneBitCountI, oneBitCountL);
+ Assert.assertEquals(msg, oneBitCountI, oneBitCount1);
+ }
+
+ static int[] testDataOneBit = new int[] {
+ 0,0, 1,1, 2,1, 3,2, 4,1, 5,2, 6,2, 7,3,
+ 8,1, 9,2, 10,2, 11,3, 12,2, 13,3, 14,3, 15,4, 16,1, 17,2,
+ 0x3F,6, 0x40,1, 0x41,2, 0x7f,7, 0x80,1, 0x81,2, 0xfe,7, 0xff,8,
+ 0x4000,1, 0x4001,2, 0x7000,3, 0x7fff,15,
+ 0x0FFFFFF0,24,
+ 0x55555555,16,
+ 0x7F53F57B,23, 0xFEA7EAF6,23, /* << 1 */
+ 0x80000000, 1,
+ 0xAAAAAAAA,16,
+ 0xC0C0C0C0, 8,
+ 0xFF000000, 8,
+ 0xFFFFFFFF,32
+ };
+ @Test
+ public void test03_BitCount32_Data() {
+ for(int i = 0; i<testDataOneBit.length; i+=2) {
+ test_BitCount32_Data(testDataOneBit[i], testDataOneBit[i+1]);
+ }
+ }
+ static void test_BitCount32_Data(final int i, final int expOneBits) {
+ final int oneBitCountI = Integer.bitCount(i);
+ final int oneBitCount1 = Bitfield.Util.bitCount(i);
+ final String msg = String.format("Round 0x%08x, c %d / %d", i,
+ oneBitCountI, oneBitCount1);
+ Assert.assertEquals(msg, oneBitCount1, expOneBits);
+ Assert.assertEquals(msg, oneBitCountI, oneBitCount1);
+ }
+
+ @Test
+ public void test10_Setup() {
+ final int bitSize32 = 32;
+ final int bitSize128 = 128;
+ final Bitfield bf1 = Bitfield.Factory.create(bitSize32);
+ Assert.assertEquals(bitSize32, bf1.size());
+ Assert.assertTrue(bf1 instanceof jogamp.common.util.Int32Bitfield);
+ final Bitfield bf2 = Bitfield.Factory.create(bitSize128);
+ Assert.assertEquals(bitSize128, bf2.size());
+ Assert.assertTrue(bf2 instanceof jogamp.common.util.Int32ArrayBitfield);
+
+ // verify no bit is set
+ Assert.assertEquals(0, bf1.bitCount());
+ Assert.assertEquals(0, bf2.bitCount());
+
+ bf1.clearField(true);
+ bf2.clearField(true);
+ Assert.assertEquals(bf1.size(), bf1.bitCount());
+ Assert.assertEquals(bf2.size(), bf2.bitCount());
+
+ bf1.clearField(false);
+ bf2.clearField(false);
+ Assert.assertEquals(0, bf1.bitCount());
+ Assert.assertEquals(0, bf2.bitCount());
+ }
+ static class TestDataBF {
+ final int bitSize;
+ final int val;
+ final String pattern;
+ public TestDataBF(final int bitSize, final int value, final String pattern) {
+ this.bitSize = bitSize;
+ this.val = value;
+ this.pattern = pattern;
+ }
+ }
+ static TestDataBF[] testDataBF32Bit = {
+ new TestDataBF(32, BitDemoData.testIntMSB, BitDemoData.testStringMSB),
+ new TestDataBF(32, BitDemoData.testIntMSB_rev, BitDemoData.testStringMSB_rev),
+ new TestDataBF(32, BitDemoData.testIntLSB, BitDemoData.testStringLSB),
+ new TestDataBF(32, BitDemoData.testIntLSB_revByte, BitDemoData.testStringLSB_revByte),
+
+ // H->L : 0x04030201: 00000100 00000011 00000010 00000001
+ new TestDataBF(32, 0x04030201, "00000100000000110000001000000001"),
+
+ // H->L : 0xAFFECAFE: 10101111 11111110 11001010 11111110
+ new TestDataBF(32, 0xAFFECAFE, "10101111111111101100101011111110"),
+ // H->L : 0xDEADBEEF: 11011110 10101101 10111110 11101111
+ new TestDataBF(32, 0xDEADBEEF, "11011110101011011011111011101111")
+ };
+ static TestDataBF[] testDataBF16Bit = {
+ // H->L : 0x0201: 00000100 00000011 00000010 00000001
+ new TestDataBF(16, 0x0201, "0000001000000001"),
+ // H->L : 0x0403: 00000100 00000011
+ new TestDataBF(16, 0x0403, "0000010000000011"),
+
+ // H->L : 0xAFFE: 10101111 11111110
+ new TestDataBF(16, 0xAFFE, "1010111111111110"),
+ // H->L : 0xCAFE: 11001010 11111110
+ new TestDataBF(16, 0xCAFE, "1100101011111110"),
+
+ // H->L : 0xDEADBEEF: 11011110 10101101 10111110 11101111
+ new TestDataBF(16, 0xDEAD, "1101111010101101"),
+ new TestDataBF(16, 0xBEEF, "1011111011101111")
+ };
+ static TestDataBF[] testDataBF3Bit = {
+ new TestDataBF(3, 0x01, "001"),
+ new TestDataBF(3, 0x02, "010"),
+ new TestDataBF(3, 0x05, "101")
+ };
+
+ @Test
+ public void test20_ValidateTestData() {
+ for(int i=0; i<testDataBF32Bit.length; i++) {
+ test_ValidateTestData( testDataBF32Bit[i] );
+ }
+ for(int i=0; i<testDataBF16Bit.length; i++) {
+ test_ValidateTestData( testDataBF16Bit[i] );
+ }
+ for(int i=0; i<testDataBF3Bit.length; i++) {
+ test_ValidateTestData( testDataBF3Bit[i] );
+ }
+ }
+ static void test_ValidateTestData(final TestDataBF d) {
+ final int oneBitCount0 = Bitfield.Util.bitCount(d.val);
+ final int oneBitCount1 = BitDemoData.getOneBitCount(d.pattern);
+ Assert.assertEquals(oneBitCount1, oneBitCount0);
+ final String pattern0 = BitDemoData.toBinaryString(d.val, d.bitSize);
+ Assert.assertEquals(d.pattern, pattern0);
+ final int val1 = BitDemoData.toInteger(d.pattern);
+ Assert.assertEquals(d.val, val1);
+ Assert.assertEquals(d.bitSize, pattern0.length());
+ }
+
+ static void assertEquals(final Bitfield bf, final int bf_off, final int v, final String pattern, final int oneBitCount) {
+ final int len = pattern.length();
+ for(int i=0; i<len; i++) {
+ final boolean exp0 = 0 != ( v & ( 1 << i ) );
+ final boolean exp1 = '1' == pattern.charAt(len-1-i);
+ final boolean has = bf.get(i+bf_off);
+ final String msg = String.format("Pos %04d: Value 0x%08x / %s, c %d", i, v, pattern, oneBitCount);
+ Assert.assertEquals(msg, exp0, has);
+ Assert.assertEquals(msg, exp1, has);
+ }
+ }
+
+ @Test
+ public void test21_Aligned32bit() {
+ for(int i=0; i<testDataBF32Bit.length; i++) {
+ test_Aligned32bit( testDataBF32Bit[i] );
+ }
+ for(int i=0; i<testDataBF16Bit.length; i++) {
+ test_Aligned32bit( testDataBF16Bit[i] );
+ }
+ for(int i=0; i<testDataBF3Bit.length; i++) {
+ test_Aligned32bit( testDataBF3Bit[i] );
+ }
+ }
+ static int get32BitStorageSize(final int bits) {
+ final int units = Math.max(1, ( bits + 31 ) >>> 5);
+ return units << 5;
+ }
+ static void test_Aligned32bit(final TestDataBF d) {
+ final int oneBitCount = Bitfield.Util.bitCount(d.val);
+
+ final Bitfield bf1 = Bitfield.Factory.create(d.bitSize);
+ Assert.assertEquals(get32BitStorageSize(d.bitSize), bf1.size());
+ final Bitfield bf2 = Bitfield.Factory.create(d.bitSize+128);
+ Assert.assertEquals(get32BitStorageSize(d.bitSize+128), bf2.size());
+
+ bf1.put32( 0, d.bitSize, d.val);
+ Assert.assertEquals(d.val, bf1.get32( 0, d.bitSize));
+ Assert.assertEquals(oneBitCount, bf1.bitCount());
+ assertEquals(bf1, 0, d.val, d.pattern, oneBitCount);
+
+ bf2.put32( 0, d.bitSize, d.val);
+ Assert.assertEquals(d.val, bf2.get32( 0, d.bitSize));
+ Assert.assertEquals(oneBitCount*1, bf2.bitCount());
+ assertEquals(bf2, 0, d.val, d.pattern, oneBitCount);
+ bf2.put32(64, d.bitSize, d.val);
+ Assert.assertEquals(d.val, bf2.get32(64, d.bitSize));
+ Assert.assertEquals(oneBitCount*2, bf2.bitCount());
+ assertEquals(bf2, 64, d.val, d.pattern, oneBitCount);
+
+ Assert.assertEquals(d.val, bf2.copy32(0, 96, d.bitSize));
+ Assert.assertEquals(d.val, bf2.get32(96, d.bitSize));
+ Assert.assertEquals(oneBitCount*3, bf2.bitCount());
+ assertEquals(bf2, 96, d.val, d.pattern, oneBitCount);
+ }
+
+ @Test
+ public void test21_Unaligned() {
+ for(int i=0; i<testDataBF32Bit.length; i++) {
+ test_Unaligned(testDataBF32Bit[i]);
+ }
+ for(int i=0; i<testDataBF16Bit.length; i++) {
+ test_Unaligned(testDataBF16Bit[i]);
+ }
+ for(int i=0; i<testDataBF3Bit.length; i++) {
+ test_Unaligned( testDataBF3Bit[i] );
+ }
+ }
+ static void test_Unaligned(final TestDataBF d) {
+ final Bitfield bf1 = Bitfield.Factory.create(d.bitSize);
+ final Bitfield bf2 = Bitfield.Factory.create(d.bitSize+128);
+ Assert.assertEquals(get32BitStorageSize(d.bitSize), bf1.size());
+ Assert.assertEquals(get32BitStorageSize(d.bitSize+128), bf2.size());
+ test_Unaligned( d, bf1 );
+ test_Unaligned( d, bf2 );
+ }
+ static void test_Unaligned(final TestDataBF d, final Bitfield bf) {
+ final int maxBitpos = bf.size()-d.bitSize;
+ for(int i=0; i<=maxBitpos; i++) {
+ bf.clearField(false);
+ test_Unaligned(d, bf, i);
+ }
+ }
+ static void test_Unaligned(final TestDataBF d, final Bitfield bf, final int lowBitnum) {
+ final int maxBitpos = bf.size()-d.bitSize;
+ final int oneBitCount = Bitfield.Util.bitCount(d.val);
+
+ final String msg = String.format("Value 0x%08x / %s, l %d/%d, c %d, lbPos %d -> %d",
+ d.val, d.pattern, d.bitSize, bf.size(), oneBitCount, lowBitnum, maxBitpos);
+
+ //
+ // via put32
+ //
+ bf.put32( lowBitnum, d.bitSize, d.val);
+ for(int i=0; i<d.bitSize; i++) {
+ Assert.assertEquals(msg+", bitpos "+i, 0 != ( d.val & ( 1 << i ) ), bf.get(lowBitnum+i));
+ }
+ Assert.assertEquals(msg, d.val, bf.get32( lowBitnum, d.bitSize));
+ Assert.assertEquals(msg, oneBitCount, bf.bitCount());
+ assertEquals(bf, lowBitnum, d.val, d.pattern, oneBitCount);
+
+ //
+ // via copy32
+ //
+ if( lowBitnum < maxBitpos ) {
+ // copy bits 1 forward
+ // clear trailing orig bit
+ Assert.assertEquals(msg, d.val, bf.copy32(lowBitnum, lowBitnum+1, d.bitSize));
+ bf.clear(lowBitnum);
+ Assert.assertEquals(msg, d.val, bf.get32( lowBitnum+1, d.bitSize));
+ Assert.assertEquals(msg, oneBitCount, bf.bitCount());
+ assertEquals(bf, lowBitnum+1, d.val, d.pattern, oneBitCount);
+ }
+
+ // test put() return value (previous value)
+ bf.clearField(false);
+ Assert.assertEquals(msg+", bitpos "+0, false, bf.put(lowBitnum+0, true));
+ Assert.assertEquals(msg+", bitpos "+0, true, bf.put(lowBitnum+0, false));
+
+ //
+ // via put
+ //
+ for(int i=0; i<d.bitSize; i++) {
+ Assert.assertEquals(msg+", bitpos "+i, false, bf.put(lowBitnum+i, 0 != ( d.val & ( 1 << i ) )));
+ }
+ Assert.assertEquals(msg, d.val, bf.get32(lowBitnum, d.bitSize));
+ for(int i=0; i<d.bitSize; i++) {
+ Assert.assertEquals(msg+", bitpos "+i, 0 != ( d.val & ( 1 << i ) ), bf.get(lowBitnum+i));
+ }
+ Assert.assertEquals(msg, oneBitCount, bf.bitCount());
+ assertEquals(bf, lowBitnum, d.val, d.pattern, oneBitCount);
+
+ //
+ // via copy
+ //
+ if( lowBitnum < maxBitpos ) {
+ // copy bits 1 forward
+ // clear trailing orig bit
+ for(int i=d.bitSize-1; i>=0; i--) {
+ Assert.assertEquals(msg+", bitpos "+i, 0 != ( d.val & ( 1 << i ) ),
+ bf.copy(lowBitnum+i, lowBitnum+1+i) );
+ }
+ bf.clear(lowBitnum);
+ Assert.assertEquals(msg, d.val, bf.get32( lowBitnum+1, d.bitSize));
+ for(int i=0; i<d.bitSize; i++) {
+ Assert.assertEquals(msg+", bitpos "+i, 0 != ( d.val & ( 1 << i ) ), bf.get(lowBitnum+1+i));
+ }
+ Assert.assertEquals(msg, oneBitCount, bf.bitCount());
+ assertEquals(bf, lowBitnum+1, d.val, d.pattern, oneBitCount);
+ }
+
+ //
+ // via set/clear
+ //
+ bf.clearField(false);
+ for(int i=0; i<d.bitSize; i++) {
+ if( 0 != ( d.val & ( 1 << i ) ) ) {
+ bf.set(lowBitnum+i);
+ } else {
+ bf.clear(lowBitnum+i);
+ }
+ }
+ Assert.assertEquals(msg, d.val, bf.get32(lowBitnum, d.bitSize));
+ for(int i=0; i<d.bitSize; i++) {
+ Assert.assertEquals(msg+", bitpos "+i, 0 != ( d.val & ( 1 << i ) ), bf.get(lowBitnum+i));
+ }
+ Assert.assertEquals(msg, oneBitCount, bf.bitCount());
+ assertEquals(bf, lowBitnum, d.val, d.pattern, oneBitCount);
+
+ //
+ // Validate 'other bits' put32/get32
+ //
+ bf.clearField(false);
+ bf.put32( lowBitnum, d.bitSize, d.val);
+ checkOtherBits(d, bf, lowBitnum, msg, 0);
+
+ bf.clearField(true);
+ bf.put32( lowBitnum, d.bitSize, d.val);
+ checkOtherBits(d, bf, lowBitnum, msg, Bitfield.UNSIGNED_INT_MAX_VALUE);
+ }
+
+ static void checkOtherBits(final TestDataBF d, final Bitfield bf, final int lowBitnum, final String msg, final int expBits) {
+ final int highBitnum = lowBitnum + d.bitSize - 1;
+ // System.err.println(msg+": [0"+".."+"("+lowBitnum+".."+highBitnum+").."+(bf.size()-1)+"]");
+ for(int i=0; i<lowBitnum; i+=32) {
+ final int len = Math.min(32, lowBitnum-i);
+ final int val = bf.get32(i, len);
+ final int exp = expBits & Bitfield.Util.getBitMask(len);
+ // System.err.println(" <"+i+".."+(i+len-1)+">, exp "+BitDemoData.toHexString(exp));
+ Assert.assertEquals(msg+", bitpos "+i, exp, val);
+ }
+ for(int i=highBitnum+1; i<bf.size(); i+=32) {
+ final int len = Math.min(32, bf.size() - i);
+ final int val = bf.get32(i, len);
+ final int exp = expBits & Bitfield.Util.getBitMask(len);
+ // System.err.println(" <"+i+".."+(i+len-1)+">, exp "+BitDemoData.toHexString(exp));
+ Assert.assertEquals(msg+", bitpos "+i, exp, val);
+ }
+ }
+
+ public static void main(final String args[]) throws IOException {
+ final String tstname = TestBitfield00.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+}
diff --git a/src/junit/com/jogamp/common/util/TestBitstream00.java b/src/junit/com/jogamp/common/util/TestBitstream00.java
index 920363b..a2fd095 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream00.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream00.java
@@ -40,7 +40,7 @@ import org.junit.Assert;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.os.Platform;
-import static com.jogamp.common.util.BitstreamData.*;
+import static com.jogamp.common.util.BitDemoData.*;
import com.jogamp.junit.util.SingletonJunitCase;
diff --git a/src/junit/com/jogamp/common/util/TestBitstream01.java b/src/junit/com/jogamp/common/util/TestBitstream01.java
index 49931a3..bff37e3 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream01.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream01.java
@@ -35,7 +35,7 @@ import org.junit.Assert;
import org.junit.Test;
import com.jogamp.junit.util.SingletonJunitCase;
-import static com.jogamp.common.util.BitstreamData.*;
+import static com.jogamp.common.util.BitDemoData.*;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
diff --git a/src/junit/com/jogamp/common/util/TestBitstream02.java b/src/junit/com/jogamp/common/util/TestBitstream02.java
index 16904a2..5e6da1c 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream02.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream02.java
@@ -37,7 +37,7 @@ import org.junit.Test;
import com.jogamp.common.nio.Buffers;
import com.jogamp.junit.util.SingletonJunitCase;
-import static com.jogamp.common.util.BitstreamData.*;
+import static com.jogamp.common.util.BitDemoData.*;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
diff --git a/src/junit/com/jogamp/common/util/TestBitstream03.java b/src/junit/com/jogamp/common/util/TestBitstream03.java
index a6129d8..bd09d4a 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream03.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream03.java
@@ -38,7 +38,7 @@ import org.junit.Test;
import com.jogamp.common.nio.Buffers;
import com.jogamp.junit.util.SingletonJunitCase;
-import static com.jogamp.common.util.BitstreamData.*;
+import static com.jogamp.common.util.BitDemoData.*;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
diff --git a/src/junit/com/jogamp/common/util/TestBitstream04.java b/src/junit/com/jogamp/common/util/TestBitstream04.java
index 47be38d..2302e2e 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream04.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream04.java
@@ -38,7 +38,7 @@ import org.junit.Test;
import com.jogamp.common.nio.Buffers;
import com.jogamp.junit.util.SingletonJunitCase;
-import static com.jogamp.common.util.BitstreamData.*;
+import static com.jogamp.common.util.BitDemoData.*;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
diff --git a/src/junit/com/jogamp/common/util/TestIOUtil01.java b/src/junit/com/jogamp/common/util/TestIOUtil01.java
index e85aa37..19bc8b0 100644
--- a/src/junit/com/jogamp/common/util/TestIOUtil01.java
+++ b/src/junit/com/jogamp/common/util/TestIOUtil01.java
@@ -35,6 +35,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.net.URISyntaxException;
import java.net.URLConnection;
import java.nio.ByteBuffer;
@@ -43,6 +44,9 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
+import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.net.URIDumpUtil;
+import com.jogamp.common.net.Uri;
import com.jogamp.common.os.MachineDataInfo;
import com.jogamp.common.os.Platform;
import com.jogamp.junit.util.SingletonJunitCase;
@@ -78,8 +82,86 @@ public class TestIOUtil01 extends SingletonJunitCase {
}
@Test
- public void testCopyStream01Array() throws IOException {
- final URLConnection urlConn = IOUtil.getResource(this.getClass(), tfilename);
+ public void test01CleanPathString() throws IOException, URISyntaxException {
+ {
+ final String input = "./dummy/nop/../a.txt";
+ final String expected = "dummy/a.txt";
+ Assert.assertEquals(expected, IOUtil.cleanPathString(input));
+ }
+ {
+ final String input = "../dummy/nop/../a.txt";
+ final String expected = "../dummy/a.txt";
+ Assert.assertEquals(expected, IOUtil.cleanPathString(input));
+ }
+ {
+ final String input = ".././dummy/nop/../a.txt";
+ final String expected = "../dummy/a.txt";
+ Assert.assertEquals(expected, IOUtil.cleanPathString(input));
+ }
+ {
+ final String input = "./../dummy/nop/../a.txt";
+ final String expected = "../dummy/a.txt";
+ Assert.assertEquals(expected, IOUtil.cleanPathString(input));
+ }
+ {
+ final String input = "../dummy/./nop/../a.txt";
+ final String expected = "../dummy/a.txt";
+ Assert.assertEquals(expected, IOUtil.cleanPathString(input));
+ }
+ {
+ final String input = "/dummy/nop/./../a.txt";
+ final String expected = "/dummy/a.txt";
+ Assert.assertEquals(expected, IOUtil.cleanPathString(input));
+ }
+ {
+ final String input = "dummy/../nop/./.././aaa/bbb/../../a.txt";
+ final String expected = "a.txt";
+ Assert.assertEquals(expected, IOUtil.cleanPathString(input));
+ }
+ {
+ final String input = "/dummy/../nop/./.././aaa/bbb/././ccc/../../../a.txt";
+ final String expected = "/a.txt";
+ Assert.assertEquals(expected, IOUtil.cleanPathString(input));
+ }
+ {
+ URISyntaxException use = null;
+ try {
+ // Error case!
+ final String input = "../../error.txt";
+ final String expected = "error.txt";
+ final String result = IOUtil.cleanPathString(input); // URISyntaxException
+ System.err.println("input : "+input);
+ System.err.println("expected: "+expected);
+ System.err.println("result : "+result);
+ Assert.assertEquals(expected, result);
+ } catch (final URISyntaxException _use) {
+ use = _use;
+ ExceptionUtils.dumpThrowable("", _use, 0, 3);
+ }
+ Assert.assertNotNull("URISyntaxException expected", use);
+ }
+ {
+ URISyntaxException use = null;
+ try {
+ // Error case!
+ final String input = ".././a/../../error.txt";
+ final String expected = "error.txt";
+ final String result = IOUtil.cleanPathString(input); // URISyntaxException
+ System.err.println("input : "+input);
+ System.err.println("expected: "+expected);
+ System.err.println("result : "+result);
+ Assert.assertEquals(expected, result);
+ } catch (final URISyntaxException _use) {
+ use = _use;
+ ExceptionUtils.dumpThrowable("", _use, 0, 3);
+ }
+ Assert.assertNotNull("URISyntaxException expected", use);
+ }
+ }
+
+ @Test
+ public void test11CopyStream01Array() throws IOException {
+ final URLConnection urlConn = IOUtil.getResource(tfilename, this.getClass().getClassLoader(), this.getClass());
Assert.assertNotNull(urlConn);
final BufferedInputStream bis = new BufferedInputStream( urlConn.getInputStream() );
final byte[] bb;
@@ -94,8 +176,8 @@ public class TestIOUtil01 extends SingletonJunitCase {
}
@Test
- public void testCopyStream02Buffer() throws IOException {
- final URLConnection urlConn = IOUtil.getResource(this.getClass(), tfilename);
+ public void test12CopyStream02Buffer() throws IOException {
+ final URLConnection urlConn = IOUtil.getResource(tfilename, this.getClass().getClassLoader(), this.getClass());
Assert.assertNotNull(urlConn);
final BufferedInputStream bis = new BufferedInputStream( urlConn.getInputStream() );
final ByteBuffer bb;
@@ -111,16 +193,16 @@ public class TestIOUtil01 extends SingletonJunitCase {
}
@Test
- public void testCopyStream03Buffer() throws IOException {
+ public void test13CopyStream03Buffer() throws IOException {
final String tfilename2 = "./test2.bin" ;
- final URLConnection urlConn1 = IOUtil.getResource(this.getClass(), tfilename);
+ final URLConnection urlConn1 = IOUtil.getResource(tfilename, this.getClass().getClassLoader(), this.getClass());
Assert.assertNotNull(urlConn1);
final File file2 = new File(tfilename2);
file2.deleteOnExit();
try {
IOUtil.copyURLConn2File(urlConn1, file2);
- final URLConnection urlConn2 = IOUtil.getResource(this.getClass(), tfilename2);
+ final URLConnection urlConn2 = IOUtil.getResource(tfilename2, this.getClass().getClassLoader(), this.getClass());
Assert.assertNotNull(urlConn2);
final BufferedInputStream bis = new BufferedInputStream( urlConn2.getInputStream() );
diff --git a/src/junit/com/jogamp/common/util/TestPlatform01.java b/src/junit/com/jogamp/common/util/TestPlatform01.java
index 6f1fe0e..bf3e79d 100644
--- a/src/junit/com/jogamp/common/util/TestPlatform01.java
+++ b/src/junit/com/jogamp/common/util/TestPlatform01.java
@@ -44,7 +44,7 @@ public class TestPlatform01 extends SingletonJunitCase {
@Test
public void testInfo00() {
System.err.println();
- System.err.println();
+ System.err.print(Platform.getNewline());
System.err.println("OS name/type: "+Platform.getOSName()+", "+Platform.getOSType());
System.err.println("OS version: "+Platform.getOSVersion()+", "+Platform.getOSVersionNumber());
System.err.println();
diff --git a/src/junit/com/jogamp/common/util/TestRunnableTask01.java b/src/junit/com/jogamp/common/util/TestRunnableTask01.java
index 76c2d2a..6fd8f19 100644
--- a/src/junit/com/jogamp/common/util/TestRunnableTask01.java
+++ b/src/junit/com/jogamp/common/util/TestRunnableTask01.java
@@ -60,7 +60,7 @@ public class TestRunnableTask01 extends SingletonJunitCase {
System.err.println("BB.0: "+syncObject);
synchronized (syncObject) {
System.err.println("BB.1: "+syncObject);
- new Thread(clientAction, Thread.currentThread().getName()+"-clientAction").start();
+ new InterruptSource.Thread(null, clientAction, Thread.currentThread().getName()+"-clientAction").start();
try {
System.err.println("BB.2");
syncObject.wait();
@@ -88,7 +88,7 @@ public class TestRunnableTask01 extends SingletonJunitCase {
System.err.println("BB.0: "+rTask.getSyncObject());
synchronized (rTask.getSyncObject()) {
System.err.println("BB.1: "+rTask.getSyncObject());
- new Thread(rTask, Thread.currentThread().getName()+"-clientAction").start();
+ new InterruptSource.Thread(null, rTask, Thread.currentThread().getName()+"-clientAction").start();
try {
System.err.println("BB.2");
rTask.getSyncObject().wait();
diff --git a/src/junit/com/jogamp/common/util/TestVersionSemantics.java b/src/junit/com/jogamp/common/util/TestVersionSemantics.java
index 6faa9a6..8e36684 100644
--- a/src/junit/com/jogamp/common/util/TestVersionSemantics.java
+++ b/src/junit/com/jogamp/common/util/TestVersionSemantics.java
@@ -66,9 +66,6 @@ import com.jogamp.junit.util.VersionSemanticsUtil;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestVersionSemantics extends SingletonJunitCase {
static final String jarFile = "gluegen-rt.jar";
- static final VersionNumberString preVersionNumber = new VersionNumberString("2.2.0");
- static final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.NON_BACKWARD_COMPATIBLE;
- // static final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.BACKWARD_COMPATIBLE_USER;
static final DiffCriteria diffCriteria = new SimpleDiffCriteria();
// static final DiffCriteria diffCriteria = new PublicDiffCriteria();
@@ -76,22 +73,55 @@ public class TestVersionSemantics extends SingletonJunitCase {
static final JogampVersion curVersion = GlueGenVersion.getInstance();
static final VersionNumberString curVersionNumber = new VersionNumberString(curVersion.getImplementationVersion());
- static final Set<String> excludes;
+ static final Set<String> excludesDefault;
static {
- excludes = new HashSet<String>();
- excludes.add("^\\Qjogamp/\\E.*$");
+ excludesDefault = new HashSet<String>();
+ excludesDefault.add("^\\Qjogamp/\\E.*$");
}
@Test
- public void testVersionLatest() throws IllegalArgumentException, IOException, URISyntaxException {
+ public void testVersionV220V221() throws IllegalArgumentException, IOException, URISyntaxException {
+ testVersions(diffCriteria, Delta.CompatibilityType.BACKWARD_COMPATIBLE_USER, "2.2.0", "2.2.1", excludesDefault);
+ }
+
+ @Test
+ public void testVersionV221V230() throws IllegalArgumentException, IOException, URISyntaxException {
+ testVersions(diffCriteria, Delta.CompatibilityType.NON_BACKWARD_COMPATIBLE, "2.2.1", "2.3.0", excludesDefault);
+ }
+
+ @Test
+ public void testVersionV230V232() throws IllegalArgumentException, IOException, URISyntaxException {
+ testVersions(diffCriteria, Delta.CompatibilityType.BACKWARD_COMPATIBLE_BINARY, "2.3.0", "2.3.2", excludesDefault);
+ }
+
+ void testVersions(final DiffCriteria diffCriteria, final Delta.CompatibilityType expectedCompatibilityType,
+ final String v1, final String v2, final Set<String> excludes)
+ throws IllegalArgumentException, IOException, URISyntaxException {
+ final VersionNumberString preVersionNumber = new VersionNumberString(v1);
+ final File previousJar = new File("lib/v"+v1+"/"+jarFile);
+
+ final VersionNumberString curVersionNumber = new VersionNumberString(v2);
+ final File currentJar = new File("lib/v"+v2+"/"+jarFile);
+
+ VersionSemanticsUtil.testVersion(diffCriteria, expectedCompatibilityType,
+ previousJar, preVersionNumber,
+ currentJar, curVersionNumber, excludes);
+ }
+
+ @Test
+ public void testVersionV232V24x() throws IllegalArgumentException, IOException, URISyntaxException {
+ final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.NON_BACKWARD_COMPATIBLE;
+ // final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.BACKWARD_COMPATIBLE_USER;
+ // final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.BACKWARD_COMPATIBLE_BINARY;
+ final VersionNumberString preVersionNumber = new VersionNumberString("2.3.2");
final File previousJar = new File("lib/v"+preVersionNumber.getVersionString()+"/"+jarFile);
final ClassLoader currentCL = TestVersionSemantics.class.getClassLoader();
VersionSemanticsUtil.testVersion(diffCriteria, expectedCompatibilityType,
previousJar, preVersionNumber,
- curVersion.getClass(), currentCL, curVersionNumber, excludes);
+ curVersion.getClass(), currentCL, curVersionNumber, excludesDefault);
}
public static void main(final String args[]) throws IOException {
diff --git a/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java b/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java
index 4508f94..7455618 100644
--- a/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java
+++ b/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java
@@ -38,6 +38,7 @@ import org.junit.Assert;
import org.junit.Test;
import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.junit.util.SingletonJunitCase;
import org.junit.FixMethodOrder;
@@ -170,7 +171,7 @@ public class TestRecursiveLock01 extends SingletonJunitCase {
public final void action2Deferred(final int l, final YieldMode yieldMode) {
final Action2 action2 = new Action2(l, yieldMode);
- new Thread(action2, Thread.currentThread().getName()+"-deferred").start();
+ new InterruptSource.Thread(null, action2, Thread.currentThread().getName()+"-deferred").start();
}
public final void lock() {
@@ -296,14 +297,14 @@ public class TestRecursiveLock01 extends SingletonJunitCase {
final long t0 = System.currentTimeMillis();
final LockedObject lo = new LockedObject(implType, fair);
final LockedObjectRunner[] runners = new LockedObjectRunner[threadNum];
- final Thread[] threads = new Thread[threadNum];
+ final InterruptSource.Thread[] threads = new InterruptSource.Thread[threadNum];
int i;
for(i=0; i<threadNum; i++) {
runners[i] = new LockedObjectRunner1(lo, loops, iloops, yieldMode);
// String name = Thread.currentThread().getName()+"-ActionThread-"+i+"_of_"+threadNum;
final String name = "ActionThread-"+i+"_of_"+threadNum;
- threads[i] = new Thread( runners[i], name );
+ threads[i] = new InterruptSource.Thread( null, runners[i], name );
threads[i].start();
}
diff --git a/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java b/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java
index e35d146..30a0274 100644
--- a/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java
+++ b/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java
@@ -34,6 +34,7 @@ import org.junit.Assert;
import org.junit.Test;
import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.junit.util.SingletonJunitCase;
import org.junit.FixMethodOrder;
@@ -239,15 +240,15 @@ public class TestRecursiveThreadGroupLock01 extends SingletonJunitCase {
final LockedObject lo = new LockedObject();
final LockedObjectRunner[] concurrentRunners = new LockedObjectRunner[concurrentThreadNum];
final LockedObjectRunner[] slaveRunners = new LockedObjectRunner[slaveThreadNum];
- final Thread[] concurrentThreads = new Thread[concurrentThreadNum];
- final Thread[] slaveThreads = new Thread[slaveThreadNum];
- final Thread[] noCoOwnerThreads = new Thread[0];
+ final InterruptSource.Thread[] concurrentThreads = new InterruptSource.Thread[concurrentThreadNum];
+ final InterruptSource.Thread[] slaveThreads = new InterruptSource.Thread[slaveThreadNum];
+ final InterruptSource.Thread[] noCoOwnerThreads = new InterruptSource.Thread[0];
int i;
for(i=0; i<slaveThreadNum; i++) {
slaveRunners[i] = new LockedObjectRunner1(" ", "s"+i, lo, loops, mark, yieldMode);
final String name = "ActionThread-Slaves-"+i+"_of_"+slaveThreadNum;
- slaveThreads[i] = new Thread( slaveRunners[i], name );
+ slaveThreads[i] = new InterruptSource.Thread( null, slaveRunners[i], name );
}
for(i=0; i<concurrentThreadNum; i++) {
String name;
@@ -258,7 +259,7 @@ public class TestRecursiveThreadGroupLock01 extends SingletonJunitCase {
concurrentRunners[i] = new LockedObjectRunner1(" ", "O"+i, lo, noCoOwnerThreads, loops, mark, yieldMode);
name = "ActionThread-Others-"+i+"_of_"+concurrentThreadNum;
}
- concurrentThreads[i] = new Thread( concurrentRunners[i], name );
+ concurrentThreads[i] = new InterruptSource.Thread( null, concurrentRunners[i], name );
concurrentThreads[i].start();
if(i==0) {
// master thread w/ slaves shall start first
diff --git a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java
index b018a79..ce0087a 100644
--- a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java
+++ b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java
@@ -35,10 +35,12 @@ import org.junit.Test;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.junit.util.JunitTracer;
import com.jogamp.junit.util.SingletonJunitCase;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestSingletonServerSocket00 {
+public class TestSingletonServerSocket00 extends JunitTracer {
public static final long SINGLE_INSTANCE_LOCK_TO = SingletonJunitCase.SINGLE_INSTANCE_LOCK_TO;
public static final long SINGLE_INSTANCE_LOCK_POLL = 100; // poll every 100ms
@@ -69,7 +71,7 @@ public class TestSingletonServerSocket00 {
}
private Thread startLockUnlockOffThread(final int i) {
- final Thread t = new Thread(new Runnable() {
+ final Thread t = new InterruptSource.Thread(null, new Runnable() {
public void run() {
final SingletonInstance myLock = SingletonInstance.createServerSocket(10, SingletonJunitCase.SINGLE_INSTANCE_LOCK_PORT);
System.err.println(Thread.currentThread().getName()+" LOCK try ..");
diff --git a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java
index b37e600..c637865 100644
--- a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java
+++ b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java
@@ -35,10 +35,11 @@ import org.junit.Test;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
+import com.jogamp.junit.util.JunitTracer;
import com.jogamp.junit.util.SingletonJunitCase;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestSingletonServerSocket01 {
+public class TestSingletonServerSocket01 extends JunitTracer {
private static volatile SingletonInstance singletonInstance;
@BeforeClass
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..db8c157 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java
@@ -65,21 +65,25 @@ public class BaseClass extends SingletonJunitCase {
Assert.assertNotNull(ifName+" does not exist", clazzIf);
Assert.assertNotNull(implName+" does not exist", clazzImpl);
- Assert.assertEquals(1, clazzIf.getDeclaredField("CONSTANT_ONE").get(null));
+ Assert.assertNotNull(clazzImpl.getDeclaredMethod("nopTest"));
final Object obj = clazzImpl.newInstance();
Assert.assertTrue("Not of type "+ifName, clazzIf.isAssignableFrom(obj.getClass()));
- Assert.assertTrue("Not of type com.jogamp.gluegen.test.junit.generation.Bindingtest1", (obj instanceof com.jogamp.gluegen.test.junit.generation.Bindingtest1));
+ Assert.assertTrue("Not of type com.jogamp.gluegen.test.junit.generation.Bindingtest1",
+ (obj instanceof com.jogamp.gluegen.test.junit.generation.Bindingtest1));
}
+ public static final float EPSILON = 1.1920929E-7f; // Float.MIN_VALUE == 1.4e-45f ; double EPSILON 2.220446049250313E-16d
+
/**
* Verifies if all generated method signatures are completed,
* ie a compilation only coverage test without functional tests.
*/
public void chapter__TestCoverageSignature(final Bindingtest1 binding) throws Exception {
- int i;
+ int i = 0;
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 +93,42 @@ 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.testShortBlob(sb);
+ sb = binding.testLPShortBlob0(sb);
+ sb = binding.testLPShortBlob1(sb);
+ sb = binding.testLPShortBlob2(sb);
+ sb = binding.testLPShortBlob3(sb);
+ sb = binding.testShortBlobL1(sb);
+ sb = binding.testShortBlobL2(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);
+
+ i = binding.testDelegate(i);
+ }
+
+ {
+ bb = binding.createAPtrBlob();
+ pb = safeByteBuffer2PointerBuffer(bb, 1);
long bb2A = binding.getAPtrAddress(bb);
bb2A = bb2A - 0; // avoid warning
@@ -119,9 +155,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);
@@ -177,6 +210,185 @@ public class BaseClass extends SingletonJunitCase {
l = binding.typeTestUIntPtrT(l, l);
}
+ /**
+ * Verifies if all generated static constant values are completed,
+ * and whether their value is as expected!
+ * <p>
+ * Covers all enumerates and defines.
+ * </p>
+ */
+ public void chapter01TestStaticConstants(final Bindingtest1 binding) throws Exception {
+ // Plain vanilla CPP constants
+ Assert.assertEquals( 1, Bindingtest1.CONSTANT_ONE);
+ Assert.assertEquals( 8, Bindingtest1.ARRAY_SIZE);
+ Assert.assertEquals(1234, Bindingtest1.DEFINE_01);
+
+ // Enums
+ Assert.assertEquals( 1, Bindingtest1.LI);
+ Assert.assertEquals( 3, Bindingtest1.LO);
+ Assert.assertEquals( 2, Bindingtest1.LU);
+ Assert.assertEquals( 1, Bindingtest1.MI);
+ Assert.assertEquals( 3, Bindingtest1.MO);
+ Assert.assertEquals( 2, Bindingtest1.MU);
+ Assert.assertEquals( 0, Bindingtest1.ZERO);
+ Assert.assertEquals( 1, Bindingtest1.ONE);
+ Assert.assertEquals( 2, Bindingtest1.TWO);
+ Assert.assertEquals( 3, Bindingtest1.THREE);
+
+ // CPP Macro Expansion!
+ Assert.assertEquals( 1, Bindingtest1.NUMBER_ONE);
+ Assert.assertEquals( 2, Bindingtest1.NUMBER_TWO);
+ Assert.assertEquals( 4, Bindingtest1.NUMBER_FOUR);
+ Assert.assertEquals( 5, Bindingtest1.NUMBER_FIVE);
+ Assert.assertEquals( 8, Bindingtest1.NUMBER_EIGHT);
+ Assert.assertEquals( 9, Bindingtest1.NUMBER_NINE);
+ Assert.assertEquals( 10, Bindingtest1.NUMBER_TEN);
+
+ // Enum Constant Expressions!
+ Assert.assertEquals( 1, Bindingtest1.ENUM_NUM_ONE);
+ Assert.assertEquals( 2, Bindingtest1.ENUM_NUM_TWO);
+ Assert.assertEquals( 3, Bindingtest1.ENUM_NUM_THREE);
+ Assert.assertEquals( 4, Bindingtest1.ENUM_NUM_FOUR);
+ Assert.assertEquals( 5, Bindingtest1.ENUM_NUM_FIVE);
+ Assert.assertEquals( 8, Bindingtest1.ENUM_NUM_EIGHT);
+ Assert.assertEquals( 9, Bindingtest1.ENUM_NUM_NINE);
+ Assert.assertEquals( 10, Bindingtest1.ENUM_NUM_TEN);
+
+ // Integer 32bit (int / enum)
+ final int ENUM_I0 = Bindingtest1.ENUM_I0;
+ final int ENUM_I1 = Bindingtest1.ENUM_I1;
+ final int ENUM_I2 = Bindingtest1.ENUM_I2;
+ final int ENUM_I3 = Bindingtest1.ENUM_I3;
+ final int ENUM_I4 = -Bindingtest1.ENUM_I4;
+ final int ENUM_I5 = -Bindingtest1.ENUM_I5;
+ final int ENUM_I6 = -Bindingtest1.ENUM_I6;
+ final int ENUM_I7 = Bindingtest1.ENUM_I7;
+ final int ENUM_I8 = Bindingtest1.ENUM_I8;
+ final int ENUM_I9 = Bindingtest1.ENUM_I9;
+ final int ENUM_IA = Bindingtest1.ENUM_IA;
+ final int ENUM_IB = Bindingtest1.ENUM_IB;
+ final int ENUM_IX = Bindingtest1.ENUM_IX;
+ int iexp = 10;
+ Assert.assertEquals(iexp++, ENUM_I0);
+ Assert.assertEquals(iexp++, ENUM_I1);
+ Assert.assertEquals(iexp++, ENUM_I2);
+ Assert.assertEquals(iexp++, ENUM_I3);
+ Assert.assertEquals(iexp++, ENUM_I4);
+ Assert.assertEquals(iexp++, ENUM_I5);
+ Assert.assertEquals(iexp++, ENUM_I6);
+ Assert.assertEquals(iexp++, ENUM_I7);
+ Assert.assertEquals(iexp++, ENUM_I8);
+ Assert.assertEquals(iexp++, ENUM_I9);
+ Assert.assertEquals(iexp++, ENUM_IA);
+ Assert.assertEquals(iexp++, ENUM_IB);
+ Assert.assertEquals(0xffffffff, ENUM_IX);
+
+ // Integer 32bit (int / define)
+ final int CL_INT_I0 = Bindingtest1.CL_INT_I0;
+ final int CL_INT_I1 = Bindingtest1.CL_INT_I1;
+ final int CL_INT_I2 = Bindingtest1.CL_INT_I2;
+ final int CL_INT_I3 = Bindingtest1.CL_INT_I3;
+ final int CL_INT_I4 = -Bindingtest1.CL_INT_I4;
+ final int CL_INT_I5 = -Bindingtest1.CL_INT_I5;
+ final int CL_INT_I6 = -Bindingtest1.CL_INT_I6;
+ final int CL_INT_I7 = -Bindingtest1.CL_INT_I7;
+ final int CL_INT_I8 = Bindingtest1.CL_INT_I8;
+ final int CL_INT_I9 = Bindingtest1.CL_INT_I9;
+ final int CL_INT_IA = Bindingtest1.CL_INT_IA;
+ final int CL_INT_IB = Bindingtest1.CL_INT_IB;
+ final int CL_INT_IX = Bindingtest1.CL_INT_IX;
+ iexp = 10;
+ Assert.assertEquals(iexp++, CL_INT_I0);
+ Assert.assertEquals(iexp++, CL_INT_I1);
+ Assert.assertEquals(iexp++, CL_INT_I2);
+ Assert.assertEquals(iexp++, CL_INT_I3);
+ Assert.assertEquals(iexp++, CL_INT_I4);
+ Assert.assertEquals(iexp++, CL_INT_I5);
+ Assert.assertEquals(iexp++, CL_INT_I6);
+ Assert.assertEquals(iexp++, CL_INT_I7);
+ Assert.assertEquals(iexp++, CL_INT_I8);
+ Assert.assertEquals(iexp++, CL_INT_I9);
+ Assert.assertEquals(iexp++, CL_INT_IA);
+ Assert.assertEquals(iexp++, CL_INT_IB);
+ Assert.assertEquals(0xffffffff, CL_INT_IX);
+
+ // Integer 64bit (long / define )
+ final long CL_LNG_L0 = Bindingtest1.CL_LNG_L0;
+ final long CL_LNG_L1 = Bindingtest1.CL_LNG_L1;
+ final long CL_LNG_L2 = Bindingtest1.CL_LNG_L2;
+ final long CL_LNG_L3 = Bindingtest1.CL_LNG_L3;
+ final long CL_LNG_L4 = -Bindingtest1.CL_LNG_L4;
+ final long CL_LNG_L5 = -Bindingtest1.CL_LNG_L5;
+ final long CL_LNG_L6 = -Bindingtest1.CL_LNG_L6;
+ final long CL_LNG_L7 = -Bindingtest1.CL_LNG_L7;
+ final long CL_LNG_L8 = Bindingtest1.CL_LNG_L8;
+ final long CL_LNG_L9 = Bindingtest1.CL_LNG_L9;
+ final long CL_LNG_LA = Bindingtest1.CL_LNG_LA;
+ final long CL_LNG_LB = Bindingtest1.CL_LNG_LB;
+ final long CL_LNG_LX = Bindingtest1.CL_LNG_LX;
+ long lexp = 2147483648L;
+ Assert.assertEquals(lexp++, CL_LNG_L0);
+ Assert.assertEquals(lexp++, CL_LNG_L1);
+ Assert.assertEquals(lexp++, CL_LNG_L2);
+ Assert.assertEquals(lexp++, CL_LNG_L3);
+ Assert.assertEquals(lexp++, CL_LNG_L4);
+ Assert.assertEquals(lexp++, CL_LNG_L5);
+ Assert.assertEquals(lexp++, CL_LNG_L6);
+ Assert.assertEquals(lexp++, CL_LNG_L7);
+ Assert.assertEquals(lexp++, CL_LNG_L8);
+ Assert.assertEquals(lexp++, CL_LNG_L9);
+ Assert.assertEquals(lexp++, CL_LNG_LA);
+ Assert.assertEquals(lexp++, CL_LNG_LB);
+ Assert.assertEquals(0xffffffffffffffffL, CL_LNG_LX);
+
+ // Floating point hexadecimals
+ final float CL_FLT_A0 = Bindingtest1.CL_FLT_A0;
+ final float CL_FLT_A1 = Bindingtest1.CL_FLT_A1;
+ final float CL_FLT_A2 = Bindingtest1.CL_FLT_A2;
+ final float CL_FLT_A3 = Bindingtest1.CL_FLT_A3;
+ final float CL_FLT_A4 = Bindingtest1.CL_FLT_A4;
+ final float CL_FLT_A5 = Bindingtest1.CL_FLT_A5;
+ final float CL_FLT_A6 = Bindingtest1.CL_FLT_A6;
+ final float CL_FLT_A7 = Bindingtest1.CL_FLT_A7;
+ Assert.assertEquals( 0x1.p127f, CL_FLT_A0, EPSILON);
+ Assert.assertEquals( 0x1.p+127F, CL_FLT_A1, EPSILON);
+ Assert.assertEquals( 0x1.p-127f, CL_FLT_A2, EPSILON);
+ Assert.assertEquals( -0.1f, CL_FLT_A3, EPSILON);
+ Assert.assertEquals( 0.2f, CL_FLT_A4, EPSILON);
+ Assert.assertEquals( 0.3f, CL_FLT_A5, EPSILON);
+ Assert.assertEquals( 0.4f, CL_FLT_A6, EPSILON);
+ Assert.assertEquals( 1.0f, CL_FLT_A7, EPSILON);
+
+ final float CL_FLT_EPSILON = Bindingtest1.CL_FLT_EPSILON;
+ final double CL_FLT_MAX= Bindingtest1.CL_FLT_MAX;
+ final double CL_FLT_MIN = Bindingtest1.CL_FLT_MIN;
+ Assert.assertEquals( 0x1.0p-23f, CL_FLT_EPSILON, EPSILON);
+ Assert.assertEquals( 0x1.fffffep127f, CL_FLT_MAX, EPSILON);
+ Assert.assertEquals( 0x1.0p-126f, CL_FLT_MIN, EPSILON);
+
+ final double CL_DBL_B0 = Bindingtest1.CL_DBL_B0;
+ final double CL_DBL_B1 = Bindingtest1.CL_DBL_B1;
+ final double CL_DBL_B2 = Bindingtest1.CL_DBL_B2;
+ final double CL_DBL_B3 = Bindingtest1.CL_DBL_B3;
+ final double CL_DBL_B4 = Bindingtest1.CL_DBL_B4;
+ final double CL_DBL_B5 = Bindingtest1.CL_DBL_B5;
+ final double CL_DBL_B6 = Bindingtest1.CL_DBL_B6;
+ Assert.assertEquals( 0x1.p127d, CL_DBL_B0, EPSILON);
+ Assert.assertEquals( 0x1.p+127D, CL_DBL_B1, EPSILON);
+ Assert.assertEquals( 0x1.p-127d, CL_DBL_B2, EPSILON);
+ Assert.assertEquals( -0.1, CL_DBL_B3, EPSILON);
+ Assert.assertEquals( 0.2, CL_DBL_B4, EPSILON);
+ Assert.assertEquals( 0.3, CL_DBL_B5, EPSILON);
+ Assert.assertEquals( 3.5e+38, CL_DBL_B6, EPSILON);
+
+ final float CL_DBL_EPSILON = Bindingtest1.CL_DBL_EPSILON;
+ final double CL_DBL_MAX= Bindingtest1.CL_DBL_MAX;
+ final double CL_DBL_MIN = Bindingtest1.CL_DBL_MIN;
+ Assert.assertEquals( 0x1.0p-52f, CL_DBL_EPSILON, EPSILON);
+ Assert.assertEquals( 0x1.fffffffffffffp1023, CL_DBL_MAX, EPSILON);
+ Assert.assertEquals( 0x1.0p-1022, CL_DBL_MIN, EPSILON);
+ }
+
ByteBuffer newByteBuffer(final int size, final boolean direct) {
if(direct) {
final ByteBuffer bb = Buffers.newDirectByteBuffer(size);
@@ -629,6 +841,66 @@ 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 sb_ = binding.testShortBlob(sb);
+ final ShortBlob sb0 = binding.testLPShortBlob0(sb);
+ final ShortBlob sb1 = binding.testLPShortBlob1(sb);
+ final ShortBlob sb2 = binding.testLPShortBlob2(sb);
+ final ShortBlob sb3 = binding.testLPShortBlob3(sb);
+ final ShortBlob sb4 = binding.testShortBlobL1(sb);
+ final ShortBlob sb5 = binding.testShortBlobL2(sb);
+ Assert.assertEquals(sb.getBuffer(), sb_.getBuffer());
+ 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());
+ Assert.assertEquals(sb.getBuffer(), sb5.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);
+ }
+
+ {
+ i=41;
+ final int iRes = binding.testDelegate(i);
+ Assert.assertEquals(i+1, iRes);
+ }
}
public void chapter04TestPointerBuffer(final Bindingtest1 binding) throws Exception {
@@ -1115,22 +1387,20 @@ public class BaseClass extends SingletonJunitCase {
}
}
- public static final float EPSILON = 1.1920929E-7f; // Float.MIN_VALUE == 1.4e-45f ; double EPSILON 2.220446049250313E-16d
-
/** Test array and pointer bindings of structs */
public void chapter12TestStructArrayModelConst(final Bindingtest1 binding) throws Exception {
final TK_ModelConst model = binding.createModelConst();
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 +1440,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 +1455,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 +1506,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 +1566,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 +1655,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 +1670,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/Test1p1JavaEmitter.java b/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p1JavaEmitter.java
index 9e961cb..5809acf 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p1JavaEmitter.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p1JavaEmitter.java
@@ -50,7 +50,7 @@ public class Test1p1JavaEmitter extends BaseClass {
* Verifies loading of the new library.
*/
@BeforeClass
- public static void chapter01TestLoadLibrary() throws Exception {
+ public static void chapter__TestLoadLibrary() throws Exception {
BindingJNILibLoader.loadBindingtest1p1();
}
@@ -58,7 +58,7 @@ public class Test1p1JavaEmitter extends BaseClass {
* Verifies the existence and creation of the generated class.
*/
@Test
- public void chapter02TestClassExist() throws Exception {
+ public void chapter00TestClassExist() throws Exception {
testClassExist("test1p1");
}
@@ -71,6 +71,18 @@ public class Test1p1JavaEmitter extends BaseClass {
}
/**
+ * Verifies if all generated static constant values are completed,
+ * and whether their value is as expected!
+ * <p>
+ * Covers all enumerates and defines.
+ * </p>
+ */
+ @Test
+ public void chapter01TestStaticConstants() throws Exception {
+ chapter01TestStaticConstants(new Bindingtest1p1Impl());
+ }
+
+ /**
* Verifies if all methods / signatures are properly generated,
* can be invoked and functions.
* This is a compilation (coverage) and runtime time (semantic) test.
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2LoadJNIAndImplLib.java b/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2LoadJNIAndImplLib.java
index b8adab0..e61c600 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2LoadJNIAndImplLib.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2LoadJNIAndImplLib.java
@@ -46,9 +46,9 @@ public class Test1p2LoadJNIAndImplLib extends BaseClass {
* Verifies loading of the new library.
*/
@BeforeClass
- public static void chapter01TestLoadLibrary() throws Exception {
+ public static void chapter__TestLoadLibrary() throws Exception {
BindingJNILibLoader.loadBindingtest1p2();
- dynamicLookupHelper = NativeLibrary.open("test1", Test1p2LoadJNIAndImplLib.class.getClassLoader(), true);
+ dynamicLookupHelper = NativeLibrary.open("test1", true, true, Test1p2LoadJNIAndImplLib.class.getClassLoader(), true);
Assert.assertNotNull("NativeLibrary.open(test1) failed", dynamicLookupHelper);
Bindingtest1p2Impl.resetProcAddressTable(dynamicLookupHelper);
@@ -58,17 +58,16 @@ public class Test1p2LoadJNIAndImplLib extends BaseClass {
* Verifies the existence and creation of the generated class.
*/
@Test
- public void chapter02TestClassExist() throws Exception {
+ public void chapter00TestClassExist() throws Exception {
testClassExist("test1p2");
}
-
@SuppressWarnings("unused")
public static void main(final String args[]) throws Exception {
if( true ) {
- chapter01TestLoadLibrary();
+ chapter__TestLoadLibrary();
final Test1p2LoadJNIAndImplLib tst = new Test1p2LoadJNIAndImplLib();
- tst.chapter02TestClassExist();
+ tst.chapter00TestClassExist();
} else {
final String tstname = Test1p2LoadJNIAndImplLib.class.getName();
org.junit.runner.JUnitCore.main(tstname);
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2ProcAddressEmitter.java b/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2ProcAddressEmitter.java
index 49a1851..fa99915 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2ProcAddressEmitter.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/Test1p2ProcAddressEmitter.java
@@ -30,6 +30,7 @@ package com.jogamp.gluegen.test.junit.generation;
import java.io.IOException;
+import com.jogamp.gluegen.test.junit.generation.impl.Bindingtest1p1Impl;
import com.jogamp.gluegen.test.junit.generation.impl.Bindingtest1p2Impl;
import com.jogamp.common.os.NativeLibrary;
@@ -54,9 +55,9 @@ public class Test1p2ProcAddressEmitter extends BaseClass {
* Verifies loading of the new library.
*/
@BeforeClass
- public static void chapter01TestLoadLibrary() throws Exception {
+ public static void chapter__TestLoadLibrary() throws Exception {
BindingJNILibLoader.loadBindingtest1p2();
- dynamicLookupHelper = NativeLibrary.open("test1", Test1p2ProcAddressEmitter.class.getClassLoader(), true);
+ dynamicLookupHelper = NativeLibrary.open("test1", false, false, Test1p2ProcAddressEmitter.class.getClassLoader(), true);
Assert.assertNotNull("NativeLibrary.open(test1) failed", dynamicLookupHelper);
Bindingtest1p2Impl.resetProcAddressTable(dynamicLookupHelper);
@@ -66,7 +67,7 @@ public class Test1p2ProcAddressEmitter extends BaseClass {
* Verifies the existence and creation of the generated class.
*/
@Test
- public void chapter02TestClassExist() throws Exception {
+ public void chapter00TestClassExist() throws Exception {
testClassExist("test1p2");
}
@@ -79,6 +80,18 @@ public class Test1p2ProcAddressEmitter extends BaseClass {
}
/**
+ * Verifies if all generated static constant values are completed,
+ * and whether their value is as expected!
+ * <p>
+ * Covers all enumerates and defines.
+ * </p>
+ */
+ @Test
+ public void chapter01TestStaticConstants() throws Exception {
+ chapter01TestStaticConstants(new Bindingtest1p2Impl());
+ }
+
+ /**
* Verifies if all methods / signatures are properly generated,
* can be invoked and functions.
* This is a compilation (coverage) and runtime time (semantic) test.
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1-CustomJavaCode.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test1-CustomJavaCode.cfg
new file mode 100644
index 0000000..8d8f650
--- /dev/null
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1-CustomJavaCode.cfg
@@ -0,0 +1,7 @@
+
+@Override
+public int testDelegate(int v) {
+ return testDelegateOrigImpl(v) + 1;
+}
+
+
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..6c516c2 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,24 @@ 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*
+
+Opaque long _Crazy*;
+Opaque long ShortBlob.Cool
+
CustomCCode #include "test1.h"
Opaque long TK_Context
+RenameJavaSymbol DEFINE_01_EXT DEFINE_01
+RenameJavaSymbol testXID_EXT testXID
+
+DelegateImplementation testDelegate testDelegateOrigImpl
+IncludeAs CustomJavaCode Bindingtest1p1Impl test1-CustomJavaCode.cfg
+IncludeAs CustomJavaCode Bindingtest1p2Impl test1-CustomJavaCode.cfg
+
StructPackage TK_Dimension com.jogamp.gluegen.test.junit.generation
EmitStruct TK_Dimension
StructPackage TK_DimensionPair com.jogamp.gluegen.test.junit.generation
@@ -96,6 +110,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..0683600 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c
@@ -8,10 +8,67 @@
#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 testShortBlob(const ShortBlob *v) {
+ return v;
+}
+MYAPI const LPShortBlob0 MYAPIENTRY testLPShortBlob0(const LPShortBlob0 v) {
+ return v;
+}
+MYAPI LPShortBlob1 MYAPIENTRY testLPShortBlob1(LPShortBlob1 v) {
+ return v;
+}
+MYAPI const LPShortBlob2 MYAPIENTRY testLPShortBlob2(const LPShortBlob2 v) {
+ return v;
+}
+MYAPI LPShortBlob3 MYAPIENTRY testLPShortBlob3(LPShortBlob3 v) {
+ return v;
+}
+MYAPI const ShortBlobL1 * MYAPIENTRY testShortBlobL1(const ShortBlobL1 * v) {
+ return v;
+}
+MYAPI ShortBlobL2 * MYAPIENTRY testShortBlobL2(ShortBlobL2 * 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;
}
+MYAPI int32_t MYAPIENTRY testDelegate(int32_t v) {
+ return v;
+}
+
/**
* new blob sizeof(void*) filled w/ 0xDEADBEEF
*/
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..4896165 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h
@@ -28,12 +28,166 @@
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) - OpenSolaris: Native gcc error
+// typedef int XID_2; // Duplicate w/ incompatible type ERROR
+
+#define CL_INT_I0 10
+#define CL_INT_I1 11u
+#define CL_INT_I2 12U
+#define CL_INT_I3 0x0d
+#define CL_INT_I4 -14
+#define CL_INT_I5 -15u
+#define CL_INT_I6 -16U
+#define CL_INT_I7 -0x11U
+#define CL_INT_I8 +18
+#define CL_INT_I9 +19u
+#define CL_INT_IA +20U
+#define CL_INT_IB +0x15u
+#define CL_INT_IX 0xffffffffU
+
+enum CL_INT { ENUM_I0=10, ENUM_I1, ENUM_I2=+12U, ENUM_I3=0x0d, ENUM_I4=-14, ENUM_I5=-15u, ENUM_I6=-16U, ENUM_I7=0x11U,
+ ENUM_I8=+18, ENUM_I9=+19u, ENUM_IA, ENUM_IB=+0x15u, ENUM_IX=0xffffffffU };
+
+#define CL_LNG_L0 2147483648
+#define CL_LNG_L1 0x80000001ul
+#define CL_LNG_L2 2147483650UL
+#define CL_LNG_L3 0x80000003l
+#define CL_LNG_L4 -2147483652L
+#define CL_LNG_L5 -2147483653ul
+#define CL_LNG_L6 -2147483654lu
+#define CL_LNG_L7 -0x80000007UL
+#define CL_LNG_L8 +2147483656LU
+#define CL_LNG_L9 +2147483657uL
+#define CL_LNG_LA +2147483658lU
+#define CL_LNG_LB +0x8000000BLu
+#define CL_LNG_LX 0xffffffffffffffffUL
+
+#define CL_FLT_A0 0x1p127
+#define CL_FLT_A1 0x1p+127F
+#define CL_FLT_A2 +0x1p-127f
+#define CL_FLT_A3 -0.1
+#define CL_FLT_A4 0.2f
+#define CL_FLT_A5 0.3F
+#define CL_FLT_A6 .4
+#define CL_FLT_A7 1.0
+
+#define CL_DBL_B0 0x1.p127d
+#define CL_DBL_B1 0x1.p+127D
+#define CL_DBL_B2 +0x1.p-127d
+#define CL_DBL_B3 -0.1d
+#define CL_DBL_B4 0.2D
+#define CL_DBL_B5 .3D
+#define CL_DBL_B6 3.5e+38
+
+#define CL_FLT_MAX 0x1.fffffep127f
+#define CL_FLT_MIN 0x1.0p-126f
+#define CL_FLT_EPSILON 0x1.0p-23f
+
+#define CL_DBL_MAX 0x1.fffffffffffffp1023
+#define CL_DBL_MIN 0x1.0p-1022
+#define CL_DBL_EPSILON 0x1.0p-52
+
+#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_01 1235 // 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)
+
+#define NUMBER_ONE CONSTANT_ONE
+#define NUMBER_TWO ( NUMBER_ONE + NUMBER_ONE )
+#define NUMBER_FOUR ( NUMBER_ONE << NUMBER_TWO )
+#define NUMBER_FIVE ( ( CONSTANT_ONE << NUMBER_TWO ) + NUMBER_ONE )
+#define NUMBER_EIGHT ( NUMBER_TWO * NUMBER_TWO + ( NUMBER_ONE << NUMBER_TWO ) )
+#define NUMBER_NINE ( 2 * 2 + ( 1 << 2 ) + 1 )
+#define NUMBER_TEN ( NUMBER_EIGHT | NUMBER_TWO )
+
+enum NumberOps { ENUM_NUM_ONE = CONSTANT_ONE,
+ ENUM_NUM_TWO = 1+1,
+ ENUM_NUM_THREE,
+ ENUM_NUM_FOUR = ( ENUM_NUM_ONE << ENUM_NUM_TWO ),
+ ENUM_NUM_FIVE = ( CONSTANT_ONE << ENUM_NUM_TWO ) + ENUM_NUM_ONE,
+ ENUM_NUM_EIGHT = ( ENUM_NUM_TWO * ENUM_NUM_TWO + ( ENUM_NUM_ONE << ENUM_NUM_TWO ) ),
+ ENUM_NUM_NINE = ( 2 * 2 + ( 1 << 2 ) + 1 ),
+ ENUM_NUM_TEN = ENUM_NUM_EIGHT |
+ ENUM_NUM_TWO
+ };
+
+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
+
+struct _Crazy;
+
+typedef struct _ShortBlob {
+ uint8_t b1;
+ uint8_t b2;
+ struct _Crazy * Cool; // Opaque field!
+} ShortBlob, ShortBlob2, *LPShortBlob0; // Aliased to 'ShortBlob'
+typedef ShortBlob * LPShortBlob1; // Aliased to 'ShortBlob'
+typedef ShortBlob2 * LPShortBlob2; // Aliased to 'ShortBlob'
+typedef LPShortBlob1 LPShortBlob3; // Aliased to 'ShortBlob'
+typedef ShortBlob ShortBlobL1; // Aliased to 'ShortBlob'
+typedef ShortBlob2 ShortBlobL2; // 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 testShortBlob(const ShortBlob *v);
+MYAPI const LPShortBlob0 MYAPIENTRY testLPShortBlob0(const LPShortBlob0 v);
+MYAPI LPShortBlob1 MYAPIENTRY testLPShortBlob1(LPShortBlob1 v);
+MYAPI const LPShortBlob2 MYAPIENTRY testLPShortBlob2(const LPShortBlob2 v);
+MYAPI LPShortBlob3 MYAPIENTRY testLPShortBlob3(LPShortBlob3 v);
+MYAPI const ShortBlobL1 * MYAPIENTRY testShortBlobL1(const ShortBlobL1 *v);
+MYAPI ShortBlobL2 * MYAPIENTRY testShortBlobL2(ShortBlobL2 *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();
+MYAPI int32_t MYAPIENTRY testDelegate(int32_t v);
+
//
// Different pointer type tests ..
//
@@ -131,7 +285,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 +326,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;
@@ -246,9 +400,12 @@ typedef struct {
int32_t i2;
} TK_DimensionPair;
+// some implicity _local_ typedef -> public typedef checks
+typedef TK_Surface * (MYAPIENTRY* PFNCREATESURFACEPROC)();
+typedef void (MYAPIENTRY* PFNDESTROYSURFACEPROC)(TK_Surface * surface);
+
MYAPI TK_Surface * MYAPIENTRY createSurface();
MYAPI void MYAPIENTRY destroySurface(TK_Surface * surface);
-
MYAPI TK_ComplicatedSuperSet * MYAPIENTRY createComplicatedSuperSet();
MYAPI Bool MYAPIENTRY hasInitValues(TK_ComplicatedSuperSet * s);
MYAPI void MYAPIENTRY destroyComplicatedSuperSet(TK_ComplicatedSuperSet * s);
@@ -266,6 +423,13 @@ MYAPI TK_Dimension MYAPIENTRY addDimensions(const TK_Dimension s[TWO]);
MYAPI TK_Dimension MYAPIENTRY addDimensionPair(const TK_DimensionPair s);
MYAPI void MYAPIENTRY zeroDimensions(TK_Dimension s[2]);
+
+// some implicity _local_ typedef -> public typedef checks
+typedef void (MYAPIENTRY* PFNCOPYPRIMTODIMENSIONSPROC)(const int pos[2], const int size[2], TK_Dimension dest[1]);
+typedef int (MYAPIENTRY* PFNRGBATOINTPROC)(const char rgba[4]);
+typedef void (MYAPIENTRY* PFNINTTORGBAPROC)(int irgba, char rgbaSink[4]);
+typedef void (MYAPIENTRY* PFNADDBYTEPROC)(const char summands[2], char result[1]);
+
MYAPI void MYAPIENTRY copyPrimToDimensions(const int pos[2], const int size[2], TK_Dimension dest[1]);
MYAPI void MYAPIENTRY copyDimensionsToPrim(TK_Dimension dim, int dpos[2], int dsize[2]);
MYAPI int MYAPIENTRY rgbaToInt(const char rgba[4]);
@@ -296,7 +460,7 @@ typedef struct {
const int32_t structPointerCustomLenVal;
const TK_Dimension * structPointerOneElem;
- const TK_Context ctx;
+ TK_Context ctx;
const char modelNameArrayFixedLen[12]; /* 'Hello Array' len=11+1 */
const char * modelNamePointerCString; /* 'Hello CString' len=13+1 */
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg
index 6ef171b..b8582a8 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg
@@ -6,6 +6,8 @@ NativeOutputDir native
Extends Bindingtest1p1 Bindingtest1
+ExtendedInterfaceSymbolsIgnore ../build-temp/gensrc/classes/com/jogamp/gluegen/test/junit/generation/Bindingtest1.java
+
Include test1-common.cfg
Import com.jogamp.gluegen.test.junit.generation.Bindingtest1
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg
index 708bd26..eb9fdcf 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg
@@ -6,6 +6,8 @@ NativeOutputDir native
Extends Bindingtest1p2 Bindingtest1
+ExtendedInterfaceSymbolsIgnore ../build-temp/gensrc/classes/com/jogamp/gluegen/test/junit/generation/Bindingtest1.java
+
# Use a ProcAddressTable so we dynamically look up the routines
EmitProcAddressTable true
ProcAddressTableClassName Bindingtest1p2ProcAddressTable
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..84fc463
--- /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, null);
+ final FloatType f2 = new FloatType("float", null, 0, null);
+ final IntType i1 = new IntType("GLint", null, false, 0, null);
+ final IntType i2 = new IntType("int", null, false, 0, null);
+ 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);
+ }
+
+}
diff --git a/src/junit/com/jogamp/junit/sec/Applet01.java b/src/junit/com/jogamp/junit/sec/Applet01.java
index f028d7c..fd13207 100644
--- a/src/junit/com/jogamp/junit/sec/Applet01.java
+++ b/src/junit/com/jogamp/junit/sec/Applet01.java
@@ -201,7 +201,7 @@ public class Applet01 extends Applet {
final Uri absLib = libDir1.concat(Uri.Encoded.cast("natives/" + libBaseName));
Exception sec01 = null;
try {
- final NativeLibrary nlib = NativeLibrary.open(absLib.toFile().getPath(), cl);
+ final NativeLibrary nlib = NativeLibrary.open(absLib.toFile().getPath(), true, true, cl, true);
System.err.println("NativeLibrary: "+nlib);
} catch (final SecurityException e) {
sec01 = e;
diff --git a/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java b/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java
index b3a1877..27f8d0b 100644
--- a/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java
+++ b/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java
@@ -183,7 +183,7 @@ public class TestSecIOUtil01 extends SingletonJunitCase {
Exception se0 = null;
NativeLibrary nlib = null;
try {
- nlib = NativeLibrary.open(absLib.toFile().getPath(), cl);
+ nlib = NativeLibrary.open(absLib.toFile().getPath(), true, true, cl, true);
System.err.println("NativeLibrary: "+nlib);
} catch (final SecurityException e) {
se0 = e;
diff --git a/src/junit/com/jogamp/junit/util/SingletonJunitCase.java b/src/junit/com/jogamp/junit/util/SingletonJunitCase.java
index 7fb5fea..ad80bde 100644
--- a/src/junit/com/jogamp/junit/util/SingletonJunitCase.java
+++ b/src/junit/com/jogamp/junit/util/SingletonJunitCase.java
@@ -45,19 +45,29 @@ public abstract class SingletonJunitCase extends JunitTracer {
private static SingletonInstance singletonInstance = null; // system wide lock via port locking
private static final Object singletonSync = new Object(); // classloader wide lock
+ private static boolean enabled = true;
+
+ /**
+ * Default is {@code true}.
+ */
+ public static final void enableSingletonLock(final boolean v) {
+ enabled = v;
+ }
@BeforeClass
public static final void oneTimeSetUpSingleton() {
// one-time initialization code
synchronized( singletonSync ) {
- if( null == singletonInstance ) {
- System.err.println("++++ Test Singleton.ctor()");
- // singletonInstance = SingletonInstance.createFileLock(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_FILE);
- singletonInstance = SingletonInstance.createServerSocket(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_PORT);
- }
- System.err.println("++++ Test Singleton.lock()");
- if(!singletonInstance.tryLock(SINGLE_INSTANCE_LOCK_TO)) {
- throw new RuntimeException("Fatal: Could not lock single instance: "+singletonInstance.getName());
+ if( enabled ) {
+ if( null == singletonInstance ) {
+ System.err.println("++++ Test Singleton.ctor()");
+ // singletonInstance = SingletonInstance.createFileLock(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_FILE);
+ singletonInstance = SingletonInstance.createServerSocket(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_PORT);
+ }
+ System.err.println("++++ Test Singleton.lock()");
+ if(!singletonInstance.tryLock(SINGLE_INSTANCE_LOCK_TO)) {
+ throw new RuntimeException("Fatal: Could not lock single instance: "+singletonInstance.getName());
+ }
}
}
}
@@ -67,12 +77,14 @@ public abstract class SingletonJunitCase extends JunitTracer {
// one-time cleanup code
synchronized( singletonSync ) {
System.gc(); // force cleanup
- System.err.println("++++ Test Singleton.unlock()");
- singletonInstance.unlock();
- try {
- // allowing other JVM instances to pick-up socket
- Thread.sleep( SINGLE_INSTANCE_LOCK_POLL );
- } catch (final InterruptedException e) { }
+ if( enabled ) {
+ System.err.println("++++ Test Singleton.unlock()");
+ singletonInstance.unlock();
+ try {
+ // allowing other JVM instances to pick-up socket
+ Thread.sleep( SINGLE_INSTANCE_LOCK_POLL );
+ } catch (final InterruptedException e) { }
+ }
}
}
}
diff --git a/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java b/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java
index 78f4460..de850d0 100644
--- a/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java
+++ b/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java
@@ -86,16 +86,18 @@ public class VersionSemanticsUtil {
}
System.err.println("Semantic Version Test");
- System.err.println("Previous version: "+preVersionNumber+" - "+previousJar.toString());
- System.err.println("Current version: "+curVersionNumber+" - "+currentJar.toString());
- System.err.println("Compat. expected: "+expectedCompatibilityType);
- System.err.println("Compat. detected: "+detectedCompatibilityType);
- System.err.println("Compat. result: detected "+compS+" expected -> "+(compOK ? "OK" : "ERROR"));
+ System.err.println(" criteria: "+diffCriteria);
+ System.err.println(" Previous version: "+preVersionNumber+" - "+previousJar.toString());
+ System.err.println(" Current version: "+curVersionNumber+" - "+currentJar.toString());
+ System.err.println(" Field values changed: "+delta.fieldCompatChanged());
+ System.err.println(" Compat. expected: "+expectedCompatibilityType);
+ System.err.println(" Compat. detected: "+detectedCompatibilityType);
+ System.err.println(" Compat. result: detected "+compS+" expected -> "+(compOK ? "OK" : "ERROR"));
final String resS;
if( compOK ) {
- resS = "Current version "+curVersionNumber+" is "+expectedCompatibilityType+" to previous version "+preVersionNumber+", actually "+detectedCompatibilityType;
+ resS = " Current version "+curVersionNumber+" is "+expectedCompatibilityType+" to previous version "+preVersionNumber+", actually "+detectedCompatibilityType;
} else {
- resS = "Current version "+curVersionNumber+" is not "+expectedCompatibilityType+" to previous version "+preVersionNumber+", but "+detectedCompatibilityType;
+ resS = " Current version "+curVersionNumber+" is not "+expectedCompatibilityType+" to previous version "+preVersionNumber+", but "+detectedCompatibilityType;
}
System.err.println(resS);
System.err.printf("%n%n");
diff --git a/src/native/tinype/make.sh b/src/native/tinype/make.sh
new file mode 100755
index 0000000..b141066
--- /dev/null
+++ b/src/native/tinype/make.sh
@@ -0,0 +1,15 @@
+# /cygdrive/c/mingw/bin/gcc -nodefaultlibs -nostdlib -s -Os -mconsole -o tiny-conso-i386.exe tiny.c
+
+jardir=../../../build-win64
+
+/cygdrive/c/mingw/bin/gcc -nodefaultlibs -nostdlib -s -Os -mwindows -o tiny2-win32-i386.exe tiny2.c -lUser32
+java -cp "$jardir/test/build/gluegen-test.jar;$jardir/gluegen-rt.jar" com.jogamp.common.util.CustomDeflate tiny2-win32-i386.exe exe2-windows-i386.defl
+
+/cygdrive/c/mingw64/bin/gcc -nodefaultlibs -nostdlib -s -Os -mwindows -o tiny2-win32-x86_64.exe tiny2.c -lUser32
+java -cp "$jardir/test/build/gluegen-test.jar;$jardir/gluegen-rt.jar" com.jogamp.common.util.CustomDeflate tiny2-win32-x86_64.exe exe2-windows-x86_64.defl
+
+/cygdrive/c/mingw/bin/gcc -nodefaultlibs -nostdlib -s -Os -mwindows -o tiny-win32-i386.exe tiny.c
+java -cp "$jardir/test/build/gluegen-test.jar;$jardir/gluegen-rt.jar" com.jogamp.common.util.CustomDeflate tiny-win32-i386.exe exe-windows-i386.defl
+
+/cygdrive/c/mingw64/bin/gcc -nodefaultlibs -nostdlib -s -Os -mwindows -o tiny-win32-x86_64.exe tiny.c
+java -cp "$jardir/test/build/gluegen-test.jar;$jardir/gluegen-rt.jar" com.jogamp.common.util.CustomDeflate tiny-win32-x86_64.exe exe-windows-x86_64.defl
diff --git a/src/native/tinype/tiny.c b/src/native/tinype/tiny.c
new file mode 100644
index 0000000..6d2de3a
--- /dev/null
+++ b/src/native/tinype/tiny.c
@@ -0,0 +1,13 @@
+#undef UNICODE
+#define UNICODE
+#include <windows.h>
+
+// const char * id = "JogAmp Windows Universal Test PE Executable";
+
+// int __main()
+// int main()
+// int main( int argc, char* argv[] )
+int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
+{
+ return 0;
+}
diff --git a/src/native/tinype/tiny2.c b/src/native/tinype/tiny2.c
new file mode 100644
index 0000000..6330911
--- /dev/null
+++ b/src/native/tinype/tiny2.c
@@ -0,0 +1,15 @@
+#undef UNICODE
+#define UNICODE
+#include <windows.h>
+
+const wchar_t * id = L"JogAmp Windows Universal Test PE Executable";
+const wchar_t * cap = L"JogAmp";
+
+// int __main()
+// int main()
+// int main( int argc, char* argv[] )
+int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
+{
+ MessageBox(0, id, cap, MB_SETFOREGROUND | MB_OK);
+ return 0;
+}