diff options
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/GLPbufferImpl.java')
0 files changed, 0 insertions, 0 deletions
![]() |
index : jogl.git | |
JOGL repository on http://jogamp.org/ ; |
aboutsummaryrefslogtreecommitdiffstats |
/*
* Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
* Copyright (c) 2003 Sun Microsystems, Inc. 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 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.
*
* 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.
*
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
*
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
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.regex.*;
import com.jogamp.gluegen.jgram.*;
import com.jogamp.gluegen.cgram.types.*;
import static java.util.logging.Level.*;
import static com.jogamp.gluegen.JavaEmitter.MethodAccess.*;
import static com.jogamp.gluegen.JavaEmitter.EmissionStyle.*;
/** Parses and provides access to the contents of .cfg files for the
JavaEmitter. */
public class JavaConfiguration {
private int nestedReads;
private String libraryOnLoadName;
private String packageName;
private String implPackageName;
private String className;
private String implClassName;
protected final LoggerIf LOG;
public static String NEWLINE = System.getProperty("line.separator");
/**
* Root directory for the hierarchy of generated java classes. Default is
* working directory.
*/
private String javaOutputDir = ".";
/**
* Top output root directory for all generated files. Default is null, ie not to use it.
*/
private String outputRootDir = null;
/**
* Directory into which generated native JNI code will be written. Default
* is current working directory.
*/
private String nativeOutputDir = ".";
/**
* If true, then each native *.c and *.h file will be generated in the
* directory nativeOutputDir/packageAsPath(packageName). Default is false.
*/
private boolean nativeOutputUsesJavaHierarchy;
/**
* If true, then the comment of a native method binding will include a @native tag
* to allow taglets to augment the javadoc with additional information regarding
* the mapped C function. Defaults to false.
*/
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
* the implementation (ImplOnly).
*/
private EmissionStyle emissionStyle = AllStatic;
/**
* List of imports to emit at the head of the output files.
*/
private final List<String> imports = new ArrayList<String>();
/**
* The package in which the generated glue code expects to find its
* run-time helper classes (Buffers, Platform,
* StructAccessor). Defaults to "com.jogamp.gluegen.runtime".
*/
private String gluegenRuntimePackage = "com.jogamp.gluegen.runtime";
/**
* The kind of exception raised by the generated code if run-time
* checks fail. Defaults to RuntimeException.
*/
private String runtimeExceptionType = "RuntimeException";
private String unsupportedExceptionType = "UnsupportedOperationException";
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 Set<String> returnsStringOnly = new HashSet<String>();
private final Map<String, JavaType> returnsOpaqueJType = new HashMap<String, JavaType>();
private final Map<String, String> returnedArrayLengths = new HashMap<String, String>();
private final Set<String> maxOneElement = new HashSet<String>();
/**
* Key is function that has some byte[] or short[] arguments that should be
* converted to String args; value is List of Integer argument indices
*/
private final Map<String, List<Integer>> argumentsAreString = new HashMap<String, List<Integer>>();
/** JavaCallback configuration definition (static) */
public static class JavaCallbackDef {
final String cbFuncTypeName;
final int cbFuncUserParamIdx;
final String setFuncName;
final List<Integer> setFuncKeyIndices = new ArrayList<Integer>();
final String setFuncKeyClassName; // optional
JavaCallbackDef(final String cbFuncTypeName, final int cbFuncUserParamIdx, final String setFuncName, final String setFuncKeyClassName) {
this.cbFuncTypeName = cbFuncTypeName;
this.cbFuncUserParamIdx = cbFuncUserParamIdx;
this.setFuncName = setFuncName;
this.setFuncKeyClassName = setFuncKeyClassName;
}
@Override
public String toString() {
return String.format("JavaCallbackDef[cbFunc[type %s, userParamIdx %d], set[%s, keys %s, KeyClass %s]]",
cbFuncTypeName, cbFuncUserParamIdx, setFuncName, setFuncKeyIndices.toString(), setFuncKeyClassName);
}
}
private final List<JavaCallbackDef> javaCallbackList = new ArrayList<JavaCallbackDef>();
private final Map<String, JavaCallbackDef> javaCallbackSetFuncToDef = new HashMap<String, JavaCallbackDef>();
private final Set<String> extendedIntfSymbolsIgnore = new HashSet<String>();
private final Set<String> extendedIntfSymbolsOnly = new HashSet<String>();
private final Set<String> extendedImplSymbolsIgnore = new HashSet<String>();
private final Set<String> extendedImplSymbolsOnly = new HashSet<String>();
private final Set<Pattern> ignores = new HashSet<Pattern>();
private final Map<String, Pattern> ignoreMap = new HashMap<String, Pattern>();
private final Set<Pattern> ignoreNots = new HashSet<Pattern>();
private final Set<Pattern> unignores = new HashSet<Pattern>();
private final Set<Pattern> unimplemented = new HashSet<Pattern>();
private boolean forceUseNIOOnly4All = false;
private final Set<String> useNIOOnly = new HashSet<String>();
private boolean forceUseNIODirectOnly4All = false;
private final Set<String> useNIODirectOnly = new HashSet<String>();
private final Set<String> immutableAccessSymbols = new HashSet<String>();
private final Set<String> manuallyImplement = new HashSet<String>();
private final Map<String, String> delegatedImplementation = new HashMap<String, String>();
private final Map<String, List<String>> customJavaCode = new HashMap<String, List<String>>();
private final Map<String, List<String>> customJNICode = new HashMap<String, List<String>>();
private final Map<String, List<String>> classJavadoc = new HashMap<String, List<String>>();
private final Map<String, List<String>> methodJavadoc = new HashMap<String, List<String>>();
private final Map<String, String> structPackages = new HashMap<String, String>();
private final List<String> customCCode = new ArrayList<String>();
private final List<String> forcedStructs = new ArrayList<String>();
private final Map<String, String> structMachineDataInfoIndex = new HashMap<String, String>();
private final Map<String, String> returnValueCapacities = new HashMap<String, String>();
private final Map<String, String> returnValueLengths = new HashMap<String, String>();
private final Map<String, List<String>> temporaryCVariableDeclarations = new HashMap<String, List<String>>();
private final Map<String, List<String>> temporaryCVariableAssignments = new HashMap<String, List<String>>();
private final Map<String, List<String>> extendedInterfaces = new HashMap<String, List<String>>();
private final Map<String, List<String>> implementedInterfaces = new HashMap<String, List<String>>();
private final Map<String, String> parentClass = new HashMap<String, String>();
private final Map<String, String> javaTypeRenames = new HashMap<String, String>();
private final Map<String, String> javaSymbolRenames = new HashMap<String, String>();
private final Map<String, Set<String>> javaRenamedSymbols = new HashMap<String, Set<String>>();
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
*/
public final void read(final String filename) throws IOException {
read(filename, null);
}
/** Reads the specified file, treating each line as if it started with the
specified string.
@param filename path to file that should be read
@param linePrefix if not null, treat each line read as if it were
prefixed with the specified string.
*/
protected final void read(final String filename, final String linePrefix) throws IOException {
final File file = new File(filename);
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
}
catch (final FileNotFoundException fnfe) {
throw new RuntimeException("Could not read file \"" + file + "\"", fnfe);
}
int lineNo = 0;
String line = null;
final boolean hasPrefix = linePrefix != null && linePrefix.length() > 0;
try {
++nestedReads;
while ((line = reader.readLine()) != null) {
++lineNo;
if (hasPrefix) {
line = linePrefix + " " + line;
}
if (line.trim().startsWith("#")) {
// comment line
continue;
}
final StringTokenizer tok = new StringTokenizer(line);
if (tok.hasMoreTokens()) {
// always reset delimiters in case of CustomJavaCode, etc.
final String cmd = tok.nextToken(" \t\n\r\f");
dispatch(cmd, tok, file, filename, lineNo);
}
}
reader.close();
} finally {
--nestedReads;
}
if (nestedReads == 0) {
if (allStatic() && implClassName != null) {
throw new IllegalStateException("Error in configuration file \"" + filename + "\": Cannot use " +
"directive \"ImplJavaClass\" in conjunction with " +
"\"Style AllStatic\"");
}
if (className == null && (emissionStyle() != ImplOnly)) {
// throw new RuntimeException("Output class name was not specified in configuration file \"" + filename + "\"");
}
if (packageName == null && (emissionStyle() != ImplOnly)) {
throw new RuntimeException("Output package name was not specified in configuration file \"" + filename + "\"");
}
if (allStatic()) {
implClassName = className;
// If we're using the "Style AllStatic" directive, then the
// implPackageName is the same as the regular package name
implPackageName = packageName;
} else {
if (implClassName == null) {
// implClassName defaults to "<className>Impl" if ImplJavaClass
// directive is not used
if (className == null) {
throw new RuntimeException("If ImplJavaClass is not specified, must specify JavaClass");
}
implClassName = className + "Impl";
}
if (implPackageName == null) {
// implPackageName defaults to "<packageName>.impl" if ImplPackage
// directive is not used
if (packageName == null) {
throw new RuntimeException("If ImplPackageName is not specified, must specify PackageName");
}
implPackageName = packageName + ".impl";
}
}
}
}
public void setOutputRootDir(final String s) { outputRootDir=s; }
/** Returns the library basename used to {@link CCodeUnit#emitJNIOnLoadJNIEnvCode(String)}. */
public String libraryOnLoadName() {
return libraryOnLoadName;
}
/** Returns the package name parsed from the configuration file. */
public String packageName() {
return packageName;
}
/** Returns the implementation package name parsed from the configuration file. */
public String implPackageName() {
return implPackageName;
}
/** Returns the class name parsed from the configuration file. */
public String className() {
return className;
}
/** Returns the implementation class name parsed from the configuration file. */
public String implClassName() {
return implClassName;
}
public boolean structsOnly() {
return className == null && implClassName == null;
}
/** Returns the Java code output directory parsed from the configuration file. */
public String javaOutputDir() {
return (null != outputRootDir) ? (outputRootDir + "/" + javaOutputDir) : javaOutputDir;
}
/** Returns the native code output directory parsed from the configuration file. */
public String nativeOutputDir() {
return (null != outputRootDir) ? (outputRootDir + "/" + nativeOutputDir) : nativeOutputDir;
}
/** Returns whether the native code directory structure mirrors the Java hierarchy. */
public boolean nativeOutputUsesJavaHierarchy() {
return nativeOutputUsesJavaHierarchy;
}
/** Returns whether the comment of a native method binding should include a @native tag. */
public boolean tagNativeBinding() {
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;
}
/**
* Returns the access control for the given method-name
* or fully qualified class-name.
*/
public MethodAccess accessControl(final String name) {
final MethodAccess ret = accessControl.get(name);
if (ret != null) {
return ret;
}
// 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,
StructAccessor). Defaults to "com.jogamp.gluegen.runtime". */
public String gluegenRuntimePackage() {
return gluegenRuntimePackage;
}
/** Returns the kind of exception to raise if run-time checks fail in the generated code. */
public String runtimeExceptionType() {
return runtimeExceptionType;
}
/** Returns the kind of exception to raise if run-time checks fail in the generated code. */
public String unsupportedExceptionType() {
return unsupportedExceptionType;
}
/** Returns the list of imports that should be emitted at the top of each .java file. */
public List<String> imports() {
return imports;
}
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) {
// 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 + ", " + type.getDebugString());
final int pointerDepth = type.pointerDepth();
for (int i = 0; i <= pointerDepth; i++) {
String name = type.getName();
if (DEBUG_TYPE_INFO) {
System.err.printf(" [%2d] Name = %s%n", i, name);
System.err.printf(" [%2d] Type = %s, pointerDepth %d, %s%n", i, type, type.pointerDepth(), type.getDebugString());
}
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.printf(" [A][%2d] name %s%n", i, name);
System.err.printf(" [A][%2d] info %s%n", i, info.toString());
System.err.printf(" [A][%2d] res %s%n", i, res.toString());
}
return res;
}
}
if (type.isCompound()) {
// Try struct name as well
name = type.asCompound().getStructName();
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.printf(" [A][%2d] name %s%n", i, name);
System.err.printf(" [A][%2d] info %s%n", i, info.toString());
System.err.printf(" [A][%2d] res %s%n", i, res.toString());
}
return res;
}
}
}
if (type.isPointer()) {
type = type.asPointer().getTargetType();
}
}
if (DEBUG_TYPE_INFO) {
System.err.println(" [X] NULL");
}
return null;
}
// Helper functions for above
private TypeInfo closestTypeInfo(final String name, final int pointerDepth) {
TypeInfo info = typeInfoMap.get(name);
TypeInfo closest = null;
while (info != null) {
if (DEBUG_TYPE_INFO) {
System.err.println(" Checking TypeInfo for " + name + " at pointerDepth " + pointerDepth);
}
if (info.pointerDepth() <= pointerDepth && (closest == null || info.pointerDepth() > closest.pointerDepth())) {
if (DEBUG_TYPE_INFO) {
System.err.println(" Accepted");
}
closest = info;
}
info = info.next();
}
return closest;
}
// Promotes a TypeInfo to a higher pointer type (if necessary)
private TypeInfo promoteTypeInfo(final TypeInfo info, final int numPointersStripped) {
final int pd = info.pointerDepth();
int diff = numPointersStripped - pd;
if (diff == 0) {
return info;
}
if (diff < 0) {
throw new RuntimeException("TypeInfo for " + info.name() + " and pointerDepth " +
info.pointerDepth() + " should not have matched for depth " +
numPointersStripped);
}
Class<?> c = info.javaType().getJavaClass();
// Handle single-pointer stripping for types compatible with C
// integral and floating-point types specially so we end up
// generating NIO variants for these
if (diff == 1) {
JavaType jt = null;
if (c == Boolean.TYPE) jt = JavaType.createForCCharPointer();
else if (c == Byte.TYPE) jt = JavaType.createForCCharPointer();
else if (c == Short.TYPE) jt = JavaType.createForCShortPointer();
else if (c == Integer.TYPE) jt = JavaType.createForCInt32Pointer();
else if (c == Long.TYPE) jt = JavaType.createForCInt64Pointer();
else if (c == Float.TYPE) jt = JavaType.createForCFloatPointer();
else if (c == Double.TYPE) jt = JavaType.createForCDoublePointer();
if (jt != null)
return new TypeInfo(info.name(), numPointersStripped, jt);
}
while (diff > 0) {
c = Array.newInstance(c, 0).getClass();
--diff;
}
return new TypeInfo(info.name(),
numPointersStripped,
JavaType.createForClass(c));
}
/** 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 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());
}
/** Indicates whether the given function (which returns a
<code>char*</code> in C) should be translated as returning a
<code>java.lang.String</code> only. Excluding other variants for struct field access. */
public boolean returnsStringOnly(final String functionName) {
return returnsStringOnly.contains(functionName);
}
/** Returns the list of all configured JavaCallback definitions. */
public List<JavaCallbackDef> getJavaCallbackList() {
return javaCallbackList;
}
/** Returns the configured JavaCallback definition mapped to the JavaCallback-Set-Function name. */
public JavaCallbackDef javaCallbackSetFuncToDef(final AliasedSymbol symbol) {
final String name = symbol.getName();
final Set<String> aliases = symbol.getAliasedNames();
JavaCallbackDef res = javaCallbackSetFuncToDef.get(name);
if( null == res ) {
res = oneInMap(javaCallbackSetFuncToDef, aliases);
}
return res;
}
/**
* Returns a MessageFormat string of the Java expression calculating
* the number of elements in the returned array from the specified function
* name or struct-field array-size. The literal <code>1</code> indicates a constant single object.
* <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>
* <p>
* In case of struct fields, this array length will also be used
* for the native C function, i.e. multiplied w/ <code>sizeof(C-Type)</code>
* and passed down to native code, <b>if</b> not overriden by
* either {@link #returnValueCapacity(String)} or {@link #returnValueLength(String)}!
* </p>
*/
public String returnedArrayLength(final String symbol) {
return returnedArrayLengths.get(symbol);
}
/**
* Indicates whether the given symbol covers no or one single object.
* This is useful for struct-field pointer, indicating a null value
* holding no object or at most referincing memory for one single object.
*/
public boolean maxOneElement(final String symbol) {
return maxOneElement.contains(symbol);
}
/** Returns a list of <code>Integer</code>s which are the indices of <code>const char*</code>
arguments that should be converted to <code>String</code>s. Returns null if there are no
such hints for the given function name. */
public List<Integer> stringArguments(final String functionName) {
return argumentsAreString.get(functionName);
}
/** Returns a list of <code>Integer</code>s which are the indices of <code>const char*</code>
arguments that should be converted to <code>String</code>s. Returns null if there are no
such hints for the given function alias symbol. */
public List<Integer> stringArguments(final AliasedSymbol symbol) {
final String name = symbol.getName();
final Set<String> aliases = symbol.getAliasedNames();
List<Integer> res = argumentsAreString.get(name);
if( null == res ) {
res = oneInMap(argumentsAreString, aliases);
if( null == res ) {
return null;
}
}
LOG.log(INFO, getASTLocusTag(symbol), "ArgumentsAreString: {0} -> {1}", symbol, res);
return res;
}
public boolean isForceUsingNIOOnly4All() { return forceUseNIOOnly4All; }
public void addUseNIOOnly(final String fname ) {
useNIOOnly.add(fname);
}
/** Returns true if the given function should only create a java.nio
variant, and no array variants, for <code>void*</code> and other
C primitive pointers. NIO only still allows usage of array backed not direct Buffers. */
public boolean useNIOOnly(final String functionName) {
return useNIODirectOnly(functionName) || forceUseNIOOnly4All || useNIOOnly.contains(functionName);
}
public void addUseNIODirectOnly(final String fname ) {
useNIODirectOnly.add(fname);
}
/** Returns true if the given function should only create a java.nio
variant, and no array variants, for <code>void*</code> and other
C primitive pointers. NIO direct only does only allow direct Buffers.
Implies useNIOOnly !
*/
public boolean useNIODirectOnly(final String functionName) {
return forceUseNIODirectOnly4All || useNIODirectOnly.contains(functionName);
}
/** Returns a list of Strings containing user-implemented code for
the given Java type name (not fully-qualified, only the class
name); returns either null or an empty list if there is no
custom code for the class. */
public List<String> customJavaCodeForClass(final String className) {
List<String> res = customJavaCode.get(className);
if (res == null) {
res = new ArrayList<String>();
customJavaCode.put(className, res);
}
return res;
}
/** Returns a list of Strings containing user-implemented JNI code for
the given Java type name (not fully-qualified, only the class
name); returns either null or an empty list if there is no
custom code for the class. */
public List<String> customJNICodeForClass(final String className) {
List<String> res = customJNICode.get(className);
if (res == null) {
res = new ArrayList<String>();
customJNICode.put(className, res);
}
return res;
}
public List<String> javadocForMethod(final String methodName) {
List<String> res = methodJavadoc.get(methodName);
if (res == null) {
res = new ArrayList<String>();
methodJavadoc.put(methodName, res);
}
return res;
}
/** Returns a list of Strings containing Javadoc documentation for
the given Java type name (not fully-qualified, only the class
name); returns either null or an empty list if there is no
Javadoc documentation for the class. */
public List<String> javadocForClass(final String className) {
List<String> res = classJavadoc.get(className);
if (res == null) {
res = new ArrayList<String>();
classJavadoc.put(className, res);
}
return res;
}
/** Returns the package into which to place the glue code for
accessing the specified struct. Defaults to emitting into the
regular package (i.e., the result of {@link #packageName}). */
public String packageForStruct(final String structName) {
String res = structPackages.get(structName);
if (res == null) {
res = packageName;
}
return res;
}
/** Returns, as a List of Strings, the custom C code to be emitted
along with the glue code for the main class. */
public List<String> customCCode() {
return customCCode;
}
/** Returns, as a List of Strings, the structs for which glue code
emission should be forced. */
public List<String> forcedStructs() {
return forcedStructs;
}
/**
* Returns a MessageFormat string of the Java code defining {@code mdIdx},
* i.e. the index of the static MachineDescriptor index for structs.
* <p>
* If undefined, code generation uses the default expression:
* <pre>
* private static final int mdIdx = MachineDataInfoRuntime.getStatic().ordinal();
* </pre>
* </p>
*/
public String returnStructMachineDataInfoIndex(final String structName) {
return structMachineDataInfoIndex.get(structName);
}
/**
* Returns a MessageFormat string of the C expression calculating
* the capacity of the java.nio.ByteBuffer being returned from a
* native method, or null if no expression has been specified.
* <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 String returnValueCapacity(final String functionName) {
return returnValueCapacities.get(functionName);
}
/**
* Returns a MessageFormat string of the C expression calculating
* the length of the array being returned from a native method.
* <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 String returnValueLength(final String symbol) {
return returnValueLengths.get(symbol);
}
/** Returns a List of Strings of expressions declaring temporary C
variables in the glue code for the specified function. */
public List<String> temporaryCVariableDeclarations(final String functionName) {
return temporaryCVariableDeclarations.get(functionName);
}
/** Returns a List of Strings of expressions containing assignments
to temporary C variables in the glue code for the specified
function. */
public List<String> temporaryCVariableAssignments(final String functionName) {
return temporaryCVariableAssignments.get(functionName);
}
/** Returns a List of Strings indicating the interfaces the passed
interface should declare it extends. May return null or a list
of zero length if there are none. */
public List<String> extendedInterfaces(final String interfaceName) {
List<String> res = extendedInterfaces.get(interfaceName);
if (res == null) {
res = new ArrayList<String>();
extendedInterfaces.put(interfaceName, res);
}
return res;
}
/** Returns a List of Strings indicating the interfaces the passed
class should declare it implements. May return null or a list
of zero length if there are none. */
public List<String> implementedInterfaces(final String className) {
List<String> res = implementedInterfaces.get(className);
if (res == null) {
res = new ArrayList<String>();
implementedInterfaces.put(className, res);
}
return res;
}
/** Returns a List of Strings indicating the interfaces the passed
class should declare it implements. May return null or a list
of zero length if there are none. */
public String extendedParentClass(final String className) {
return parentClass.get(className);
}
public void logIgnoresOnce() {
if(!loggedIgnores) {
loggedIgnores = true;
logIgnores();
}
}
private static boolean loggedIgnores = false;
public void logIgnores() {
LOG.log(INFO, "Extended Intf: {0}", extendedIntfSymbolsIgnore.size());
for (final String str : extendedIntfSymbolsIgnore) {
LOG.log(INFO, "\t{0}", str);
}
LOG.log(INFO, "Extended Impl: {0}", extendedImplSymbolsIgnore.size());
for (final String str : extendedImplSymbolsIgnore) {
LOG.log(INFO, "\t{0}", str);
}
LOG.log(INFO, "Ignores (All): {0}", ignores.size());
for (final Pattern pattern : ignores) {
LOG.log(INFO, "\t{0}", pattern);
}
}
public void logRenamesOnce() {
if(!loggedRenames) {
loggedRenames = true;
logRenames();
}
}
private static boolean loggedRenames = false;
public void logRenames() {
LOG.log(INFO, "Symbol Renames: {0}", javaSymbolRenames.size());
for (final String key : javaSymbolRenames.keySet()) {
LOG.log(INFO, "\t{0} -> {1}", key, javaSymbolRenames.get(key));
}
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) {
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'
*/
public static String canonicalStructFieldSymbol(final String structName, final String fieldName) {
return structName+"."+fieldName;
}
/**
* Returns true if the glue code for the given aliased symbol
* shall produce code for immutable access only.
* <p>
* This is implemented for whole struct-type symbols or struct-field names,
* where no setter methods will be produced if marked immutable.
* </p>
*/
public final boolean immutableAccess(final AliasedSymbol symbol) {
final String name = symbol.getName();
final Set<String> aliases = symbol.getAliasedNames();
if ( immutableAccessSymbols.contains( name ) ||
oneInSet(immutableAccessSymbols, aliases)
)
{
LOG.log(INFO, getASTLocusTag(symbol), "Immutable access: {0}", symbol);
return true;
}
return false;
}
/**
* Returns true if the glue code for the given symbol
* shall produce code for immutable access only.
* <p>
* This is implemented for whole struct-type symbols or struct-field names,
* where no setter methods will be produced if marked immutable.
* </p>
*/
public final boolean immutableAccess(final String symbol) {
if ( immutableAccessSymbols.contains( symbol ) ) {
LOG.log(INFO, "Immutable access: {0}", symbol);
return true;
}
return false;
}
/**
* 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>
* 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 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;
}
}
/**
* 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;
}
}
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 the opaque {@link JavaType} for the given function {@link AliasedSymbol}
* or {@code null} if not opaque.
* <p>
* {@code ReturnsOpaque <Primitive Java Type> <Function Name>}
* </p>
*/
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;
}
/**
* 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);
}
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 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;
}
// 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);
}
/**
* 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;
}
// 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 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;
}
}
// 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;
}
}
}
}
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 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 a set of aliased-name for comment in docs.
* <p>
* This is usually {@link AliasedSymbol#addAliasedName(String)},
* however an implementation may choose otherwise.
* </p>
* @param symbol the aliased symbol to retrieve the aliases
* @return set of aliased-names or {@code null}.
*/
public Set<String> getAliasedDocNames(final AliasedSymbol symbol) {
return symbol.getAliasedNames();
}
/** Returns a replacement name for this type, which should be the
name of a Java wrapper class for a C struct, or the name
unchanged if no RenameJavaType directive was specified for this
type. */
public String renameJavaType(final String javaTypeName) {
final String rename = javaTypeRenames.get(javaTypeName);
if (rename != null) {
return rename;
}
return javaTypeName;
}
/** Returns a replacement name for this function or definition which
should be used as the Java name for the bound method or
constant. If a function, it still calls the originally-named C
function under the hood. Returns null if this symbol has not
been explicitly renamed. */
public String getJavaSymbolRename(final String origName) {
if( LOG.isLoggable(INFO) ) {
logRenamesOnce();
}
return javaSymbolRenames.get(origName);
}
/** Returns a set of replaced names to the given <code>aliasedName</code>. */
public Set<String> getRenamedJavaSymbols(final String aliasedName) {
return javaRenamedSymbols.get(aliasedName);
}
/** Programmatically adds a rename directive for the given symbol. */
public void addJavaSymbolRename(final String origName, final String 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!");
}
Set<String> origNames = javaRenamedSymbols.get(newName);
if(null == origNames) {
origNames = new HashSet<String>();
javaRenamedSymbols.put(newName, origNames);
}
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;
}
/** Returns true if an interface should be emitted during glue code generation. */
public boolean emitInterface() {
return emissionStyle() == InterfaceAndImpl || emissionStyle() == InterfaceOnly;
}
/** Returns true if an implementing class should be emitted during glue code generation. */
public boolean emitImpl() {
return emissionStyle() == AllStatic || emissionStyle() == InterfaceAndImpl || emissionStyle() == ImplOnly;
}
/** Returns a list of Strings which should be emitted as a prologue
to the body for the Java-side glue code for the given method.
Returns null if no prologue was specified. */
public List<String> javaPrologueForMethod(final MethodBinding binding,
final boolean forImplementingMethodCall,