Library functions ๐
By library function (also LibraryLink function) we understand a C++ function with one of the following signatures
EXTERN_C DLLEXPORT int f (WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res);
or
EXTERN_C DLLEXPORT int f (WolframLibraryData libData, WSLINK wslp);
Such functions are building blocks of every LibraryLink paclet. They are usually called directly from the Wolfram Language after being loaded from the dynamic library first. It is common for paclets to also define functions entirely in the Wolfram Language or provide thin Wolfram Language wrappers around loaded library functions for instance in order to validate input data and then pass it down to the C++ code.
Function arguments ๐
Passing data between Wolfram Language and external C or C++ libraries is a core feature of LibraryLink. This is far from a straightforward task, because in the Wolfram Language everything is an expression and variableโs type can change at run time, whereas C and C++ variables are statically typed. Apart from that, every C/C++ library may define custom data types it uses.
LibraryLink does the heavy lifting by providing translation between popular Wolfram Language expression types and corresponding C types. For instance, when you
pass a String
expression to the library function, you will receive a null-terminated char*
in the C code, or passing a NumericArray
will yield
an object of type MNumericArray
.
In practice, what you will receive in a library function as input arguments from the Wolfram Language is an array of MArgument
, which is a union type:
typedef union {
mbool *boolean;
mint *integer;
mreal *real;
mcomplex *cmplex;
MTensor *tensor;
MSparseArray *sparse;
MNumericArray *numeric;
MImage *image;
char **utf8string;
} MArgument;
Similarly, there is one MArgument
to store the result of your library function that you want to return to the Wolfram Language. You must also remember that
some types of arguments need special treatment, for example you must call UTF8String_disown
on string arguments to avoid memory leaks.
Developers who are not familiar with this part of LibraryLink are encouraged to consult the official guide before reading on.
LLU hides all those implementation details in the MArgumentManager
class. You still need to know what the actual
argument types are but you can now extract arguments using member functions like getInteger
,
getString
etc. and set the resulting value with set
without
worrying about memory management.
Example ๐
Write a library function that adds two integers. First thing you need to do is to create an instance of MArgumentManager
initialized with all arguments to the library function:
EXTERN_C DLLEXPORT int AddTwoIntegers(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) {
LLU::MArgumentManager mngr {libData, Argc, Args, Res};
auto n1 = mngr.get<mint>(0); // get first (index = 0) argument, which is of type mint
auto n2 = mngr.get<mint>(1); // get second argument which is also an integer
mngr.set(n1 + n2); // set the sum of arguments to be the result
return LLU::ErrorCode::NoError;
}
Such function, when compiled into a shared library, say myLib.so
, could be loaded into WolframLanguage and used like this:
AddInts = LibraryFunctionLoad["myLib", "AddTwoIntegers", {Integer, Integer}, Integer];
AddInts[17, 25]
(* = 42 *)
Loading library functions ๐
In the example above we saw how library functions can be loaded from shared objects via LibraryFunctionLoad:
FunctionNameInWL = LibraryFunctionLoad["path/to/sharedLibrary", "FunctionNameInCppCode", {ArgumentType1, ArgumentType2, ...}, ResultType];
The syntax is described in details in LibraryLink ยป Functions, Arguments, and Results.
In case of WSTP library functions, the call gets simplified to:
FunctionNameInWL = LibraryFunctionLoad["path/to/sharedLibrary", "FunctionNameInCppCode", LinkObject, LinkObject];
It is common but not in any way required to have FunctionNameInWL
be equal to FunctionNameInCppCode
with a $
prepended, e.g.
$FunctionName = LibraryFunctionLoad["path/to/sharedLibrary", "FunctionName", LinkObject, LinkObject]
LLU expands the library loading mechanism in LibraryLink by providing convenient wrappers with extra options:
- SafeLibraryLoad[lib_]
Quietly attempts to load the dynamic library
lib
, and throws if it cannot be loaded.- PacletFunctionSet[resultSymbol_, lib_, f_, fParams_, fResultType_, opts___]
Attempts to load an exported function
f
from a dynamic librarylib
and assign the result toresultSymbol
. By default, the dynamic library name is taken from the library given toInitializePacletLibrary
(Paclet Library). A caveat is that if Paclet Library has been lazily initialized andPacletFunctionSet
is called with a path to it, then auto-loading of Paclet Library will not be triggered. By default, the name of the library function is assumed to be the same as the symbol name (sans any leading or trailing $โs).- Arguments:
resultSymbol
- a WL symbol to represent the loaded functionlib
- name of the dynamic library [optional]f
- name of the function to load from the dynamic library [optional]fParams
- parameter types of the library function to be loadedfResultType
- result type
- LazyPacletFunctionSet[resultSymbol_, lib_, f_, fParams_, fResultType_, opts___]
Lazy version of
PacletFunctionSet
which loads the function upon the first evaluation ofresultSymbol
.- WSTPFunctionSet[resultSymbol_, lib_, f_, opts___]
A convenient wrapper around
PacletFunctionSet
for easier loading of WSTP functions. Argument and result type are fixed asLinkObject
.- LazyWSTPFunctionSet[resultSymbol_, lib_, f_, opts___]
Lazy version of
WSTPFunctionSet
which loads the function upon the first evaluation ofresultSymbol
.- MemberFunctionSet[exprHead_][memberSymbol_?Developer`SymbolQ, lib_, f_, fParams_, retType_, opts___]
Loads a library function into
memberSymbol
that can be invoked on instances ofexprHead
like so:instance @ memberSymbol[โฆ]
- LazyMemberFunctionSet[exprHead_][memberSymbol_?Developer`SymbolQ, lib_, f_, fParams_, retType_, opts___]
Lazy version of
MemberFunctionSet
which loads the function upon the first evaluation ofmemberSymbol
.- WSTPMemberFunctionSet[exprHead_][memberSymbol_, lib_, f_, opts___]
A convenient wrapper around
MemberFunctionSet
for easier loading of WSTP member functions.- LazyWSTPMemberFunctionSet[exprHead_][memberSymbol_, lib_, f_, opts___]
Lazy version of
WSTPMemberFunctionSet
which loads the function upon the first evaluation ofmemberSymbol
.
There is also one lower level function which does not take a symbol as first argument but instead returns the loaded library function as the result
- PacletFunctionLoad[lib_, f_, fParams_, retType_, opts___]
Attempts to load an exported function
f
from a dynamic librarylib
and return it. UnlikePacletFunctionSet
, there is no mechanism by which to avoid eager loading of the default paclet library (i.e. there is no LazyPacletFunctionLoad). Iflib
is omitted, the dynamic library name is taken from the library given toInitializePacletLibrary
.
Supported options for all of the above functions include:
-
"Optional"
-> True | False
๐ Whether the library function is optional in the library, i.e. loading may fail quietly. Defaults to False.
-
"ProgressMonitor"
-> None | _Symbol
๐ Provide a symbol which will store the current progress of library function. See Progress monitor for details. Defaults to None.
-
"Throws"
-> True | False
๐ Whether the library function should throw Failure expressions on error or return them as the result. Defaults to True (so Failures will be thrown).
Reducing boilerplate code ๐
The set of utility functions described in the previous section allows you to reduce the amount of code you need to write in order to load functions from your pacletโs dynamic library to the Wolfram Language. Similarly, LLU provides a number of macros that eliminate the need to repeat the full signature for every library function.
After you include <LLU/LibraryLinkFunctionMacro.h>
instead of writing:
EXTERN_C DLLEXPORT int name (WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res);
you can type
-
LIBRARY_LINK_FUNCTION
(name) ๐ This macro forward declares and begins the definition of an extern โCโ LibraryLink function with given name.
For input parameter and return type explanation see the official LibraryLink guide. WolframLibraryData parameter is marked [[maybe_unused]] because it is a common workflow to take the instance of WolframLibraryData passed to WolframLibrary_initialize function and store it with LLU::LibraryData::setLibraryData so that it is accessible everywhere. With such setup one does not need to use the WolframLibraryData copy provided to every LibraryLink function.
And similarly instead of
EXTERN_C DLLEXPORT int name (WolframLibraryData libData, WSLINK wslp);
you can use
-
LIBRARY_WSTP_FUNCTION
(name) ๐ This macro forward declares and begins the definition of an extern โCโ LibraryLink function with given name, which uses WSTP to exchange data with WolframLanguage.
For input parameter and return type explanation see the official LibraryLink guide. WolframLibraryData parameter is marked [[maybe_unused]] because it is a common workflow to take the instance of WolframLibraryData passed to WolframLibrary_initialize function and store it with LLU::LibraryData::setLibraryData so that it is accessible everywhere. With such setup one does not need to use the WolframLibraryData copy provided to every LibraryLink function.
Finally, if you use exception-based error handling you will often end up writing code like this:
1 2 3 4 5 6 7 8 9 10 11 12 | EXTERN_C DLLEXPORT int name(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) {
auto err = ErrorCode::NoError;
try {
LLU::MArgumentManager mngr {libData, Argc, Args, Res};
// body of a function that effectively takes mngr as the single parameter
} catch (const LibraryLinkError& e) {
err = e.which();
} catch (...) {
err = ErrorCode::FunctionError;
}
return err;
}
|
Fortunately, there is a macro that allows you to focus only on the highlighted part:
-
LLU_LIBRARY_FUNCTION
(name) ๐ This macro provides all the boilerplate code needed for a typical exception-safe LibraryLink function.
LLU_LIBRARY_FUNCTION(MyFunction) defines a LibraryLink function MyFunction and a regular function impl_MyFunction of type void(LLU::MArgumentManager&), which is the one you need to provide a body for. All LLU::LibraryLinkError exceptions thrown from impl_MyFunction will be caught and the error code returned to LibraryLink. All other exceptions will also be caught and translated to a FunctionError.
- Note
While this macro saves quite a lot of typing it may also decrease code readability and make debugging harder so use with caution.
User-defined types ๐
LibraryLink supports a number of types as function arguments and for the majority of use cases the built-in types are enough. However, imagine you are writing
a library that operates on financial data and it processes amounts of money. For example, in the Wolfram Language you work with expressions like
Quantity[20.3, "USD"]
and in C++ you have a corresponding structure:
struct Money {
double amount;
std::string currency;
};
If you want to write a library function that takes an amount of money and a currency and converts that amount to the given currency, you will probably choose
{Real, String, String}
for argument types (Quantity
would be split into Real and String and the second String is for the new currency)
and "DataStore"
for the return type. This requires some extra code on the Wolfram Language side to extract Real and String from the Quantity and
on the C++ side to construct a DataStore from a Money object. Having large number of functions in the library that may repeat those translations, you will
probably decide to factor this extra code to helper functions.
You could then use your library in Wolfram Language as follows:
(* Load raw library function that operates on basic LibraryLink types *)
$ConvertMoney = LibraryFunctionLoad["myLib.so", "ConvertMoney", {Real, String, String}, "DataStore"];
(* Create a higher-level wrapper for users of your package *)
ConvertMoney[amount_Quantity, newCurrency_String] := With[
{
rawlibraryResult = $ConvertMoney[QuantityMagnitude[amount], QuantityUnit[amount], newCurrency];
},
$dataStoreToQuantity[rawLibraryResult] (* $dataStoreToQuantity is a small utility function, omitted for brevity *)
];
ConvertMoney[Quantity[50., "USD"], "PLN"]
(* = Quantity[XXX, "PLN"] *)
The implementation of ConvertMoney
in C++ would go along the lines:
EXTERN_C DLLEXPORT int ConvertMoney(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) {
LLU::MArgumentManager mngr {libData, Argc, Args, Res};
auto amount = mngr.get<double>(0);
auto oldCurrency = mngr.get<std::string>(1);
auto newCurrency = mngr.get<std::string>(2);
auto moneyToConvert = Money { amount, oldCurrency };
Money converted = myLib::convert(moneyToConvert, newCurrency);
mngr.set(myLib::MoneyToDataList(converted)); // myLib::MoneyToDataList is a helper function to convert Money object to a DataList
return LLU::ErrorCode::NoError;
}
This is a fine code and if you are satisfied with it, you can stop reading here. However, it is possible with LLU to implement the same functionality like this:
(* Load "ConvertMoney" function from "myLib.so" and assign it to ConvertMoney symbol *)
`LLU`PacletFunctionSet[ConvertMoney, "myLib.so", "ConvertMoney", {"Money", String}, "Money"];
(* No need for separate higher-level wrapper because the types are translated by LLU now. *)
ConvertMoney[Quantity[50., "USD"], "PLN"]
(* = Quantity[XXX, "PLN"] *)
and in C++
EXTERN_C DLLEXPORT int ConvertMoney(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) {
LLU::MArgumentManager mngr {libData, Argc, Args, Res};
auto moneyToConvert = mngr.get<Money>(0);
auto newCurrency = mngr.get<std::string>(2); // under the hood Money object is still sent as two values (Real + String), so new currency has index 2
Money converted = myLib::convert(moneyToConvert, newCurrency);
mngr.set(converted);
return LLU::ErrorCode::NoError;
}
The point is to delegate the translation between your types and LibraryLink types to LLU, so that you can write cleaner code that does not distract readers
with technicalities.
To achieve this, you need to teach LLU to understand your types. Here is how you register "Money"
as a library function argument type, the values of which
are of the form Quantity[_Real, _String]
:
`LLU`MArgumentType["Money", {Real, String}, (Sequence[QuantityMagnitude[#], QuantityUnit[#]]) &];
The second argument is the list of basic LibraryLink types that constitute to a single expression of type "Money"
. The third argument is a translation
function that takes something of the form Quantity[_Real, _String]
and produces a Sequence
of two values: Real and String.
In the C++ code we used mngr.get<Money>
, which means we have to tell LLU how many and what basic LibraryLink types correspond to a Money
object.
This is achieved by defining a specialization of CustomType
structure template and providing a type alias member CorrespondingTypes
which must be a
std::tuple
of corresponding basic LibraryLink types:
template<>
struct LLU::MArgumentManager::CustomType<Money> {
using CorrespondingTypes = std::tuple<double, std::string>;
};
With this information, whenever LLU is requested to read an argument of type Money
it will read two
consecutive input arguments as double
and std::string
, respectively, and construct a Money
object from those 2 values.
In many cases this is sufficient, however in some situations you may want to have full control over how LLU creates objects of your type. Imagine we want
to always capitalize the currency that is passed from Wolfram Language code, before creating a Money
object. To have such fine-grained control over
MArgumentManagerโs behavior, we must additionally specialize a struct template Getter
that provides a member function get
, like this:
template<>
struct LLU::MArgumentManager::Getter<Money> {
static Money get(const MArgumentManager& mngr, size_type index) {
auto [amount, currency] = mngr.getTuple<double, std::string>(index);
std::transform(currency.begin(), currency.end(), currency.begin(), [](unsigned char c){ return std::toupper(c); });
return Money { amount, std::move(currency) };
}
};
At this point, LLU knows how to change WL expressions of the form Quantity[_Real, _String]
into Money
objects in C++. The only thing left is to teach
LLU how to work in the other direction, i.e. how to return Money
objects via โDataStoreโ and change them into Quantity. First, let us specialize
MArgumentManager::set
template:
template<>
void LLU::MArgumentManager::set<Money>(const Money& m) const {
DataList<NodeType::Any> moneyDS;
moneyDS.push_back(m.amount);
moneyDS.push_back(m.currency);
set(moneyDS);
}
You can read more about DataList
in the section
about Containers. The last step is to tell LLU how to turn incoming DataStores into Quantities in library functions that declare โMoneyโ as return type:
`LLU`MResultType["Money", "DataStore", (Quantity @@ #)&];
Here we say that if a library function has return type โMoneyโ, then the corresponding LibraryLink type is โDataStoreโ and when we get such a DataStore
we need to apply a function (Quantity @@ #)&
to turn it into the form that we use to represent Money expressions.
Registering user-defined types in LLU may seem like a lot of extra work, but actually it is no extra work at all. It is merely a way to organize the code that you would previously have written anyway in the form of small utility functions scattered all over your library and possibly even duplicated, if you are not careful enough.
API reference ๐
-
class
LLU
::
MArgumentManager
๐ Manages arguments exchanged between the paclet C++ code and LibraryLink interface.
MArgumentManager provides a safe way to access MArguments received from LibraryLink and takes care of memory management both for in- and out- arguments. Using MArgumentManager one can perform generic operations on NumericArrays, Tensors and Images independent of their data type.
Public Types
-
using
size_type
= std::size_t ๐ Size type for indexing the list of arguments that MArgumentManager manages.
Public Functions
-
MArgumentManager
(mint Argc, MArgument *Args, MArgument &Res) ๐ Constructor.
-
MArgumentManager
(WolframLibraryData ld, mint Argc, MArgument *Args, MArgument &Res) ๐ Constructor.
-
template<typename
T
>
TgetInteger
(size_type index) const ๐ Get MArgument of type mint at position
index
with extra static_cast if needed.
-
std::complex<double>
getComplex
(size_type index) const ๐ Get MArgument of type mcomplex at position
index
.
-
char *
getCString
(size_type index) const ๐ Get value of MArgument of type โUTF8Stringโ at position
index
.
-
std::string
getString
(size_type index) const ๐ Get value of MArgument of type โUTF8Stringโ at position
index
.
-
template<typename
T
, PassingMode
= Passing::Automatic>
NumericArray<T>getNumericArray
(size_type index) const ๐ Get MArgument of type MNumericArray at position
index
and wrap it into NumericArray.
-
template<Passing
Mode
= Passing::Automatic>
GenericNumericArraygetGenericNumericArray
(size_type index) const ๐ Get MArgument of type MNumericArray at position
index
and wrap it into generic MContainer wrapper.
-
MNumericArray
getMNumericArray
(size_type index) const ๐ Get MArgument of type MNumericArray at position
index
.
-
template<typename
T
, PassingMode
= Passing::Automatic>
Tensor<T>getTensor
(size_type index) const ๐ Get MArgument of type MTensor at position
index
and wrap it into Tensor object.
-
template<Passing
Mode
= Passing::Automatic>
GenericTensorgetGenericTensor
(size_type index) const ๐ Get MArgument of type MTensor at position
index
and wrap it into generic MContainer wrapper.
-
template<typename
T
, PassingMode
= Passing::Automatic>
SparseArray<T>getSparseArray
(size_type index) const ๐ Get MArgument of type MSparseArray at position
index
and wrap it into SparseArray.
-
template<Passing
Mode
= Passing::Automatic>
GenericSparseArraygetGenericSparseArray
(size_type index) const ๐ Get MArgument of type MSparseArray at position
index
and wrap it into generic MContainer wrapper.
-
MSparseArray
getMSparseArray
(size_type index) const ๐ Get MArgument of type MSparseArray at position
index
.
-
template<typename
T
, PassingMode
= Passing::Automatic>
Image<T>getImage
(size_type index) const ๐ Get MArgument of type MImage at position
index
and wrap it into Image object.
-
template<Passing
Mode
= Passing::Automatic>
GenericImagegetGenericImage
(size_type index) const ๐ Get MArgument of type MImage at position
index
and wrap it into generic MContainer wrapper.
-
template<typename
T
, PassingMode
= Passing::Automatic>
DataList<T>getDataList
(size_type index) const ๐ Get DataStore with all nodes of the same type from MArgument at position
index
.
-
template<Passing
Mode
= Passing::Automatic>
GenericDataListgetGenericDataList
(size_type index) const ๐ Get MArgument of type DataStore at position
index
and wrap it into generic MContainer wrapper.
-
DataStore
getDataStore
(size_type index) const ๐ Get MArgument of type DataStore at position
index
.
-
template<class
ManagedExpr
, classDynamicType
= ManagedExpr>
DynamicType &getManagedExpression
(size_type index, ManagedExpressionStore<ManagedExpr> &store) const ๐ Get a reference to an instance of Managed Expression that was sent from Wolfram Language as argument to a library function.
Get a shared pointer to an instance of Managed Expression that was sent from Wolfram Language as argument to a library function.
-
template<typename
T
>
RequestedType<T>get
(size_type index) const ๐ Extract library function argument at given index and convert it from MArgument to a desired type.
-
template<typename ...
ArgTypes
>
std::tuple<RequestedType<ArgTypes>...>getTuple
(size_type index = 0) const ๐ Extract arguments from the Manager and return them as values of given types.
-
template<typename ...
ArgTypes
>
std::tuple<RequestedType<ArgTypes>...>getTuple
(std::array<size_type, sizeof...(ArgTypes)> indices) const ๐ Extract arguments from the Manager at given positions and return them as values of given types.
-
void
setBoolean
(bool result) noexcept ๐ Set
result
as output MArgument.
-
void
setReal
(double result) noexcept ๐ Set
result
as output MArgument.
-
void
setInteger
(mint result) noexcept ๐ Set
result
as output MArgument.
-
template<typename
T
>
boolsetMintAndCheck
(T result) noexcept ๐ Set
result
as output MArgument and check for overflow.
-
void
setComplex
(std::complex<double> c) noexcept ๐ Set
c
as output MArgument.
-
void
setString
(const std::string &str) ๐ Set
str
as output MArgument.
-
void
setString
(const char *str) ๐ This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
-
void
setString
(std::string &&str) ๐ This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
-
template<typename
T
>
voidsetNumericArray
(const NumericArray<T> &na) ๐ Set MNumericArray wrapped by
na
as output MArgument.
-
void
setMNumericArray
(MNumericArray na) ๐ Set MNumericArray as output MArgument.
-
template<typename
T
>
voidsetTensor
(const Tensor<T> &ten) ๐ Set MTensor wrapped by
ten
as output MArgument.
-
void
setMTensor
(MTensor t) ๐ Set MTensor as output MArgument.
-
template<typename
T
>
voidsetImage
(const Image<T> &im) ๐ Set MImage wrapped by
im
as output MArgument.
-
void
setMImage
(MImage im) ๐ Set MImage as output MArgument.
-
template<typename
T
>
voidsetDataList
(const DataList<T> &ds) ๐ Set DataStore wrapped in DataList
ds
as output MArgument.
-
void
setDataStore
(DataStore ds) ๐ Set DataStore as output MArgument.
-
template<typename
T
>
voidsetSparseArray
(const SparseArray<T> &sa) ๐ Set MSparseArray wrapped by
sa
as output MArgument.
-
void
setMSparseArray
(MSparseArray sa) ๐ Set MSparseArray as output MArgument.
-
void
set
(bool result) noexcept ๐ Set
result
as output MArgument.
-
void
set
(double result) noexcept ๐ Set
result
as output MArgument.
-
void
set
(mint result) noexcept ๐ Set
result
as output MArgument.
-
void
set
(std::complex<double> c) noexcept ๐ Set
c
as output MArgument.
-
void
set
(const std::string &str) ๐ Set
str
as output MArgument.
-
void
set
(const char *str) ๐ Set
str
as output MArgument.
-
void
set
(std::string &&str) ๐ Set
str
as output MArgument.
-
template<typename
T
>
voidset
(const NumericArray<T> &na) ๐ Set MNumericArray wrapped by
na
as output MArgument.
-
void
set
(const GenericNumericArray &na) ๐ Set MNumericArray wrapped by
na
as output MArgument.
-
template<typename
T
>
voidset
(const SparseArray<T> &ten) ๐ Set MSparseArray wrapped by
sa
as output MArgument.
-
void
set
(const GenericSparseArray &t) ๐ Set MSparseArray wrapped by
t
as output MArgument.
-
template<typename
T
>
voidset
(const Tensor<T> &ten) ๐ Set MTensor wrapped by
ten
as output MArgument.
-
void
set
(const GenericTensor &t) ๐ Set MTensor wrapped by
t
as output MArgument.
-
void
set
(const GenericImage &im) ๐ Set MImage wrapped by
im
as output MArgument.
-
template<typename
T
>
voidset
(const DataList<T> &ds) ๐ Set DataStore wrapped in DataList
ds
as output MArgument.
-
void
set
(const GenericDataList &ds) ๐ Set DataStore wrapped by
ds
as output MArgument.
-
template<typename
T
>
voidset
(const T &arg) ๐ Set given value as a result of the library function.
-
ProgressMonitor
getProgressMonitor
(double step = ProgressMonitor::getDefaultStep()) const ๐ Get ProgressMonitor shared with WL Kernel.
-
numericarray_data_t
getNumericArrayType
(size_type index) const ๐ Get type of MNumericArray at position
index
inArgs
.
-
template<Passing
Mode
, classOperator
, class ...OpArgs
>
voidoperateOnNumericArray
(size_type index, OpArgs&&... opArgs) ๐ Perform operation on NumericArray created from MNumericArray argument at position
index
inArgs
.
-
template<Passing
Mode
= Passing::Automatic, classOperator
>
voidoperateOnNumericArray
(size_type index, Operator &&op) ๐ Perform operation on NumericArray created from MNumericArray argument at position
index
inArgs
.
-
unsigned char
getTensorType
(size_type index) const ๐ Get type of MTensor at position
index
inArgs
.
-
template<Passing
Mode
, classOperator
, class ...Args
>
voidoperateOnTensor
(size_type index, Args&&... opArgs) ๐ Perform operation on Tensor created from MTensor argument at position
index
inArgs
.
-
template<Passing
Mode
= Passing::Automatic, classOperator
>
voidoperateOnTensor
(size_type index, Operator &&op) ๐ Perform operation on Tensor created from MTensor argument at position
index
inArgs
.
-
template<typename
T
>
structCustomType
๐ Helper structure that can be used to register user-defined argument types in LLU.
If you want a type X to be supported as template argument for MArgumentManager::get<>, you must specialize CustomType<> for X and this specialization must contain a type alias CorrespondingTypes which is defined to be a std::tuple of basic LibraryLink types, from which an object of type X can be constructed. See online docs and MArgumentManager unit tests for examples.
- Template Parameters
T
: - any type you would like to treat as a user-defined LibraryLink argument type
-
template<typename
T
>
structGetter
๐ Helper structure to fully customize the way MArgumentManager reads T as argument type.
If T is a user-defined argument type, LLU will by default attempt to create an object of type T by reading values of corresponding types and feeding it to a constructor of T. Specialize Getter<> to override this behavior.
- Template Parameters
T
: - any type, for which you would like full control over how MArgumentManager reads arguments of that type
- Note
Every user-defined argument type must specialize CustomType<>, specializing Getter<> is optional.
Public Static Functions
-
T
get
(const MArgumentManager &mngr, size_type firstIndex) ๐ A function that tells LLU how to interpret an object of a user-defined type as an argument of a library function This function is used internally by MArgumentManager::get.
-
template<class
Container
, PassingMode
>
structManaged
๐ Helper struct to โattachโ a passing mode to container type when passing it as template argument to MArgumentManager::getTuple.
- Template Parameters
Container
: - any generic or strongly typed container wrapper type (e.g. GenericImage, Tensor<mint>, etc.)Mode
: - passing mode for the container
-
template<typename
T
>
structSetter
๐ Helper structure to fully customize the way MArgumentManager sets an object of type T as result of a library function.
- Note
You can explicitly specialize MArgumentManager::set for your type T, but having Setter<> allows you to define partial specializations.
Public Static Functions
-
void
set
(MArgumentManager&, const T&) ๐ A function that tells LLU how to send an object of a user-defined type as a result of a library function This function is used internally by MArgumentManager::set.
-
using