diff options
-rwxr-xr-x | doc/manual/index.html | 102 | ||||
-rw-r--r-- | src/java/com/sun/gluegen/CMethodBindingEmitter.java | 25 | ||||
-rw-r--r-- | src/java/com/sun/gluegen/FunctionEmitter.java | 17 | ||||
-rw-r--r-- | src/java/com/sun/gluegen/JavaConfiguration.java | 57 | ||||
-rw-r--r-- | src/java/com/sun/gluegen/JavaEmitter.java | 6 | ||||
-rw-r--r-- | src/java/com/sun/gluegen/JavaMethodBindingEmitter.java | 60 | ||||
-rwxr-xr-x | src/java/com/sun/gluegen/opengl/GLConfiguration.java | 20 | ||||
-rw-r--r-- | src/java/com/sun/gluegen/runtime/BufferFactory.java | 39 |
8 files changed, 195 insertions, 131 deletions
diff --git a/doc/manual/index.html b/doc/manual/index.html index 2e4ed84..cbeea8e 100755 --- a/doc/manual/index.html +++ b/doc/manual/index.html @@ -1,3 +1,9 @@ +<HTML> +<HEAD> +<TITLE>GlueGen Manual</TITLE> +</HEAD> +<BODY> + <H1>GlueGen Manual</H1> <H2> Table of Contents </H2> @@ -23,6 +29,7 @@ Chapter 2 - Using GlueGen <LI> <a href = "#SecStub">Stub Headers</a> <LI> <a href = "#Sec32">32- and 64-bit Considerations</a> <LI> <a href = "#SecOpaque">Opaque Directives</a> +<LI> <a href = "#SecSubstitution">Argument Name Substitution</a> <LI> <a href = "#SecConfiguration">Configuration File Directives</a> <UL> <LI> <a href = "#SecJavaEmitter">JavaEmitter Configuration</a> @@ -755,6 +762,63 @@ type to a Java long: Now HANDLEs are exposed to Java as longs as desired. A similar technique is used to expose XIDs on the X11 platform as Java longs. +</P> + + +<H3><a name="SecSubstitution">Argument Name Substitution</a></H3> + +<P> + +Certain configuration file directives allow the insertion of Java or C +code at various places in the generated glue code, to both eliminate +the need to hand-edit the generated glue code as well as to minimize +the hand-writing of glue code, which sidesteps the GlueGen process. In +some situations the inserted code may reference incoming arguments to +compute some value or perform some operation. Examples of directives +supporting this substitution include <a +href="#ReturnValueCapacity">ReturnValueCapacity</a> and <a +href="#ReturnedArrayLength">ReturnedArrayLength</a>. + +</P> +<P> + +The expressions in these directives may contain Java MessageFormat +expressions like <code>{0}</code> which refer to the incoming argument +names to the function. <code>{0}</code> refers to the first incoming +argument. + +</P> +<P> + +Strongly-typed C primitive pointers such as <code>int*</code>, which +ordinarily expand to overloaded Java methods taking +e.g. <code>int[]</code> as well as <code>IntBuffer</code>, present a +problem. The expansion to <code>int[] arr</code> also generates an +<code>int arr_offset</code> argument to be able to pass a pointer into +the middle of the array down to C. To allow the same MessageFormat +expression to be used for both cases, the subsitution that occurs when +such a primitive array is referenced is the string <code>arr, +arr_offset</code>; in other words, the subtituted string contains a +comma. This construct may be used in the following way: the code being +manually inserted may itself contain a method call taking +e.g. <code>{3}</code> (the incoming argument index of the primitive +array or buffer). The user should supply two overloaded versions of +this method, one taking a strongly-typed Buffer and one taking e.g. an +<code>int[] arr</code> and <code>int arr_offset</code> argument. The +implementation of <code>RangeCheck</code>s for primitive arrays and +strongly-typed buffers uses this construct. + +</P> +<P> + +It should be noted that in the autogenerated C code the offset +argument is expressed in bytes while at the Java level it is expressed +in elements. Most uses of GlueGen will probably not have to refer to +the primitive array arguments in C code so this slight confusion +should be minor. + +</P> + <H3><a name="SecConfiguration">Configuration File Directives</a></H3> @@ -1047,10 +1111,11 @@ href="#ImplJavaClass">ImplJavaClass</a>. (optional) Adds the specified code as an epilogue in the Java method for the specified C function; this code is run after the underlying C function has been called via the native method but before any result -is returned. No transformations are currently performed on this code, -unlike in the <a href="#ReturnedArrayLength">ReturnedArrayLength</a> -and other directives. See also <a -href="#JavaPrologue">JavaPrologue</a>. +is returned. As in the <a +href="#ReturnedArrayLength">ReturnedArrayLength</a> and other +directives, <a href="#SecSubstitution">argument name +substitution</a> is performed on MessageFormat expressions in the +specified code. See also <a href="#JavaPrologue">JavaPrologue</a>. <dt><strong><a name="JavaOutputDir">JavaOutputDir</a></strong> @@ -1068,10 +1133,11 @@ defaults to the current working directory. (optional) Adds the specified code as a prologue in the Java method for the specified C function; this code is run before the underlying C -function is called via the native method. No transformations are -currently performed on this code, unlike in the <a +function is called via the native method. As in the <a href="#ReturnedArrayLength">ReturnedArrayLength</a> and other -directives. See also <a href="#JavaEpilogue">JavaEpilogue</a>. +directives, <a href="#SecSubstitution">argument name +substitution</a> is performed on MessageFormat expressions in the +specified code. See also <a href="#JavaEpilogue">JavaEpilogue</a>. <dt><strong><a name="ManuallyImplement">ManuallyImplement</a></strong> @@ -1160,9 +1226,8 @@ that should be expressed in terms of a number of bytes rather than a number of elements, see the <a href="#RangeCheckBytes">RangeCheckBytes</a> directive. As in the <a href="#ReturnedArrayLength">ReturnedArrayLength</a> and other -directives, MessageFormat expressions such as "{0}" are replaced with -the corresponding incoming argument name, where the first incoming -argument is index 0. +directives, <a href="#SecSubstitution">argument name substitution</a> +is performed on MessageFormat expressions. <dt><strong><a name="RangeCheckBytes">RangeCheckBytes</a></strong> @@ -1171,7 +1236,8 @@ argument is index 0. (optional) Same as the <a href="#RangeCheck">RangeCheck</a> directive, but the specified expression is treated as a minimum number of bytes -remaining rather than a minimum number of elements remaining. +remaining rather than a minimum number of elements remaining. This +directive may not be used with primitive arrays. <dt><strong><a name="RenameJavaMethod">RenameJavaMethod</a></strong> @@ -1203,7 +1269,8 @@ href="#ImplJavaClass">ImplJavaClass</a> directives. expression with MessageFormat specifiers such as "{0}". These specifiers will be replaced in the generated glue code with the incoming argument names where the first argument to the method is -numbered 0. <br> +numbered 0. See the section on <a href="#SecSubstitution"> argument +name substitution</a>.<br> (optional) For a function returning a compound C pointer type such as an <code>XVisualInfo*</code>, indicates that the returned pointer is @@ -1235,8 +1302,8 @@ subclass wrapping a C primitive pointer such as <code>char*</code> or <code>float*</code> being returned from a C function. Typically necessary in order to properly use such pointer return results from Java. As in the <a href="#ReturnedArrayLength">ReturnedArrayLength</a> -directive, argument name substitution is performed on MessageFormat -expressions such as "{0}" where the first argument is index 0. +directive, <a href="#SecSubstitution">argument name substitution</a> +is performed on MessageFormat expressions. <dt><strong><a name="ReturnValueLength">ReturnValueLength</a></strong> @@ -1253,8 +1320,8 @@ directive handles boxing of individual elements of the array (which are pointers) in to the Java class which wraps that C struct type. See the (FIXME) examples for a concrete example of usage. As in the <a href="#ReturnedArrayLength">ReturnedArrayLength</a> directive, -argument name substitution is performed on MessageFormat expressions -such as "{0}" where the first argument is index 0. +<a href="#SecSubstitution">argument name substitution</a> is performed +on MessageFormat expressions. <dt><strong><a name="RuntimeExceptionType">RuntimeExceptionType</a></strong> @@ -1538,3 +1605,6 @@ despite the fact that it has an associated function pointer typedef in the header. </dl> + +</BODY> +</HTML> diff --git a/src/java/com/sun/gluegen/CMethodBindingEmitter.java b/src/java/com/sun/gluegen/CMethodBindingEmitter.java index 9222588..1ffd362 100644 --- a/src/java/com/sun/gluegen/CMethodBindingEmitter.java +++ b/src/java/com/sun/gluegen/CMethodBindingEmitter.java @@ -988,13 +988,8 @@ public class CMethodBindingEmitter extends FunctionEmitter writer.print(" return (*env)->NewDirectByteBuffer(env, _res, "); // See whether capacity has been specified if (returnValueCapacityExpression != null) { - String[] argumentNames = new String[binding.getNumArguments()]; - for (int i = 0; i < binding.getNumArguments(); i++) - { - argumentNames[i] = binding.getArgumentName(i); - } writer.print( - returnValueCapacityExpression.format(argumentNames)); + returnValueCapacityExpression.format(argumentNameArray())); } else { if (cReturnType.isPointer() && cReturnType.asPointer().getTargetType().isCompound()) { @@ -1025,11 +1020,7 @@ public class CMethodBindingEmitter extends FunctionEmitter throw new RuntimeException("Error while generating C code: no length specified for array returned from function " + binding); } - String[] argumentNames = new String[binding.getNumArguments()]; - for (int i = 0; i < binding.getNumArguments(); i++) { - argumentNames[i] = binding.getArgumentName(i); - } - writer.println(" " + arrayResLength + " = " + returnValueLengthExpression.format(argumentNames) + ";"); + writer.println(" " + arrayResLength + " = " + returnValueLengthExpression.format(argumentNameArray()) + ";"); writer.println(" " + arrayRes + " = (*env)->NewObjectArray(env, " + arrayResLength + ", (*env)->FindClass(env, \"java/nio/ByteBuffer\"), NULL);"); writer.println(" for (" + arrayIdx + " = 0; " + arrayIdx + " < " + arrayResLength + "; " + arrayIdx + "++) {"); Type retType = binding.getCSymbol().getReturnType(); @@ -1408,6 +1399,18 @@ public class CMethodBindingEmitter extends FunctionEmitter return binding.getArgumentName(i) + "_byte_offset_array"; } + protected String[] argumentNameArray() { + String[] argumentNames = new String[binding.getNumArguments()]; + for (int i = 0; i < binding.getNumArguments(); i++) { + argumentNames[i] = binding.getArgumentName(i); + if (binding.getJavaArgumentType(i).isPrimitiveArray()) { + // Add on _offset argument in comma-separated expression + argumentNames[i] = argumentNames[i] + ", " + byteOffsetArgName(i); + } + } + return argumentNames; + } + protected String pointerConversionArgumentName(int i) { return "_ptr" + i; } diff --git a/src/java/com/sun/gluegen/FunctionEmitter.java b/src/java/com/sun/gluegen/FunctionEmitter.java index 3fa6f03..0d0f225 100644 --- a/src/java/com/sun/gluegen/FunctionEmitter.java +++ b/src/java/com/sun/gluegen/FunctionEmitter.java @@ -47,7 +47,7 @@ public abstract class FunctionEmitter { public static final EmissionModifier STATIC = new EmissionModifier("static"); - private HashSet modifiers = new HashSet(4); + private ArrayList modifiers = new ArrayList(); private CommentEmitter commentEmitter = null; private PrintWriter defaultOutput; @@ -64,7 +64,7 @@ public abstract class FunctionEmitter * Makes this FunctionEmitter a copy of the passed one. */ public FunctionEmitter(FunctionEmitter arg) { - modifiers = (HashSet) arg.modifiers.clone(); + modifiers = (ArrayList) arg.modifiers.clone(); commentEmitter = arg.commentEmitter; defaultOutput = arg.defaultOutput; } @@ -203,6 +203,19 @@ public abstract class FunctionEmitter public final String toString() { return emittedForm; } private String emittedForm; + + public int hashCode() { + return emittedForm.hashCode(); + } + + public boolean equals(Object arg) { + if (arg == null || (!(arg instanceof EmissionModifier))) { + return false; + } + + return emittedForm.equals(((EmissionModifier) arg).emittedForm); + } + protected EmissionModifier(String emittedForm) { this.emittedForm = emittedForm; } } } diff --git a/src/java/com/sun/gluegen/JavaConfiguration.java b/src/java/com/sun/gluegen/JavaConfiguration.java index ae8c46e..b5f43d6 100644 --- a/src/java/com/sun/gluegen/JavaConfiguration.java +++ b/src/java/com/sun/gluegen/JavaConfiguration.java @@ -116,8 +116,6 @@ public class JavaConfiguration { private Map/*<String,String>*/ javaMethodRenames = new HashMap(); private Map/*<String,List<String>>*/ javaPrologues = new HashMap(); private Map/*<String,List<String>>*/ javaEpilogues = new HashMap(); - private Map/*<String,Map<Integer,String>>*/ rangeChecks = new HashMap(); - private Map/*<String,Map<Integer,String>>*/ byteRangeChecks = new HashMap(); /** Reads the configuration file. @param filename path to file that should be read @@ -571,22 +569,6 @@ public class JavaConfiguration { return res; } - /** Returns a map of Integer argument numbers to expressions to be - used to range check the given arguments to the given function. - Returns null if there were no range check expressions supplied - for this function. */ - public Map/*<Integer, String>*/ rangeCheckExpressions(String functionName) { - return (Map/*<Integer, String>*/) rangeChecks.get(functionName); - } - - /** Returns a map of Integer argument numbers to expressions to be - used to range check (in size of bytes) the given arguments to - the given function. Returns null if there were no range check - expressions supplied for this function. */ - public Map/*<Integer, String>*/ byteRangeCheckExpressions(String functionName) { - return (Map/*<Integer, String>*/) byteRangeChecks.get(functionName); - } - //---------------------------------------------------------------------- // Internals only below this point // @@ -1142,13 +1124,7 @@ public class JavaConfiguration { methodName = methodName + descriptor; } } - Map code = (prologue ? javaPrologues : javaEpilogues); - List/*<String>*/ data = (List/*<String>*/) code.get(methodName); - if (data == null) { - data = new ArrayList/*<String>*/(); - code.put(methodName, data); - } - data.add(restOfLine); + addJavaPrologueOrEpilogue(methodName, restOfLine, prologue); } catch (NoSuchElementException e) { throw new RuntimeException("Error parsing \"" + (prologue ? "JavaPrologue" : "JavaEpilogue") + @@ -1157,27 +1133,28 @@ public class JavaConfiguration { } } + protected void addJavaPrologueOrEpilogue(String methodName, String code, boolean prologue) { + Map codes = (prologue ? javaPrologues : javaEpilogues); + List/*<String>*/ data = (List/*<String>*/) codes.get(methodName); + if (data == null) { + data = new ArrayList/*<String>*/(); + codes.put(methodName, data); + } + data.add(code); + } + protected void readRangeCheck(StringTokenizer tok, String filename, int lineNo, boolean inBytes) { try { String functionName = tok.nextToken(); int argNum = Integer.parseInt(tok.nextToken()); String restOfLine = tok.nextToken("\n\r\f"); restOfLine = restOfLine.trim(); - Map/*<Integer, String>*/ checksForFunction = null; - if (inBytes) { - checksForFunction = (Map/*<Integer, String>*/) byteRangeChecks.get(functionName); - } else { - checksForFunction = (Map/*<Integer, String>*/) rangeChecks.get(functionName); - } - if (checksForFunction == null) { - checksForFunction = new HashMap/*<Integer, String>*/(); - if (inBytes) { - byteRangeChecks.put(functionName, checksForFunction); - } else { - rangeChecks.put(functionName, checksForFunction); - } - } - checksForFunction.put(new Integer(argNum), restOfLine); + // Construct a JavaPrologue for this + addJavaPrologueOrEpilogue(functionName, + "BufferFactory.rangeCheck" + + (inBytes ? "Bytes" : "") + + "({" + argNum + "}, " + restOfLine + ");", + true); } catch (Exception e) { throw new RuntimeException("Error parsing \"RangeCheck" + (inBytes ? "Bytes" : "") + "\" command at line " + lineNo + " in file \"" + filename + "\"", e); diff --git a/src/java/com/sun/gluegen/JavaEmitter.java b/src/java/com/sun/gluegen/JavaEmitter.java index f079906..d4bafb7 100644 --- a/src/java/com/sun/gluegen/JavaEmitter.java +++ b/src/java/com/sun/gluegen/JavaEmitter.java @@ -377,8 +377,6 @@ public class JavaEmitter implements GlueEmitter { emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); emitter.setPrologue(prologue); emitter.setEpilogue(epilogue); - emitter.setRangeCheckExpressions(cfg.rangeCheckExpressions(binding.getName())); - emitter.setByteRangeCheckExpressions(cfg.byteRangeCheckExpressions(binding.getName())); allEmitters.add(emitter); } @@ -432,8 +430,6 @@ public class JavaEmitter implements GlueEmitter { } emitter.addModifier(JavaMethodBindingEmitter.NATIVE); emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); - emitter.setRangeCheckExpressions(cfg.rangeCheckExpressions(binding.getName())); - emitter.setByteRangeCheckExpressions(cfg.byteRangeCheckExpressions(binding.getName())); allEmitters.add(emitter); // Optionally emit the entry point taking arrays which handles @@ -459,8 +455,6 @@ public class JavaEmitter implements GlueEmitter { } emitter.addModifier(JavaMethodBindingEmitter.NATIVE); emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); - emitter.setRangeCheckExpressions(cfg.rangeCheckExpressions(binding.getName())); - emitter.setByteRangeCheckExpressions(cfg.byteRangeCheckExpressions(binding.getName())); allEmitters.add(emitter); } } diff --git a/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java b/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java index 7e08977..0032b61 100644 --- a/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java +++ b/src/java/com/sun/gluegen/JavaMethodBindingEmitter.java @@ -87,10 +87,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter // number of elements of the returned array. private String returnedArrayLengthExpression; - // Range-check expressions for various Buffer arguments - private Map/*<Integer, String>*/ rangeCheckExpressions; - private Map/*<Integer, String>*/ byteRangeCheckExpressions; - public JavaMethodBindingEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType, @@ -133,8 +129,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter prologue = arg.prologue; epilogue = arg.epilogue; returnedArrayLengthExpression = arg.returnedArrayLengthExpression; - rangeCheckExpressions = arg.rangeCheckExpressions; - byteRangeCheckExpressions = arg.byteRangeCheckExpressions; } public final MethodBinding getBinding() { return binding; } @@ -199,14 +193,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter this.forImplementingMethodCall = impl; } - public void setRangeCheckExpressions(Map/*<Integer, String>*/ rangeChecks) { - this.rangeCheckExpressions = rangeChecks; - } - - public void setByteRangeCheckExpressions(Map/*<Integer, String>*/ rangeChecks) { - this.byteRangeCheckExpressions = rangeChecks; - } - protected void emitReturnType(PrintWriter writer) { writer.print(getReturnTypeString(false)); @@ -369,8 +355,10 @@ public class JavaMethodBindingEmitter extends FunctionEmitter protected void emitPrologueOrEpilogue(List/*<String>*/ code, PrintWriter writer) { if (code != null) { + String[] argumentNames = argumentNameArray(); for (Iterator iter = code.iterator(); iter.hasNext(); ) { - writer.println(" " + (String) iter.next()); + MessageFormat fmt = new MessageFormat((String) iter.next()); + writer.println(" " + fmt.format(argumentNames)); } } } @@ -438,44 +426,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter } } } - - emitManuallySpecifiedRangeChecks(rangeCheckExpressions, false, writer); - emitManuallySpecifiedRangeChecks(byteRangeCheckExpressions, true, writer); - } - - protected void emitManuallySpecifiedRangeChecks(Map/*<Integer, String>*/ rangeChecks, - boolean inBytes, - PrintWriter writer) { - if (rangeChecks == null) { - return; - } - - // Check lengths of arrays and buffers with user-specified checks - for (Iterator iter = rangeChecks.keySet().iterator(); iter.hasNext(); ) { - Integer argNumBox = (Integer) iter.next(); - int argNum = argNumBox.intValue(); - JavaType type = binding.getJavaArgumentType(argNum); - String argName = getArgumentName(argNum); - if (type.isPrimitiveArray()) { - String offsetArg = offsetArgName(argNum); - if (inBytes) { - throw new RuntimeException("Can not specify RangeCheckBytes for primitive array arguments (failed on function " + - binding.getName() + ", argument " + argName + ")"); - } - writer.println(" BufferFactory.rangeCheck(" + argName + ", " + offsetArg + ", " + - new MessageFormat((String) rangeChecks.get(argNumBox)).format(argumentNameArray()) + - ");"); - } else if (!type.isPrimitive()) { - // Assume it's a Buffer - writer.print(" BufferFactory.rangeCheck"); - if (inBytes) { - writer.print("Bytes"); - } - writer.println("(" + argName + ", " + - new MessageFormat((String) rangeChecks.get(argNumBox)).format(argumentNameArray()) + - ");"); - } - } } protected void emitCall(MethodBinding binding, PrintWriter writer, boolean direct) { @@ -700,6 +650,10 @@ public class JavaMethodBindingEmitter extends FunctionEmitter String[] argumentNames = new String[binding.getNumArguments()]; for (int i = 0; i < binding.getNumArguments(); i++) { argumentNames[i] = getArgumentName(i); + if (binding.getJavaArgumentType(i).isPrimitiveArray()) { + // Add on _offset argument in comma-separated expression + argumentNames[i] = argumentNames[i] + ", " + offsetArgName(i); + } } return argumentNames; } diff --git a/src/java/com/sun/gluegen/opengl/GLConfiguration.java b/src/java/com/sun/gluegen/opengl/GLConfiguration.java index a44f3fe..e331d16 100755 --- a/src/java/com/sun/gluegen/opengl/GLConfiguration.java +++ b/src/java/com/sun/gluegen/opengl/GLConfiguration.java @@ -125,9 +125,14 @@ public class GLConfiguration extends ProcAddressConfiguration { // Need to generate appropriate prologue based on both buffer // object kind and whether this variant of the MethodBinding // is the one accepting a "long" as argument - if (res == null) { - res = new ArrayList(); + // + // NOTE we MUST NOT mutate the array returned from the super + // call! + ArrayList res2 = new ArrayList(); + if (res != null) { + res2.addAll(res); } + res = res2; String prologue = "check"; @@ -152,6 +157,17 @@ public class GLConfiguration extends ProcAddressConfiguration { prologue = prologue + "();"; res.add(0, prologue); + + // Must also filter out bogus rangeCheck directives for VBO/PBO + // variants + if (emitter.isBufferObjectMethodBinding(binding)) { + for (Iterator iter = res.iterator(); iter.hasNext(); ) { + String line = (String) iter.next(); + if (line.indexOf("BufferFactory.rangeCheck") >= 0) { + iter.remove(); + } + } + } } return res; diff --git a/src/java/com/sun/gluegen/runtime/BufferFactory.java b/src/java/com/sun/gluegen/runtime/BufferFactory.java index ce46d14..4f095f4 100644 --- a/src/java/com/sun/gluegen/runtime/BufferFactory.java +++ b/src/java/com/sun/gluegen/runtime/BufferFactory.java @@ -44,6 +44,7 @@ import java.nio.*; public class BufferFactory { public static final int SIZEOF_BYTE = 1; public static final int SIZEOF_SHORT = 2; + public static final int SIZEOF_CHAR = 2; public static final int SIZEOF_INT = 4; public static final int SIZEOF_FLOAT = 4; public static final int SIZEOF_LONG = 8; @@ -77,7 +78,7 @@ public class BufferFactory { } else if (buf instanceof LongBuffer) { return ((LongBuffer) buf).isDirect(); } - throw new RuntimeException("Unknown buffer type " + buf.getClass().getName()); + throw new RuntimeException("Unexpected buffer type " + buf.getClass().getName()); } @@ -101,6 +102,8 @@ public class BufferFactory { return (buf.position() * SIZEOF_DOUBLE); } else if (buf instanceof LongBuffer) { return (buf.position() * SIZEOF_LONG); + } else if (buf instanceof CharBuffer) { + return (buf.position() * SIZEOF_CHAR); } throw new RuntimeException("Disallowed array backing store type in buffer " @@ -127,6 +130,8 @@ public class BufferFactory { return ((DoubleBuffer) buf).array(); } else if (buf instanceof LongBuffer) { return ((LongBuffer) buf).array(); + } else if (buf instanceof CharBuffer) { + return ((CharBuffer) buf).array(); } throw new RuntimeException("Disallowed array backing store type in buffer " @@ -156,48 +161,78 @@ public class BufferFactory { return (SIZEOF_DOUBLE*(((DoubleBuffer)buf).arrayOffset() + pos)); } else if(buf instanceof LongBuffer) { return (SIZEOF_LONG*(((LongBuffer)buf).arrayOffset() + pos)); + } else if(buf instanceof CharBuffer) { + return (SIZEOF_CHAR*(((CharBuffer)buf).arrayOffset() + pos)); } throw new RuntimeException("Unknown buffer type " + buf.getClass().getName()); } public static void rangeCheck(byte[] array, int offset, int minElementsRemaining) { + if (array == null) { + return; + } + if (array.length < offset + minElementsRemaining) { throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); } } public static void rangeCheck(char[] array, int offset, int minElementsRemaining) { + if (array == null) { + return; + } + if (array.length < offset + minElementsRemaining) { throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); } } public static void rangeCheck(short[] array, int offset, int minElementsRemaining) { + if (array == null) { + return; + } + if (array.length < offset + minElementsRemaining) { throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); } } public static void rangeCheck(int[] array, int offset, int minElementsRemaining) { + if (array == null) { + return; + } + if (array.length < offset + minElementsRemaining) { throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); } } public static void rangeCheck(long[] array, int offset, int minElementsRemaining) { + if (array == null) { + return; + } + if (array.length < offset + minElementsRemaining) { throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); } } public static void rangeCheck(float[] array, int offset, int minElementsRemaining) { + if (array == null) { + return; + } + if (array.length < offset + minElementsRemaining) { throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); } } public static void rangeCheck(double[] array, int offset, int minElementsRemaining) { + if (array == null) { + return; + } + if (array.length < offset + minElementsRemaining) { throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); } @@ -232,6 +267,8 @@ public class BufferFactory { bytesRemaining = elementsRemaining * SIZEOF_DOUBLE; } else if (buffer instanceof LongBuffer) { bytesRemaining = elementsRemaining * SIZEOF_LONG; + } else if (buffer instanceof CharBuffer) { + bytesRemaining = elementsRemaining * SIZEOF_CHAR; } if (bytesRemaining < minBytesRemaining) { throw new IndexOutOfBoundsException("Required " + minBytesRemaining + " remaining bytes in buffer, only had " + bytesRemaining); |