From 405512e1c8a2e24834b0d057f0b020b4a0f4c25b Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 11 Mar 2015 08:48:36 +0100 Subject: Bug 1144 - Add 'DelegateImplementation', manually impl. may delegate to renamed original 'DelegateImplementation' is a variation of 'ManuallyImplement'. 'ManuallyImplement' emits the interface method, but suppresses the Java and native-code implementation. The latter shall be implemented manually by the user. 'DelegateImplementation' emits the interface method, and the _private_ renamed Java and native-code implementation. Both can be called from the manual user implementation, hence delegation. Configuration: DelegateImplementation I.e. delegation model shall apply to and the Java and native-code implementation renamed to . The user manual implementation of may delegate to . --- src/java/com/jogamp/gluegen/JavaConfiguration.java | 72 ++++++++++++++++++++++ src/java/com/jogamp/gluegen/JavaEmitter.java | 23 ++++--- src/java/com/jogamp/gluegen/MethodBinding.java | 20 +++++- 3 files changed, 106 insertions(+), 9 deletions(-) (limited to 'src/java/com') diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java index 969eaaf..987d27a 100644 --- a/src/java/com/jogamp/gluegen/JavaConfiguration.java +++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java @@ -159,6 +159,7 @@ public class JavaConfiguration { private boolean forceUseNIODirectOnly4All = false; private final Set useNIODirectOnly = new HashSet(); private final Set manuallyImplement = new HashSet(); + private final Map delegatedImplementation = new HashMap(); private final Set manualStaticInitCall = new HashSet(); private final Set forceStaticInitCode = new HashSet(); private final Map> customJavaCode = new HashMap>(); @@ -875,6 +876,54 @@ public class JavaConfiguration { } } + /** + * 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}", functionName); + 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. + *

+ * {@code DelegateImplementation } + *

+ *

+ * The interface is emitted unchanged. + *

+ *

+ * 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}. + *

+ *

+ * 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. + *

+ */ + public String getDelegatedImplementation(final AliasedSymbol symbol) { + final String name = symbol.getName(); + final Set aliases = symbol.getAliasedNames(); + + String res = delegatedImplementation.get(name); + if( null == res ) { + res = oneInMap(delegatedImplementation, aliases); + if( null == res ) { + return null; + } + } + LOG.log(INFO, getASTLocusTag(symbol), "DelegatedImplementation: {0}", symbol.getAliasedString()); + return res; + } + /** * Variant of {@link #shouldIgnoreInInterface(AliasedSymbol)}, * where this method only considers the {@link AliasedSymbol#getName() current-name} @@ -1078,6 +1127,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; @@ -1265,6 +1324,8 @@ public class JavaConfiguration { readRenameJavaType(tok, filename, lineNo); } 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")) { @@ -1798,6 +1859,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(); diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java index fa4ecab..2601929 100644 --- a/src/java/com/jogamp/gluegen/JavaEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaEmitter.java @@ -568,12 +568,6 @@ public class JavaEmitter implements GlueEmitter { return; } - final MethodAccess accessControl = cfg.accessControl(binding.getName()); - // We should not emit anything except public APIs into interfaces - if (signatureOnly && (accessControl != PUBLIC)) { - return; - } - // 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 @@ -596,6 +590,20 @@ public class JavaEmitter implements GlueEmitter { final boolean emitBody = !signatureOnly && needsBody; final boolean isNativeMethod = !isUnimplemented && !needsBody && !signatureOnly; + 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 && PUBLIC != accessControl ) { + return; + } + final PrintWriter writer = ((signatureOnly || cfg.allStatic()) ? javaWriter() : javaImplWriter()); final JavaMethodBindingEmitter emitter = @@ -2801,8 +2809,9 @@ public class JavaEmitter implements GlueEmitter { javaArgumentTypes.add(mappedType); //System.out.println("During binding of [" + sym + "], added mapping from C type: " + cArgType + " to Java type: " + mappedType); } + final String delegationImplName = null == containingType && null == containingCType ? + cfg.getDelegatedImplementation(sym) : null; final MethodBinding mb = new MethodBinding(sym, delegationImplName, - final MethodBinding mb = new MethodBinding(sym, javaReturnType, javaArgumentTypes, containingType, containingCType); mangleBinding(mb); diff --git a/src/java/com/jogamp/gluegen/MethodBinding.java b/src/java/com/jogamp/gluegen/MethodBinding.java index 5b0290a..278fea0 100644 --- a/src/java/com/jogamp/gluegen/MethodBinding.java +++ b/src/java/com/jogamp/gluegen/MethodBinding.java @@ -52,6 +52,7 @@ import java.util.List; public class MethodBinding { private final FunctionSymbol sym; + private final String delegationImplName; private final JavaType containingType; private final Type containingCType; private String nativeName; @@ -77,6 +78,7 @@ public class MethodBinding { */ public MethodBinding(final MethodBinding bindingToCopy) { this.sym = bindingToCopy.sym; + this.delegationImplName = bindingToCopy.delegationImplName; this.containingType = bindingToCopy.containingType; this.containingCType = bindingToCopy.containingCType; @@ -105,11 +107,13 @@ public class MethodBinding { *

*/ public MethodBinding(final FunctionSymbol sym, + final String delegationImplName, final JavaType javaReturnType, final List javaArgumentTypes, final JavaType containingType, final Type containingCType) { this.sym = sym; + this.delegationImplName = delegationImplName; this.containingType = containingType; this.containingCType = containingCType; @@ -173,16 +177,28 @@ public class MethodBinding { public String getName() { return sym.getName(); } + /** + * 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; + } + /** 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. + * which is the current {@link FunctionSymbol#getName() aliased} API name per default, + * or the {@link #getDelegationImplName() delegation} name. + * @see #getDelegationImplName() */ public String getImplName() { - return sym.getName(); + return null != delegationImplName ? delegationImplName : sym.getName(); } /** * Returns the {@link FunctionSymbol}'s name for the native function -- cgit v1.2.3