summaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java')
-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
88 files changed, 7841 insertions, 2588 deletions
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();
}
}