
org.n52.matlab.control.link.Linker Maven / Gradle / Ivy
The newest version!
package org.n52.matlab.control.link;
/*
* Copyright (c) 2013, Joshua Kaplan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer.
* - 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 matlabcontrol nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
*/
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.n52.matlab.control.MatlabInvocationException;
import org.n52.matlab.control.MatlabProxy;
import org.n52.matlab.control.MatlabOperations;
import org.n52.matlab.control.MatlabProxy.MatlabThreadCallable;
import org.n52.matlab.control.MatlabProxy.MatlabThreadProxy;
import org.n52.matlab.control.link.ArrayMultidimensionalizer.PrimitiveArrayGetter;
import org.n52.matlab.control.link.MatlabNumber.MatlabNumberGetter;
import org.n52.matlab.control.link.MatlabFunctionHandle.MatlabFunctionHandleGetter;
import org.n52.matlab.control.link.MatlabNumberArray.MatlabNumberArrayGetter;
import org.n52.matlab.control.link.MatlabType.MatlabTypeGetter;
import org.n52.matlab.control.link.MatlabType.MatlabTypeSetter;
import org.n52.matlab.control.link.MatlabVariable.MatlabVariableGetter;
/**
*
* @since 4.2.0
* @author Joshua Kaplan
*/
public class Linker
{
private Linker() { }
/**************************************************************************************************************\
|* Linking & Validation *|
\**************************************************************************************************************/
static MatlabOperations getLinkedMatlabOperations(MatlabProxy proxy)
{
if(proxy == null)
{
throw new NullPointerException("proxy may not be null");
}
Class> opsClass = MatlabOperations.class;
MatlabOperations operations = (MatlabOperations) Proxy.newProxyInstance(opsClass.getClassLoader(),
new Class>[] { opsClass },
new MatlabFunctionInvocationHandler(proxy, opsClass, new ConcurrentHashMap()));
return operations;
}
public static T link(Class functionInterface, MatlabProxy proxy)
{
if(!functionInterface.isInterface())
{
throw new LinkingException(functionInterface.getCanonicalName() + " is not an interface");
}
if(proxy == null)
{
throw new NullPointerException("proxy may not be null");
}
//Maps each method to information about the function and method
ConcurrentMap resolvedInfo = new ConcurrentHashMap();
//Validate and retrieve information about all of the methods in the interface
for(Method method : functionInterface.getMethods())
{
//Check method is annotated with function information
MatlabFunction annotation = method.getAnnotation(MatlabFunction.class);
if(annotation == null)
{
throw new LinkingException(method + " is not annotated with " +
MatlabFunction.class.getCanonicalName());
}
//Check method can throw MatlabInvocationException
checkExceptions(method);
//Store information about how to invoke the method, performing validation in the process
resolvedInfo.put(method, InvocationInfo.getInvocationInfo(method, annotation));
}
T functionProxy = (T) Proxy.newProxyInstance(functionInterface.getClassLoader(),
new Class>[] { functionInterface },
new MatlabFunctionInvocationHandler(proxy, functionInterface, resolvedInfo));
return functionProxy;
}
private static void checkExceptions(Method method)
{
boolean assignable = false;
Type[] genericExceptions = method.getGenericExceptionTypes();
for(Type exception : genericExceptions)
{
if(exception instanceof Class && ((Class>) exception).isAssignableFrom(MatlabInvocationException.class))
{
assignable = true;
}
}
if(!assignable)
{
throw new LinkingException(method + " is not capable of throwing " +
MatlabInvocationException.class.getCanonicalName() + " or does so with generics");
}
}
/**************************************************************************************************************\
|* Function Invocation *|
\**************************************************************************************************************/
private static class MatlabFunctionInvocationHandler implements InvocationHandler
{
private final MatlabProxy _proxy;
private final Class> _interface;
private final ConcurrentMap _invocationsInfo;
private MatlabFunctionInvocationHandler(MatlabProxy proxy, Class> functionInterface,
ConcurrentMap invocationInfo)
{
_proxy = proxy;
_interface = functionInterface;
_invocationsInfo = invocationInfo;
}
@Override
public Object invoke(Object o, Method method, Object[] args) throws MatlabInvocationException
{
Object result;
//Method belongs to java.lang.Object
if(method.getDeclaringClass().equals(Object.class))
{
result = invokeObjectMethod(method, args);
}
//Methods defined in matlabcontrol.MatlabOperations interface
else if(method.getDeclaringClass().equals(MatlabOperations.class))
{
result = invokeMatlabOperationsMethod(method, args);
}
//Method belongs to the interface supplied to this linker
else
{
result = invokeUserInterfaceMethod(method, args);
}
return result;
}
private Object invokeObjectMethod(Method method, Object[] args)
{
Object result;
//public void String toString()
if(method.getName().equals("toString"))
{
result = "[Linked " + _interface.getCanonicalName() + " info=" + _invocationsInfo + "]";
}
//public boolean equals(Object other)
else if(method.getName().equals("equals"))
{
Object other = args[0];
if(other != null && Proxy.isProxyClass(other.getClass()) &&
(Proxy.getInvocationHandler(other) instanceof MatlabFunctionInvocationHandler))
{
InvocationHandler handler = Proxy.getInvocationHandler(other);
result = _interface.equals(((MatlabFunctionInvocationHandler) handler)._interface);
}
else
{
result = false;
}
}
//public int hashCode()
else if(method.getName().equals("hashCode"))
{
result = _interface.hashCode();
}
//The other methods of java.lang.Object should not be sent to this invocation handler
else
{
throw new UnsupportedOperationException(method + " not supported");
}
return result;
}
private Object invokeMatlabOperationsMethod(Method method, Object[] args) throws MatlabInvocationException
{
Class> methodReturn = method.getReturnType();
Object result;
if(method.getName().equals("eval"))
{
InvocationInfo info = new InvocationInfo("eval", null, new Class>[0], new Class>[0][0]);
result = invokeMatlabFunction(info, false, args, methodReturn);
}
else if(method.getName().equals("returningEval"))
{
//Each return type
int nargout = (Integer) args[1];
Class>[] returnTypes = new Class>[nargout];
Arrays.fill(returnTypes, Object.class);
InvocationInfo info = new InvocationInfo("eval", null, returnTypes, new Class>[nargout][0]);
result = invokeMatlabFunction(info, false, new Object[]{ args[0] }, methodReturn);
}
else if(method.getName().equals("feval"))
{
//Make function arguments at the same level as the function name
Object[] functionArgs = (Object[]) args[1];
Object[] firstLevelArgs = new Object[functionArgs.length + 1];
firstLevelArgs[0] = args[0];
System.arraycopy(functionArgs, 0, firstLevelArgs, 1, functionArgs.length);
InvocationInfo info = new InvocationInfo("feval", null, new Class>[0], new Class>[0][0]);
result = invokeMatlabFunction(info, false, firstLevelArgs, methodReturn);
}
else if(method.getName().equals("returningFeval"))
{
//Make function arguments at same level as function name
Object[] functionArgs = (Object[]) args[2];
Object[] firstLevelArgs = new Object[functionArgs.length + 1];
firstLevelArgs[0] = args[0];
System.arraycopy(functionArgs, 0, firstLevelArgs, 1, functionArgs.length);
//Each return type
int nargout = (Integer) args[1];
Class>[] returnTypes = new Class>[nargout];
Arrays.fill(returnTypes, Object.class);
InvocationInfo info = new InvocationInfo("feval", null, returnTypes, new Class>[nargout][0]);
result = invokeMatlabFunction(info, false, firstLevelArgs, methodReturn);
}
else if(method.getName().equals("getVariable"))
{
InvocationInfo info = new InvocationInfo("eval", null, new Class>[]{ Object.class }, new Class>[1][0]);
result = ((Object[]) invokeMatlabFunction(info, false, args, methodReturn))[0];
}
else if(method.getName().equals("setVariable"))
{
InvocationInfo info = new InvocationInfo("assignin", null, new Class>[0], new Class>[0][0]);
result = invokeMatlabFunction(info, false, new Object[]{ "base", args[0], args[1] }, methodReturn);
}
else
{
throw new UnsupportedOperationException(method + " not supported");
}
return result;
}
private Object invokeUserInterfaceMethod(Method method, Object[] args) throws MatlabInvocationException
{
InvocationInfo info = _invocationsInfo.get(method);
if(args == null)
{
args = new Object[0];
}
//If the method uses var args then we need to make those arguments first level
if(method.isVarArgs() && args.length > 0)
{
Object varArgs = args[args.length - 1];
if(varArgs.getClass().isArray())
{
//Number of variable arguments
int varArgLength = Array.getLength(varArgs);
//Combined arguments, ignoring the last argument which was the var arg array container
Object[] allArgs = new Object[args.length + varArgLength - 1];
System.arraycopy(args, 0, allArgs, 0, args.length - 1);
//Update information with var args as first level arguments
for(int i = 0; i < varArgLength; i++)
{
Object arg = Array.get(varArgs, i);
allArgs[i + args.length - 1] = arg;
}
args = allArgs;
}
}
return invokeMatlabFunction(info, true, args, method.getReturnType());
}
private Object invokeMatlabFunction(InvocationInfo info, boolean userDefined, Object[] args,
Class> methodReturn)
throws MatlabInvocationException
{
//Replace all arguments with parameters of a MatlabType subclass or a multidimensional primitive array with
//their serialized setters
for(int i = 0; i < args.length; i++)
{
if(args[i] != null)
{
ClassInfo argInfo = ClassInfo.getInfo(args[i].getClass());
if(argInfo.isMatlabType)
{
args[i] = ((MatlabType) args[i]).getSetter();
}
else if(argInfo.isPrimitiveArray)
{
args[i] = ArrayLinearizer.getSetter(args[i]);
}
}
}
//Invoke function
FunctionResult result = _proxy.invokeAndWait(new CustomFunctionInvocation(info, args));
if(result.thrownException != null)
{
result.thrownException.fillInStackTrace();
throw result.thrownException;
}
Object[] returnValues = result.returnArgs;
//For each returned value that is a serialized getter, retrieve it
for(int i = 0; i < returnValues.length; i++)
{
if(returnValues[i] instanceof MatlabTypeGetter)
{
returnValues[i] = ((MatlabType.MatlabTypeGetter) returnValues[i]).retrieve();
}
}
//Process returned values if user defined
Object toReturn;
if(userDefined)
{
toReturn = processReturnValues(info, returnValues, methodReturn);
}
else
{
toReturn = returnValues;
}
return toReturn;
}
private Object processReturnValues(InvocationInfo info, Object[] result, Class> methodReturn)
{
Object toReturn;
//0 return values
if(result.length == 0)
{
toReturn = result;
}
//1 return values
else if(result.length == 1)
{
toReturn = validateAssignability(result[0], info.returnTypes[0], info.returnTypeParameters[0]);
}
//2 or more return values
else
{
for(int i = 0; i < result.length; i++)
{
result[i] = validateAssignability(result[i], info.returnTypes[i], info.returnTypeParameters[0]);
}
toReturn = MatlabReturns.getMaxReturn(result);
}
return toReturn;
}
private Object validateAssignability(Object value, Class> returnType, Class>[] returnTypeParameters)
{
Object toReturn;
if(value == null)
{
if(returnType.isPrimitive())
{
throw new UnassignableReturnException("Return type is primitive and cannot be assigned null\n" +
"Return type: " + toClassString(returnType, returnTypeParameters));
}
else
{
toReturn = null;
}
}
else if(returnType.isPrimitive())
{
Class> autoboxedClass = PRIMITIVE_TO_AUTOBOXED.get(returnType);
if(autoboxedClass.equals(value.getClass()))
{
toReturn = value;
}
else
{
throw new UnassignableReturnException("Return type cannot be assigned the value returned\n" +
"Return type: " + toClassString(returnType, returnTypeParameters) + "\n" +
"Value type: " + toClassString(value));
}
}
else
{
if(!returnType.isAssignableFrom(value.getClass()))
{
throw new UnassignableReturnException("Return type cannot be assigned the value returned\n" +
"Return type: " + toClassString(returnType, returnTypeParameters) + "\n" +
"Value type: " + toClassString(value));
}
//If the return type is a MatlabNumberArray subclass
if(MatlabNumberArray.class.isAssignableFrom(returnType))
{
//Check the parameterization matches
if(!((MatlabNumberArray) value).getOutputArrayType().equals(returnTypeParameters[0]))
{
throw new UnassignableReturnException("Return type cannot be assigned the value returned\n" +
"Return type: " + toClassString(returnType, returnTypeParameters) + "\n" +
"Value type: " + toClassString(value));
}
}
toReturn = value;
}
return toReturn;
}
private static String toClassString(Class> returnType, Class>[] returnTypeParameters)
{
String classString = returnType.getCanonicalName();
if(returnTypeParameters.length != 0)
{
classString += "<";
for(int i = 0; i < returnTypeParameters.length; i++)
{
classString += returnTypeParameters[i].getCanonicalName();
if(i != returnTypeParameters.length - 1)
{
classString += ", ";
}
}
classString += ">";
}
return classString;
}
private static String toClassString(Object obj)
{
String classString;
if(obj == null)
{
classString = "null";
}
else if(MatlabNumberArray.class.isAssignableFrom(obj.getClass()))
{
MatlabNumberArray array = (MatlabNumberArray) obj;
classString = array.getClass().getCanonicalName() +
"<" + array.getOutputArrayType().getCanonicalName() + ">";
}
else
{
classString = obj.getClass().getCanonicalName();
}
return classString;
}
private static final Map, Class>> PRIMITIVE_TO_AUTOBOXED;
static
{
Map, Class>> map = new HashMap, Class>>();
map.put(byte.class, Byte.class);
map.put(short.class, Short.class);
map.put(int.class, Integer.class);
map.put(long.class, Long.class);
map.put(double.class, Double.class);
map.put(float.class, Float.class);
map.put(boolean.class, Boolean.class);
map.put(char.class, Character.class);
PRIMITIVE_TO_AUTOBOXED = Collections.unmodifiableMap(map);
}
}
private static class FunctionResult implements Serializable
{
private final Object[] returnArgs;
private final RuntimeException thrownException;
FunctionResult(Object[] returnArgs)
{
this.returnArgs = returnArgs;
this.thrownException = null;
}
FunctionResult(RuntimeException thrownException)
{
this.returnArgs = null;
this.thrownException = thrownException;
}
}
private static class CustomFunctionInvocation implements MatlabThreadCallable, Serializable
{
private final InvocationInfo _functionInfo;
private final Object[] _args;
private CustomFunctionInvocation(InvocationInfo functionInfo, Object[] args)
{
_functionInfo = functionInfo;
_args = args;
}
@Override
public FunctionResult call(MatlabThreadProxy proxy) throws MatlabInvocationException
{
FunctionResult result;
try
{
result = new FunctionResult(this.invoke(proxy));
}
catch(RuntimeException e)
{
result = new FunctionResult(e);
}
return result;
}
private Object[] invoke(MatlabOperations ops) throws MatlabInvocationException
{
String initialDir = null;
//If the function was specified as not being on MATLAB's path
if(_functionInfo.containingDirectory != null)
{
//Initial directory before cding
initialDir = (String) ops.returningFeval("pwd", 1)[0];
//No need to change directory
if(initialDir.equals(_functionInfo.containingDirectory))
{
initialDir = null;
}
//Change directory to where the function is located
else
{
ops.feval("cd", _functionInfo.containingDirectory);
}
}
List variablesToClear = new ArrayList();
try
{
//Set all arguments as MATLAB variables and build a function call using those variables
String functionStr = _functionInfo.name + "(";
List parameterNames = generateNames(ops, "param_", _args.length);
for(int i = 0; i < _args.length; i++)
{
String name = parameterNames.get(i);
variablesToClear.add(name);
setReturnValue(ops, name, _args[i]);
functionStr += name;
if(i != _args.length - 1)
{
functionStr += ", ";
}
}
functionStr += ");";
//Return arguments
List returnNames = null;
if(_functionInfo.returnTypes.length != 0)
{
returnNames = generateNames(ops, "return_", _functionInfo.returnTypes.length);
String returnStr = "[";
for(int i = 0; i < returnNames.size(); i++)
{
ClassInfo returnInfo = ClassInfo.getInfo(_functionInfo.returnTypes[i]);
String name;
if(returnInfo.isVoid)
{
name = "~";
}
else
{
name = returnNames.get(i);
variablesToClear.add(name);
}
returnStr += name;
if(i != returnNames.size() - 1)
{
returnStr += ", ";
}
}
returnStr += "]";
functionStr = returnStr + " = " + functionStr;
}
//Invoke the function
ops.eval(functionStr);
//Get the return values
List variablesToKeep = new ArrayList();
Object[] returnValues = new Object[_functionInfo.returnTypes.length];
for(int i = 0; i < returnValues.length; i++)
{
ClassInfo returnInfo = ClassInfo.getInfo(_functionInfo.returnTypes[i]);
//No return
if(returnInfo.isVoid)
{
returnValues[i] = null;
}
//Not a true "return", keeps the value in MATLAB and returns the name of the variable
else if(_functionInfo.returnTypes[i].equals(MatlabVariable.class))
{
MatlabVariableGetter getter = new MatlabVariableGetter();
getter.getInMatlab(ops, returnNames.get(i));
returnValues[i] = getter;
variablesToKeep.add(returnNames.get(i));
}
//Retrieve the value
else
{
returnValues[i] = getReturnValue(ops, returnNames.get(i), returnInfo,
_functionInfo.returnTypeParameters[i], variablesToClear);
}
}
//Do this last, so if any exceptions occurred then the variables will not be kept
variablesToClear.removeAll(variablesToKeep);
return returnValues;
}
//Restore MATLAB's state to what it was before the function call happened
finally
{
try
{
//Clear all variables used
if(!variablesToClear.isEmpty())
{
String clearCmd = "clear ";
for(int i = 0; i < variablesToClear.size(); i++)
{
clearCmd += variablesToClear.get(i);
if(i != variablesToClear.size() - 1)
{
clearCmd += " ";
}
}
ops.eval(clearCmd);
}
}
finally
{
//If necessary, change back to the directory MATLAB was in before the function was invoked
if(initialDir != null)
{
ops.feval("cd", initialDir);
}
}
}
}
private static void setReturnValue(MatlabOperations ops, String name, Object arg)
throws MatlabInvocationException
{
if(arg == null)
{
ops.eval(name + " = [];");
}
else if(arg instanceof MatlabTypeSetter)
{
((MatlabTypeSetter) arg).setInMatlab(ops, name);
}
else if(ClassInfo.getInfo(arg.getClass()).isBuiltinNumeric)
{
Number number = (Number) arg;
if(number instanceof Byte)
{
ops.eval(name + "=int8(" + number.byteValue() + ");");
}
else if(number instanceof Short)
{
ops.eval(name + "=int16(" + number.shortValue() + ");");
}
else if(number instanceof Integer)
{
ops.eval(name + "=int32(" + number.intValue() + ");");
}
else if(number instanceof Long)
{
ops.eval(name + "=int64(" + number.longValue() + ");");
}
else if(number instanceof Float)
{
ops.setVariable(name, new float[] { number.floatValue() });
}
else if(number instanceof Double)
{
ops.setVariable(name, new double[] { number.doubleValue() });
}
}
else
{
MatlabValueSetter.setInMatlab(ops, name, arg);
}
}
private static class MatlabValueSetter
{
private static void setInMatlab(MatlabOperations ops, String variableName, Object value)
throws MatlabInvocationException
{
MatlabValueSetter setter = new MatlabValueSetter(value);
ops.setVariable(variableName, setter);
ops.eval(variableName + " = " + variableName + ".getValue();");
}
private final Object _value;
private MatlabValueSetter(Object value)
{
_value = value;
}
public Object getValue()
{
return _value;
}
}
private static Object getReturnValue(MatlabOperations ops, String returnName, ClassInfo returnInfo,
Class>[] returnParams, List variablesToClear) throws MatlabInvocationException
{
Object returnValue;
//Empty array, MATLAB's rough equivalent of null
if(isFoo(ops, "isempty", returnName))
{
returnValue = null;
}
//The variable is a Java object
else if(isFoo(ops, "isjava", returnName))
{
returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
}
else
{
String type = (String) ops.returningEval("class(" + returnName + ");", 1)[0];
if(type.equals("function_handle"))
{
MatlabFunctionHandleGetter getter = new MatlabFunctionHandleGetter();
getter.getInMatlab(ops, returnName);
returnValue = getter;
}
else if(MATLAB_TO_JAVA_PRIMITIVE.containsKey(type))
{
//If a singular value
boolean isScalar = isFoo(ops, "isscalar", returnName);
//Whether the value should be returned as a linear array instead of MATLAB's default of the minimum
//array dimension being 2
boolean keepLinear = false;
if(!isScalar)
{
if(MatlabNumberArray.class.isAssignableFrom(returnInfo.describedClass))
{
ClassInfo returnParamInfo = ClassInfo.getInfo(returnParams[0]);
keepLinear = returnParamInfo.arrayDimensions == 1 && isFoo(ops, "isvector", returnName);
}
else
{
keepLinear = returnInfo.arrayDimensions == 1 && isFoo(ops, "isvector", returnName);
}
}
//logical -> boolean
if(type.equals("logical"))
{
if(isScalar)
{
returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
}
else
{
PrimitiveArrayGetter getter = new PrimitiveArrayGetter(true, keepLinear);
getter.getInMatlab(ops, returnName);
returnValue = getter;
}
}
//char -> char or String
else if(type.equals("char"))
{
//If the return type is specified as char, Character, or an array of char
if(char.class.equals(returnInfo.describedClass) || Character.class.equals(returnInfo.describedClass) ||
char.class.equals(returnInfo.baseComponentType))
{
if(isScalar)
{
returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
}
else
{
PrimitiveArrayGetter getter = new PrimitiveArrayGetter(true, keepLinear);
getter.getInMatlab(ops, returnName);
returnValue = getter;
}
}
//By default retrieve it as a String or an array of Strings
else
{
returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
}
}
//Numerics
//int8 -> byte, int16 -> short, int32 -> int, int64 -> long, single -> float, double -> double
else
{
boolean isReal = isFoo(ops, "isreal", returnName);
//Singular value
if(isScalar)
{
//If the return value is real and the return type is a primitive numeric or the autobox
if(isReal && returnInfo.isBuiltinNumeric)
{
returnValue = MatlabValueReceiver.receiveValue(ops, variablesToClear, returnName);
}
//By default, return a MatlabNumber
else
{
MatlabNumberGetter getter = new MatlabNumberGetter();
getter.getInMatlab(ops, returnName);
returnValue = getter;
}
}
//Array
else
{
//If the return value is a real array and the return type is a primitive numeric array
if(isReal && returnInfo.isArray && returnInfo.baseComponentType.isPrimitive() &&
ClassInfo.getInfo(returnInfo.baseComponentType).isBuiltinNumeric)
{
PrimitiveArrayGetter getter = new PrimitiveArrayGetter(true, keepLinear);
getter.getInMatlab(ops, returnName);
returnValue = getter;
}
//By default, return a MatlabNumberArray
else
{
MatlabNumberArrayGetter getter = new MatlabNumberArrayGetter(keepLinear);
getter.getInMatlab(ops, returnName);
returnValue = getter;
}
}
}
}
else
{
throw new UnsupportedReturnException("Unsupported MATLAB type: " + type);
}
}
return returnValue;
}
/**
* Convenience method to invoke a MATLAB "is" function; equivalent to {@code function(var);}
*
* @param ops
* @param function
* @param var
* @return
* @throws MatlabInvocationException
*/
private static boolean isFoo(MatlabOperations ops, String function, String var) throws MatlabInvocationException
{
return ((boolean[]) ops.returningEval(function + "(" + var + ");", 1)[0])[0];
}
private static final Map> MATLAB_TO_JAVA_PRIMITIVE;
static
{
Map> map = new HashMap>();
map.put("int8", byte.class);
map.put("int16", short.class);
map.put("int32", int.class);
map.put("int64", long.class);
map.put("single", float.class);
map.put("double", double.class);
map.put("logical", boolean.class);
map.put("char", char.class);
MATLAB_TO_JAVA_PRIMITIVE = Collections.unmodifiableMap(map);
}
private static class MatlabValueReceiver
{
private static Object receiveValue(MatlabOperations ops, List variablesToClear, String variableName)
throws MatlabInvocationException
{
String receiverName = (String) ops.returningEval("genvarname('receiver_', who);", 1)[0];
MatlabValueReceiver receiver = new MatlabValueReceiver();
ops.setVariable(receiverName, receiver);
variablesToClear.add(receiverName);
ops.eval(receiverName + ".set(" + variableName + ");");
return receiver._value;
}
private Object _value = null;
public void set(Object val)
{
_value = val;
}
}
private List generateNames(MatlabOperations ops, String root, int amount)
throws MatlabInvocationException
{
//Build set of currently taken names
Set takenNames = new HashSet(Arrays.asList((String[]) ops.returningEval("who", 1)[0]));
//Generate names
List generatedNames = new ArrayList();
int genSequenence = 0;
while(generatedNames.size() != amount)
{
String generatedName = root + genSequenence;
while(takenNames.contains(generatedName))
{
genSequenence++;
generatedName = root + genSequenence;
}
genSequenence++;
generatedNames.add(generatedName);
}
return generatedNames;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy