Containers πŸ”—

Raw LibraryLink containers like MTensor or MNumericArray store their element type as a regular field in the structure. This means that the type cannot be used at compile-time, which makes writing generic code that does something with the underlying data very difficult (lots of switches on the element type and code repetition).

On the other hand, having the element type as template parameter, like STL containers, is often inconvenient and requires some template magic for simple things like passing forward the container or reading metadata when the data type is not known a priori.

To get the best of both worlds and to make the library suitable for different needs, LLU provides two categories of container wrappers - generic, datatype-agnostic wrappers and full-fledged wrappers templated with the datatype. This is illustrated in the table below:

LibraryLink element

Generic wrapper

Typed wrapper

MTensor

GenericTensor

Tensor<T>

MNumericArray

GenericNumericArray

NumericArray<T>

MImage

GenericImage

Image<T>

DataStore

GenericDataList

DataList<T>

MSparseArray

GenericSparseArray

SparseArray<T>

Memory management πŸ”—

When passing a container from Wolfram Language to a C++ library, one of 4 passing modes must be chosen:

  • Automatic

  • Constant

  • Manual

  • Shared

With the exception of DataStore, which cannot be Constant or Shared.

More about memory management can be found in the LibraryLink documentation.

In plain LibraryLink, the choice you make is reflected only in the Wolfram Language code where LibraryFunctionLoad specifies the list of parameters for the library function. There is no way to query the WolframLibraryData or MArgument about the passing modes of function arguments from within C++ code. Therefore, the programmer must remember the passing mode for each argument and then ensure the correct action is taken (releasing/not releasing memory depending on the combination of passing mode and whether the container has been returned from the library function to the Wolfram Language).

LLU defines a notion of container ownership:

enum LLU::Ownership πŸ”—

An enum listing possible owners of a LibraryLink container.

Ownership determines the memory management of a container.

Values:

enumerator LibraryLink πŸ”—

LibraryLink is responsible for managing the container’s memory. Corresponds to Automatic and β€œConstant” passing.

enumerator Library πŸ”—

The library (LLU) is responsible for managing the container’s memory. Used for Manual passing and containers created by the library.

enumerator Shared πŸ”—

When the container is shared LLU only needs to decrease share count when it’s done. Only used for arguments passed as β€œShared”.

LLU ensures that at any point of time every container has a well-defined owner. The ownership is mostly static and may change only on a few occasions e.g. when passing a container to DataList or setting it as a result of a library function.

When a container is received from the Wolfram Language as an argument to a library function, the developer must inform the MArgumentManager about the passing mode used for that container. There is a separate enumeration for this purpose:

enum LLU::Passing πŸ”—

Enumerated type representing different modes in which a container can be passed from LibraryLink to the library.

See

https://reference.wolfram.com/language/LibraryLink/tutorial/InteractionWithWolframLanguage.html#97446640

Values:

enumerator Automatic πŸ”—
enumerator Constant πŸ”—
enumerator Manual πŸ”—
enumerator Shared πŸ”—

The Passing value is used by the MArgumentManager to determine the initial owner of the container.

Here are some examples:

LLU::Tensor<mint> t { 1, 2, 3, 4, 5 };    // this Tensor is created (and therefore owned) by the library (LLU)

LLU::MArgumentManager manager {...};
auto tensor = manager.getTensor<double>(0);  // tensors acquired via MArgumentManager are by default owned by the LibraryLink

auto image = manager.getGenericImage<LLU::Passing::Shared>(0);    // the image is shared between LLU and the Kernel, so LLU knows not to deallocate
                                                                  // the underlying MImage when image goes out of scope

auto newImage = image.clone();    // the newImage has the same contents as image but it is not shared, it is owned by LLU

More examples can be found in the unit tests.

Raw Containers πŸ”—

These are just raw LibraryLink containers.

DataStore πŸ”—

DataStore is C structure (technically, a pointer to structure) defined in the WolframLibrary. It is a unidirectional linked list of immutable nodes. Each node consists of a name (char*) and value (MArgument). DataStore itself can be stored in the MArgument union, which means that DataStores can be nested. DataStores can be passed to and from library functions. Existing nodes cannot be removed but adding new nodes is supported.

The complete DataStore API can be found inside Wolfram Language (12.0+) installations at SystemFiles/IncludeFiles/C/WolframIOLibraryFunctions.h.

On the Wolfram Language side a DataStore is represented as an expression with head Developer`DataStore that takes a list of expressions, where each expressions is either:

  • a value of type supported by LibraryLink (String, Integer, NumericArray, etc.)

  • a Rule with the LHS being a String and RHS of the form described in the previous point

For example:

Developer`DataStore["node_name1" -> 42, NumericArray[{1,2,3,4}, "Integer8"], "node_name3" -> "node_value3"]

MImage πŸ”—

A structure corresponding to Wolfram Language expressions Image and Image3D. Documented in LibraryLink Β» MImage.

MNumericArray πŸ”—

A structure corresponding to Wolfram Language expressions NumericArray. Documented in LibraryLink Β» MNumericArray.

MTensor πŸ”—

A structure corresponding to packed arrays in the Wolfram Language. Documented in LibraryLink Β» MTensor.

MSparseArray πŸ”—

A structure corresponding to Wolfram Language expressions SparseArray. Documented in LibraryLink Β» MSparseArray.

Generic Wrappers πŸ”—

These are datatype-unaware wrappers that offer automatic memory management and basic interface-like access to metadata (dimensions, rank, etc). They do not provide direct access to the underlying data except via a void* (or via a generic node type LLU::NodeType::Any in case of a GenericDataList).

Tip

All generic and strongly-typed wrappers are movable but non-copyable, instead they provide a clone() method for performing deep copies. This is in accordance with rule C.67 from the C++ Core Guidelines but most of all preventing accidental deep copies of containers is beneficial in terms of performance.

LLU::GenericDataList πŸ”—

GenericDataList is a light-weight wrapper over DataStore. It offers access to the underlying nodes via iterators and a push_back method for appending new nodes. You can also get the length of the list.

Here is an example of GenericDataList in action:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Reverse each string in a list of strings using GenericDataList */
LIBRARY_LINK_FUNCTION(ReverseStrings) {
   LLU::MArgumentManager mngr {libData, Argc, Args, Res};

   // read the input GenericDataList
   auto dsIn = mngr.get<LLU::GenericDataList>(0);

   // create new GenericDataList to store reversed strings
   LLU::GenericDataList dsOut;

   for (auto node : dsIn) {
      // GenericDataList may store nodes of arbitrary type, so we need to explicitly ask to get the string value from the node
      std::string_view s = node.as<LLU::NodeType::UTF8String>();

      std::string reversed {s.rbegin(), s.rend()};   // create reversed copy

      // we push back the reversed string via a string_view, this is safe because GenericDataList will immediately copy the string
      dsOut.push_back(std::string_view(reversed));
   }

   // set the GenericDataList as the result of the library function
   mngr.set(dsOut);
   return LLU::ErrorCode::NoError;
}

Technically, GenericDataList is an alias:

using LLU::GenericDataList = MContainer<MArgumentType::DataStore> πŸ”—

MContainer specialization for DataStore is called GenericDataList.

template<>
class LLU::MContainer<MArgumentType::DataStore> : public LLU::MContainerBase<MArgumentType::DataStore> πŸ”—

MContainer specialization for DataStore, provides basic list interface for the underlying raw DataStore.

Subclassed by LLU::DataList< T >

Public Types

using iterator = DataStoreIterator πŸ”—

GenericDataList iterator is DataStoreIterator.

using const_iterator = iterator πŸ”—

Const iterator over GenericDataList is the same as regular iterator - DataStoreIterator, because it is a proxy iterator.

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

MContainer() πŸ”—

Default constructor, creates empty DataStore owned by the Library.

MContainer(Container c, Ownership owner) πŸ”—

Create new MContainer wrapping a given raw DataStore.

Parameters
  • c: - a DataStore

  • owner: - who manages the memory the raw DataStore

Note

An exception will be thrown if you try to create a Shared DataStore because LibraryLink does not allow for shared DataStores.

MContainer clone() const πŸ”—

Clone this MContainer, performs a deep copy of the underlying DataStore.

Note

The cloned MContainer always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new MContainer, by value

mint length() const πŸ”—

Get the length of the DataStore.

Return

total number of nodes in the DataStore

DataStoreNode front() const πŸ”—

Get the first node of the DataStore.

Return

first node, if it doesn’t exist the behavior is undefined

DataStoreNode back() const πŸ”—

Get the last node of the DataStore.

Return

last node, if it doesn’t exist the behavior is undefined

iterator begin() const πŸ”—

Proxy iterator to the first element of the DataStore.

iterator end() const πŸ”—

Proxy iterator past the last element of the DataStore.

const_iterator cbegin() const πŸ”—

Proxy iterator to the first element of the DataStore.

const_iterator cend() const πŸ”—

Proxy iterator past the last element of the DataStore.

template<typename T, EnableIfArgumentType<T> = 0>
void push_back(T nodeValue) πŸ”—

Add new nameless node at the end of the underlying DataStore.

Template Parameters
  • T: - any valid argument type (either primitive or a wrapper) except for MTensor/MNumericArray

Parameters
  • nodeValue: - value to be moved to the new DataStore node

Warning

MTensor and MNumericArray are actually the same type, so this function cannot handle them correctly as LLU would not be able to figure out which function from the LibraryLink API to call. Use push_back templated with MArgumentType instead.

template<typename T, EnableIfArgumentType<T> = 0>
void push_back(std::string_view name, T nodeValue) πŸ”—

Add new named node at the end of the underlying DataStore.

Template Parameters
  • T: - any valid argument type (either primitive or a wrapper) except for MTensor/MNumericArray

Parameters
  • name: - name of the new node, names in a DataStore do not have to be unique

  • nodeValue: - value to be moved to the new DataStore node

Warning

MTensor and MNumericArray are actually the same type, so this function cannot handle them correctly as LLU would not be able to figure out which function from the LibraryLink API to call. Use push_back templated with MArgumentType instead.

template<MArgumentType Type, EnableIfUnambiguousWrapperType<Type> = 0>
void push_back(Argument::WrapperType<Type> nodeValue) πŸ”—

Add new nameless node at the end of the underlying DataStore.

Template Parameters
  • Type: - type of the node data expressed via the MArgumentType enum

Parameters
  • nodeValue: - a value to be pushed as the new node, must be a wrapper over a primitive LibraryLink type

template<MArgumentType Type, EnableIfUnambiguousWrapperType<Type> = 0>
void push_back(std::string_view name, Argument::WrapperType<Type> nodeValue) πŸ”—

Add new named node at the end of the underlying DataStore.

Template Parameters
  • Type: - type of the node data expressed via the MArgumentType enum

Parameters
  • name: - name of the new node, names in a DataStore do not have to be unique

  • nodeValue: - a value to be pushed as the new node, must be a wrapper over a primitive LibraryLink type

template<MArgumentType Type>
void push_back(Argument::CType<Type> nodeValue) πŸ”—

Add new nameless node at the end of the underlying DataStore.

Template Parameters
  • Type: - type of the node data expressed via the MArgumentType enum

Parameters
  • nodeValue: - a value to be pushed as the new node, must be of a primitive LibraryLink type

template<MArgumentType Type>
void push_back(std::string_view name, Argument::CType<Type> nodeValue) πŸ”—

Add new named node at the end of the underlying DataStore.

Template Parameters
  • Type: - type of the node data expressed via the MArgumentType enum

Parameters
  • name: - name of the new node, names in a DataStore do not have to be unique

  • nodeValue: - a value to be pushed as the new node, must be of a primitive LibraryLink type

void push_back(const Argument::Typed::Any &node) πŸ”—

Add new nameless node at the end of the underlying DataStore.

Parameters
  • node: - a value to be pushed as the new node

void push_back(std::string_view name, const Argument::Typed::Any &node) πŸ”—

Add new named node at the end of the underlying DataStore.

Parameters
  • name: - name of the new node, names in a DataStore do not have to be unique

  • node: - a value to be pushed as the new node,

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

LLU::GenericImage πŸ”—

GenericImage is a light-weight wrapper over MImage. It offers the same API as LibraryLink has for MImage, except for access to the image data, because GenericImage is not aware of the image data type. Typically one would use GenericImage to take an Image of unknown type from LibraryLink, investigate image properties and data type and then upgrade the GenericImage to the strongly-typed one in order to perform operations on the image data.

Here is an example of GenericImage in action:

1
2
3
4
5
6
7
/* Get the number of columns in the input Image */
LIBRARY_LINK_FUNCTION(GetColumnCount) {
   LLU::MArgumentManager mngr {libData, Argc, Args, Res};
   const auto image = mngr.getGenericImage<LLU::Passing::Constant>(0);
   mngr.setInteger(image.columns());
   return LLU::ErrorCode::NoError;
}
using LLU::GenericImage = MContainer<MArgumentType::Image> πŸ”—

MContainer specialization for MImage is called GenericImage.

template<>
class LLU::MContainer<MArgumentType::Image> : public LLU::ImageInterface, public LLU::MContainerBase<MArgumentType::Image> πŸ”—

MContainer specialization for MImage.

Subclassed by LLU::Image< T >

Public Types

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

MContainer() = default πŸ”—

Default constructor, the MContainer does not manage any instance of MImage.

MContainer(mint width, mint height, mint channels, imagedata_t type, colorspace_t colorSpace, mbool interleaving) πŸ”—

Create new 2D MImage based on given parameters.

Parameters
  • width: - image width in pixels (number of columns)

  • height: - image height in pixels (number of rows)

  • channels: - number of color channels (for example 3 for RGB, 1 for greyscale)

  • type: - image data type (1-bit, 8-bit, Real32, etc.)

  • colorSpace: - image color space

  • interleaving: - whether the image data should be interleaved or not

MContainer(mint slices, mint width, mint height, mint channels, imagedata_t type, colorspace_t colorSpace, mbool interleaving) πŸ”—

Create new 2D or 3D MImage based on given parameters.

Parameters
  • slices: - number of slices (0 for 2D Image, any positive number for Image3D)

  • width: - image width in pixels (number of columns)

  • height: - image height in pixels (number of rows)

  • channels: - number of color channels (for example 3 for RGB, 1 for greyscale)

  • type: - image data type (1-bit, 8-bit, Real32, etc.)

  • colorSpace: - image color space

  • interleaving: - whether the image data should be interleaved or not

GenericImage convert(imagedata_t t, mbool interleavingQ) const πŸ”—

Convert this object to a new GenericImage of given datatype, optionally changing interleaving.

Parameters
  • t: - destination data type

  • interleavingQ: - whether the converted GenericImage should be interleaved or not

Return

converted GenericImage owned by the Library

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_convertType.html

GenericImage convert(imagedata_t t) const πŸ”—

Convert this object to a new GenericImage of given datatype.

Parameters
  • t: - destination data type

Return

converted GenericImage owned by the Library

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_convertType.html

MContainer clone() const πŸ”—

Clone this MContainer, performs a deep copy of the underlying MImage.

Note

The cloned MContainer always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new MContainer, by value

colorspace_t colorspace() const override πŸ”—

Get colorspace which describes how colors are represented as numbers.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getColorSpace.html

mint rows() const override πŸ”—

Get number of rows.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getRowCount.html

mint columns() const override πŸ”—

Get number of columns.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getColumnCount.html

mint slices() const override πŸ”—

Get number of slices.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getSliceCount.html

mint channels() const override πŸ”—

Get number of channels.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getChannels.html

bool alphaChannelQ() const override πŸ”—

Check if there is an alpha channel in the image.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_alphaChannelQ.html

bool interleavedQ() const override πŸ”—

Check if the image is interleaved.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_interleavedQ.html

bool is3D() const override πŸ”—

Check if the image is 3D.

mint getRank() const override πŸ”—

Get rank.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getRank.html

mint getFlattenedLength() const override πŸ”—

Get the total number of pixels in the image.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getFlattenedLength.html

imagedata_t type() const override πŸ”—

Get the data type of the image.

Return

type of elements (see definition of imagedata_t)

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getDataType.html

void *rawData() const override πŸ”—

Get access to raw image data.

Use with caution.

Return

pointer to the raw data

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getRawData.html

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

LLU::GenericNumericArray πŸ”—

GenericNumericArray is a light-weight wrapper over MNumericArray. It offers the same API as LibraryLink has for MNumericArray, except for access to the underlying array data, because GenericNumericArray is not aware of the array data type. Typically on would use GenericNumericArray to take a NumericArray of unknown type from LibraryLink, investigate its properties and data type and then upgrade the GenericNumericArray to the strongly-typed one in order to perform operations on the underlying data.

Here is an example of GenericNumericArray in action:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* Return the largest dimension of the input NumericArray */
LIBRARY_LINK_FUNCTION(GetLargestDimension) {
   LLU::MArgumentManager mngr {libData, Argc, Args, Res};
   const auto numericArray = mngr.getGenericNumericArray<LLU::Passing::Constant>(0);

   // The list of dimensions of the NumericArray will never be empty because scalar NumericArrays are forbidden
   auto maxDim = *std::max_element(numericArray.getDimensions(), std::next(numericArray.getDimensions(), numericArray.getRank()));
   mngr.setInteger(maxDim);
   return LLU::ErrorCode::NoError;
}
using LLU::GenericNumericArray = MContainer<MArgumentType::NumericArray> πŸ”—

MContainer specialization for MNumericArray is called GenericNumericArray.

template<>
class LLU::MContainer<MArgumentType::NumericArray> : public LLU::NumericArrayInterface, public LLU::MContainerBase<MArgumentType::NumericArray> πŸ”—

MContainer specialization for MNumericArray.

Subclassed by LLU::NumericArray< T >

Public Types

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

MContainer() = default πŸ”—

Default constructor, the MContainer does not manage any instance of MNumericArray.

MContainer(numericarray_data_t type, mint rank, const mint *dims) πŸ”—

Create GenericNumericArray of given type and shape.

Parameters
  • type: - new GenericNumericArray type

  • rank: - new GenericNumericArray rank

  • dims: - new GenericNumericArray dimensions

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_new.html

GenericNumericArray convert(numericarray_data_t t, NA::ConversionMethod method, double param) const πŸ”—

Convert this object to a new GenericNumericArray of given datatype, using specified conversion method.

Parameters
  • t: - destination data type

  • method: - conversion method

  • param: - conversion method parameter (aka tolerance)

Return

converted GenericNumericArray owned by the Library

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_convertType.html

MContainer clone() const πŸ”—

Clone this MContainer, performs a deep copy of the underlying MNumericArray.

Note

The cloned MContainer always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new MContainer, by value

mint getRank() const override πŸ”—

Get rank.

Return

number of dimensions in the array

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getRank.html

mint const *getDimensions() const override πŸ”—

Get dimensions.

Return

raw pointer to dimensions of the array

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getDimensions.html

mint getFlattenedLength() const override πŸ”—

Get length.

Return

total number of elements

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getFlattenedLength.html

numericarray_data_t type() const override πŸ”—

Get the data type of this array.

Return

type of elements (see definition of numericarray_data_t)

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getDataType.html

void *rawData() const noexcept override πŸ”—

Get access to the raw data.

Use with caution.

Return

pointer to the raw data

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getData.html

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

LLU::GenericTensor πŸ”—

GenericTensor is a light-weight wrapper over MTensor. It offers the same API that LibraryLink has for MTensor, except for access to the underlying array data because GenericTensor is not aware of the array data type. Typically on would use GenericTensor to take a Tensor of an unknown type from LibraryLink, investigate its properties and data type, then upgrade the GenericTensor to the strongly-typed one in order to perform operations on the underlying data.

using LLU::GenericTensor = MContainer<MArgumentType::Tensor> πŸ”—

MContainer specialization for MTensor is called GenericTensor.

template<>
class LLU::MContainer<MArgumentType::Tensor> : public LLU::TensorInterface, public LLU::MContainerBase<MArgumentType::Tensor> πŸ”—

MContainer specialization for MTensor.

Subclassed by LLU::Tensor< T >, LLU::Tensor< double >

Public Types

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

MContainer() = default πŸ”—

Default constructor, the MContainer does not manage any instance of MTensor.

MContainer(mint type, mint rank, const mint *dims) πŸ”—

Create GenericTensor of given type and shape.

Parameters
  • type: - new GenericTensor type (MType_Integer, MType_Real or MType_Complex)

  • rank: - new GenericTensor rank

  • dims: - new GenericTensor dimensions

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MTensor_new.html

MContainer clone() const πŸ”—

Clone this MContainer, performs a deep copy of the underlying MTensor.

Note

The cloned MContainer always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new MContainer, by value

mint getRank() const override πŸ”—

Get rank.

Return

number of dimensions in this tensor

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MTensor_getRank.html

mint const *getDimensions() const override πŸ”—

Get dimensions.

Return

raw pointer to dimensions of this tensor

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MTensor_getDimensions.html

mint getFlattenedLength() const override πŸ”—

Get total length.

Return

total number of elements

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MTensor_getFlattenedLength.html

mint type() const override πŸ”—

Get the data type of this tensor.

Return

type of elements (MType_Integer, MType_Real or MType_Complex)

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MTensor_getType.html

void *rawData() const override πŸ”—

Get raw pointer to the data of this tensor.

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

LLU::GenericSparseArray πŸ”—

GenericSparseArray is a light-weight wrapper over MSparseArray. It offers the same API that LibraryLink has for MSparseArray, except for access to the underlying array data because GenericSparseArray is not aware of the array data type. Typically one would use GenericSparseArray to take an MSparseArray of an unknown type from LibraryLink, investigate its properties and data type, then upgrade the GenericSparseArray to the strongly-typed one in order to perform operations on the underlying data.

using LLU::GenericSparseArray = MContainer<MArgumentType::SparseArray> πŸ”—

MContainer specialization for MSparseArray is called GenericSparseArray.

template<>
class LLU::MContainer<MArgumentType::SparseArray> : public LLU::MContainerBase<MArgumentType::SparseArray> πŸ”—

MContainer specialization for MSparseArray.

Subclassed by LLU::SparseArray< T >

Public Types

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

MContainer() = default πŸ”—

Default constructor, the MContainer does not manage any instance of MSparseArray.

MContainer(const GenericTensor &positions, const GenericTensor &values, const GenericTensor &dimensions, const GenericTensor &implicitValue) πŸ”—

Create a new SparseArray from positions, values, dimensions and an implicit value.

Parameters
  • positions: - positions of all the explicit values in the array

  • values: - explicit values to be stored in the array

  • dimensions: - dimensions of the new SparseArray

  • implicitValue: - implicit value (the one that is not stored) of the new SparseArray

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_fromExplicitPositions.html

MContainer(const GenericTensor &data, const GenericTensor &implicitValue) πŸ”—

Create a new SparseArray from data array and an implicit value.

Parameters
  • data: - a tensor whose contents will be copied and sparsified

  • implicitValue: - implicit value (the one that is not stored) of the new SparseArray

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_fromMTensor.html

MContainer(const GenericSparseArray &s, const GenericTensor &implicitValue) πŸ”—

Create a copy of given SparseArray with different implicit value.

Parameters
See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_resetImplicitValue.html

MContainer clone() const πŸ”—

Clone this MContainer, performs a deep copy of the underlying MSparseArray.

Note

The cloned MContainer always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new MContainer, by value

GenericTensor getImplicitValueAsTensor() const πŸ”—

Get the implicit value of this sparse array.

Return

Rank 0 tensor of the same type as the value type of this sparse array.

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getImplicitValue.html

void setImplicitValueFromTensor(const GenericTensor &implicitValue) πŸ”—

Change the implicit value of this array.

Parameters
  • implicitValue: - new implicit value

Note

The underlying MSparseArray object may be replaced in the process.

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_resetImplicitValue.html

mint getRank() const πŸ”—

Get the rank (number of dimensions) of this sparse array.

Return

the rank of this array

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getRank.html

mint const *getDimensions() const πŸ”—

Get dimensions of this sparse array.

Return

a read-only raw array of container dimensions

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getDimensions.html

GenericTensor getExplicitValues() const πŸ”—

Get a tensor with the values corresponding to the explicitly stored positions in the sparse array.

Return

GenericTensor of rank 1 with length equal to the number of explicit positions in the array or an empty wrapper for β€œpattern sparse arrays”

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getExplicitValues.html

GenericTensor getRowPointers() const πŸ”—

Get a row pointer array for this sparse array.

The values returned are the cumulative number of explicitly represented elements for each row, so the values will be non-decreasing.

Return

GenericTensor of rank 1 and integer type or an empty GenericTensor

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getRowPointers.html

GenericTensor getColumnIndices() const πŸ”—

Get the column indices for the explicitly stored positions in this sparse array.

The first dimension of the resulting tensor is the number of explicit positions, and the second dimension is equal to getRank() - 1.

Return

GenericTensor of rank 2 or an empty GenericTensor

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getColumnIndices.html

GenericTensor getExplicitPositions() const πŸ”—

Get the explicitly specified positions in this sparse array.

The first dimension of the resulting tensor is the number of explicit positions, and the second dimension is equal to getRank().

Return

GenericTensor of rank 2 or an empty GenericTensor

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getExplicitPositions.html

GenericTensor toGenericTensor() const πŸ”—

Expand this sparse array to a regular tensor.

Return

GenericTensor of the same data type as this array

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_toMTensor.html

void resparsify() πŸ”—

Use current implicit value to recalculate the sparse array after the data has been modified.

mint type() const πŸ”—

Get the data type of this MSparseArray.

Return

type of elements (MType_Integer, MType_Real or MType_Complex)

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

Typed Wrappers πŸ”—

Typed wrappers are full-fledged wrappers with automatic memory management (see section below), type-safe data access, iterators, etc. All typed wrappers are movable but non-copyable, instead they provide a clone() method for performing deep copies.

LLU::DataList<T> πŸ”—

DataList is a strongly-typed wrapper derived from GenericDataList in which all nodes must be of the same type and be known at compile time. Template parameter T denotes the value type of nodes. Supported node value types are shown below with corresponding types of raw DataStore nodes and with underlying C++ types:

Node Type Name

Underlying Type

Raw DataStoreNode Type

NodeType::Boolean

bool

mbool

NodeType::Integer

mint

mint

NodeType::Real

double

mreal

NodeType::Complex

std::complex<double>

mcomplex

NodeType::Tensor

LLU::GenericTensor

MTensor

NodeType::SparseArray

LLU::GenericSparseArray

MSparseArray

NodeType::NumericArray

LLU::GenericNumericArray

MNumericArray

NodeType::Image

LLU::GenericImage

MImage

NodeType::UTF8String

std::string_view

char*

NodeType::DataStore

LLU::GenericDataList

DataStore

LLU::NodeType is a namespace alias for LLU::Argument::Typed which is defined as follows:

namespace LLU::Argument::Typed πŸ”—

Namespace defining C++ types corresponding to primitive LibraryLink argument types.

Mainly used for node types in DataList.

Typedefs

using Boolean = bool πŸ”—

Boolean type, corresponds to True or False in the Wolfram Language.

using Integer = mint πŸ”—

Machine integer type.

using Real = double πŸ”—

Double precision floating point type.

using Complex = std::complex<double> πŸ”—

Complex number type, bitwise-compatible with mcomplex defined in WolframLibrary.h.

using Tensor = MContainer<MArgumentType::Tensor> πŸ”—

Tensor stands for a GenericTensor - type agnostic wrapper over MTensor.

using SparseArray = MContainer<MArgumentType::SparseArray> πŸ”—

SparseArray stands for a GenericSparseArray - type agnostic wrapper over MSparseArray.

using NumericArray = MContainer<MArgumentType::NumericArray> πŸ”—

NumericArray stands for a GenericNumericArray - type agnostic wrapper over MNumericArray.

using Image = MContainer<MArgumentType::Image> πŸ”—

Image stands for a GenericImage - type agnostic wrapper over MImage.

using UTF8String = std::string_view πŸ”—

String values from LibraryLink (char*) are wrapped in std::string_view.

using DataStore = MContainer<MArgumentType::DataStore> πŸ”—

DataStore stands for a GenericDataList - type agnostic wrapper over DataStore.

using Any = TypedArgument πŸ”—

Any is a union of all supported types. Typed::Any can be used as a template parameter for DataList to get a heterogeneous DataList.

Notice that LLU::NodeType::Any (or equivalently LLU::Argument::Typed::Any) is a special type which is a union of all other types from its namespace. In a way it corresponds to MArgument type in LibraryLink. A DataList with node type LLU::NodeType::Any can store nodes of any types so it is quite similar to LLU::GenericDataList but it has the interface of DataList, meaning that it offers more advanced iterators and more constructors.

Here is an example of the DataList class in action:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/* Take a list of named nodes with complex numbers and create two new lists: a list of node names and a list of node values */
LIBRARY_LINK_FUNCTION(SeparateKeysAndValues) {
   LLU::MArgumentManager mngr {libData, Argc, Args, Res};

   auto dsIn = mngr.getDataList<LLU::NodeType::Complex>(0);
   LLU::DataList<LLU::NodeType::UTF8String> keys;
   LLU::DataList<LLU::NodeType::Complex> values;

   // For each node in the input DataList push its name to "keys" and its value to "values"
   for (auto [name, value] : dsIn) {
     keys.push_back(name);
     values.push_back(value);
   }

   LLU::DataList<LLU::GenericDataList> dsOut;
   dsOut.push_back("Keys", std::move(keys));
   dsOut.push_back("Values", std::move(values));

   mngr.set(dsOut);
   return LLU::ErrorCode::NoError;
}

On the Wolfram Language side, we can load and use this function as follows:

`LLU`PacletFunctionSet[SeparateKeysAndValues, "SeparateKeysAndValues", {"DataStore"}, "DataStore"];

SeparateKeysAndValues[Developer`DataStore["a" -> 1 + 2.5 * I, "b" -> -3. - 6.I, 2I]]

(* Out[] = Developer`DataStore["Keys" -> Developer`DataStore["a", "b", ""], "Values" -> Developer`DataStore[1. + 2.5 * I, -3. - 6.I, 2.I]] *)
template<typename T>
class LLU::DataList : public LLU::MContainer<MArgumentType::DataStore> πŸ”—

Top-level wrapper over LibraryLink’s DataStore.

Designed to be strongly typed i.e. to wrap only homogeneous DataStores but by passing NodeType::Any as template parameter it will work with arbitrary DataStores.

Template Parameters
  • T: - type of data stored in each node, see the NodeType namespace for possible node types

Public Types

using iterator = NodeIterator<T> πŸ”—

Default DataList iterator is NodeIterator<T>

using const_iterator = iterator πŸ”—

All DataList iterators are proxy iterators so in a way they are all const, therefore const_iterator is the same as iterator.

using value_iterator = NodeValueIterator<T> πŸ”—

To iterate over node values use a proxy iterator NodeValueIterator<T>

using name_iterator = NodeNameIterator πŸ”—

To iterate over node names use a proxy iterator NodeNameIterator.

using value_type = T πŸ”—

Value of a node is of type T.

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

DataList(GenericDataList gds) πŸ”—

Create DataList wrapping around an existing GenericDataList.

Parameters
  • gds: - GenericDataList

DataList(std::initializer_list<value_type> initList) πŸ”—

Create DataList from list of values.

Keys will be set to empty strings.

Parameters
  • initList: - list of values to put in the DataList

Note

This constructor can only be used if value_type is copyable.

DataList(std::initializer_list<std::pair<std::string, value_type>> initList) πŸ”—

Create DataList from list of keys and corresponding values.

Parameters
  • initList: - list of pairs key - value to put in the DataList

Note

This constructor can only be used if value_type is copyable.

DataList clone() const πŸ”—

Clone this DataList, performing a deep copy of the underlying DataStore.

Note

The cloned DataStore always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new DataList

iterator begin() const πŸ”—

Get iterator at the beginning of underlying data.

const_iterator cbegin() const πŸ”—

Get constant iterator at the beginning of underlying data.

iterator end() const πŸ”—

Get iterator after the end of underlying data.

const_iterator cend() const πŸ”—

Get constant reverse iterator after the end of underlying data.

value_iterator valueBegin() const πŸ”—

Get proxy iterator over node values pointing to the first node.

value_iterator valueEnd() const πŸ”—

Get proxy iterator over node values pointing past the last node.

name_iterator nameBegin() const πŸ”—

Get proxy iterator over node names (keys) pointing to the first node.

name_iterator nameEnd() const πŸ”—

Get proxy iterator over node names (keys) pointing past the last node.

void push_back(value_type nodeData) πŸ”—

Add new node to the DataList.

Parameters
  • nodeData: - actual data to store in the new node

void push_back(std::string_view name, value_type nodeData) πŸ”—

Add new named node to the DataList.

Parameters
  • name: - name for the new node

  • nodeData: - actual data to store in the new node

std::vector<T> values() const πŸ”—

Return a vector of DataList node values.

Return

a std::vector of node values

std::vector<std::string> names() const πŸ”—

Return a vector of DataList node names.

Return

a std::vector of node names

std::vector<DataNode<T>> toVector() const πŸ”—

Return a vector of DataList nodes.

Return

a std::vector of nodes in the form of DataNode<T> objects

mint length() const πŸ”—

Get the length of the DataStore.

Return

total number of nodes in the DataStore

DataStoreNode front() const πŸ”—

Get the first node of the DataStore.

Return

first node, if it doesn’t exist the behavior is undefined

DataStoreNode back() const πŸ”—

Get the last node of the DataStore.

Return

last node, if it doesn’t exist the behavior is undefined

template<MArgumentType Type, EnableIfUnambiguousWrapperType<Type> = 0>
void push_back(Argument::WrapperType<Type> nodeValue) πŸ”—

Add new nameless node at the end of the underlying DataStore.

Template Parameters
  • Type: - type of the node data expressed via the MArgumentType enum

Parameters
  • nodeValue: - a value to be pushed as the new node, must be a wrapper over a primitive LibraryLink type

template<MArgumentType Type, EnableIfUnambiguousWrapperType<Type> = 0>
void push_back(std::string_view name, Argument::WrapperType<Type> nodeValue) πŸ”—

Add new named node at the end of the underlying DataStore.

Template Parameters
  • Type: - type of the node data expressed via the MArgumentType enum

Parameters
  • name: - name of the new node, names in a DataStore do not have to be unique

  • nodeValue: - a value to be pushed as the new node, must be a wrapper over a primitive LibraryLink type

template<MArgumentType Type>
void push_back(Argument::CType<Type> nodeValue) πŸ”—

Add new nameless node at the end of the underlying DataStore.

Template Parameters
  • Type: - type of the node data expressed via the MArgumentType enum

Parameters
  • nodeValue: - a value to be pushed as the new node, must be of a primitive LibraryLink type

template<MArgumentType Type>
void push_back(std::string_view name, Argument::CType<Type> nodeValue) πŸ”—

Add new named node at the end of the underlying DataStore.

Template Parameters
  • Type: - type of the node data expressed via the MArgumentType enum

Parameters
  • name: - name of the new node, names in a DataStore do not have to be unique

  • nodeValue: - a value to be pushed as the new node, must be of a primitive LibraryLink type

void push_back(const Argument::Typed::Any &node) πŸ”—

Add new nameless node at the end of the underlying DataStore.

Parameters
  • node: - a value to be pushed as the new node

void push_back(std::string_view name, const Argument::Typed::Any &node) πŸ”—

Add new named node at the end of the underlying DataStore.

Parameters
  • name: - name of the new node, names in a DataStore do not have to be unique

  • node: - a value to be pushed as the new node,

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

LLU::Image<T> πŸ”—

Image is a strongly-typed wrapper derived from GenericImage, where the underlying data type is known at compile time and encoded in the template parameter. The table below shows the correspondence between Image data types in LLU, plain LibraryLink and in the Wolfram Language:

LLU (C++) type

LibraryLink type

Wolfram Language type

std::int8_t

MImage_Type_Bit

β€œBit”

std::uint8_t

MImage_Type_Bit8

β€œByte”

std::int16_t

MImage_Type_Bit16

β€œBit16”

float

MImage_Type_Real32

β€œReal32”

double

MImage_Type_Real

β€œReal64”

Here is an example of the Image class in action:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
/* Take a constant "Byte" image and return a copy with negated pixel values */
LIBRARY_LINK_FUNCTION(NegateImage) {
   LLU::MArgumentManager mngr {libData, Argc, Args, Res};

   const auto image = mngr.getImage<uint8_t, LLU::Passing::Constant>(0);

   LLU::Image<uint8_t> outImage {image.clone()};
   constexpr uint8_t negator = (std::numeric_limits<uint8_t>::max)();
   std::transform(std::cbegin(in), std::cend(in), std::begin(outImage), [](T inElem) { return negator - inElem; });

   mngr.setImage(outImage);
   return LLU::ErrorCode::NoError;
}

On the Wolfram Language side, we can load and use this function as follows:

`LLU`PacletFunctionSet[NegateImage, "NegateImage", {{Image, "Constant"}}, Image];

NegateImage[Image[RandomImage[ColorSpace -> "RGB"], "Byte"]]

(* Out[] = [--Image--] *)

This is only an example, Wolfram Language already has a built-in function for negating images: ImageNegate.

In the example above we simply assumed that the Image we use will be of type β€œByte”, so we could simply write LLU::Image<uint8_t> in the C++ code. In the next example let’s consider a function that takes two images from LibraryLink of arbitrary types and converts the second one to the data type of the first one. In this case we cannot simply read arguments from MArgumentManager because we don’t know what template arguments should be passed to LLU::Image. Instead, we call a function LLU::MArgumentManager::operateOnImage() which lets us evaluate a function template on an input image without knowing its data type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
LIBRARY_LINK_FUNCTION(UnifyImageTypes) {
   LLU::MArgumentManager mngr {libData, Argc, Args, Res};

   // Take an image passed to the library function as the first argument, deduce its data type, create a corresponding LLU::Image wrapper and evaluate
   // given generic lambda function on this image
   mngr.operateOnImage(0, [&mngr](auto&& firstImage) {

      // T is the data type of the first image
      using T = typename std::remove_reference_t<decltype(firstImage)>::value_type;

      // Similarly, read the second image and create a properly typed LLU::Image wrapper
      mngr.operateOnImage(1, [&mngr](auto&& secondImage) {

         // Convert the second image to the data type of the first one and return as the library function result
         LLU::Image<T> out {secondImage.template convert<T>()};
         mngr.setImage(out);
      });
   });
   return LLU::ErrorCode::NoError;
}
template<typename T>
class LLU::Image : public LLU::TypedImage<T>, public LLU::MContainer<MArgumentType::Image> πŸ”—

This is a class template, where template parameter T is the type of data elements. Image is derived from MArray.

Image<> classes automate creation and deletion of MImages. They are strongly typed (no void* to underlying memory) and almost all functions from <algorithms> can be used on Image.

Template Parameters
  • T: - type of underlying data

Public Types

using value_type = T πŸ”—

Type of elements stored.

using iterator = value_type* πŸ”—

Iterator type.

using const_iterator = const value_type* πŸ”—

Constant iterator type.

using reverse_iterator = std::reverse_iterator<iterator> πŸ”—

Reverse iterator type.

using const_reverse_iterator = std::reverse_iterator<const_iterator> πŸ”—

Constant reverse iterator type.

using reference = value_type& πŸ”—

Reference type.

using const_reference = const value_type& πŸ”—

Constant reference type.

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

Image(mint w, mint h, mint channels, colorspace_t cs, bool interleavingQ) πŸ”—

Constructs new 2D Image.

Parameters
  • [in] w: - Image width (number of columns)

  • [in] h: - Image height (number of rows)

  • [in] channels: - number of channels

  • [in] cs: - color space

  • [in] interleavingQ: - whether Image data should be interleaved

Image(mint nFrames, mint w, mint h, mint channels, colorspace_t cs, bool interleavingQ) πŸ”—

Constructs new 3D Image.

Parameters
  • [in] nFrames: - number of 2D frames/slices

  • [in] w: - Image width (number of columns)

  • [in] h: - Image height (number of rows)

  • [in] channels: - number of channels

  • [in] cs: - color space

  • [in] interleavingQ: - whether Image data should be interleaved

Exceptions
  • ErrorName::ImageNewError: - if internal MImage creation failed

Image(GenericImage im) πŸ”—

Create new Image from a GenericImage.

Parameters
  • [in] im: - generic image to be wrapped into Image class

Exceptions
  • ErrorName::ImageTypeError: - if the Image template type T does not match the actual data type of the generic image

Image(MImage mi, Ownership owner) πŸ”—

Constructs Image based on MImage.

Parameters
  • [in] mi: - LibraryLink structure to be wrapped

  • [in] owner: - who manages the memory the raw MImage

Exceptions
  • ErrorName::ImageTypeError: - if template parameter T does not match MImage data type

  • ErrorName::ImageSizeError: - if constructor failed to calculate image dimensions properly

Image() = default πŸ”—

Default constructor - creates an empty wrapper.

Image clone() const πŸ”—

Clone this Image, performing a deep copy of the underlying MImage.

Note

The cloned MImage always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new Image

template<typename U>
Image<U> convert(bool interleaved) const πŸ”—

Copy this image with type conversion and explicitly specified interleaving.

Template Parameters
  • U: - any type that Image supports

Parameters
  • [in] interleaved: - whether the newly created Image should be interleaved

Return

newly created Image of type U and specified interleaving

template<typename U>
Image<U> convert() const πŸ”—

Copy this image with type conversion and other properties (dimensions, interleaving, color space, etc.) untouched.

Template Parameters
  • U: - any type that Image supports

Return

newly created Image of type U

T get(mint row, mint col, mint channel) const πŸ”—

Get channel value at specified position in 2D image.

Parameters
  • [in] row: - pixel row (in Mathematica-style indexing - starting from 1)

  • [in] col: - pixel column (in Mathematica-style indexing - starting from 1)

  • [in] channel: - desired channel (in Mathematica-style indexing - starting from 1)

Exceptions
  • ErrorName::ImageIndexError: - if the specified coordinates are out-of-bound

T get(mint slice, mint row, mint col, mint channel) const πŸ”—

Get channel value at specified position in 3D image.

Parameters
  • [in] slice: - slice index (in Mathematica-style indexing - starting from 1)

  • [in] row: - pixel row (in Mathematica-style indexing - starting from 1)

  • [in] col: - pixel column (in Mathematica-style indexing - starting from 1)

  • [in] channel: - desired channel (in Mathematica-style indexing - starting from 1)

Exceptions
  • ErrorName::ImageIndexError: - if the specified coordinates are out-of-bound

void set(mint row, mint col, mint channel, T newValue) πŸ”—

Set channel value at specified position in 2D image.

Parameters
  • [in] row: - pixel row (in Mathematica-style indexing - starting from 1)

  • [in] col: - pixel column (in Mathematica-style indexing - starting from 1)

  • [in] channel: - desired channel (in Mathematica-style indexing - starting from 1)

  • [in] newValue: - new channel value

Exceptions
  • ErrorName::ImageIndexError: - if the specified coordinates are out-of-bound

void set(mint slice, mint row, mint col, mint channel, T newValue) πŸ”—

Set channel value at specified position in 3D image.

Parameters
  • [in] slice: - slice index (in Mathematica-style indexing - starting from 1)

  • [in] row: - pixel row (in Mathematica-style indexing - starting from 1)

  • [in] col: - pixel column (in Mathematica-style indexing - starting from 1)

  • [in] channel: - desired channel (in Mathematica-style indexing - starting from 1)

  • [in] newValue: - new channel value

Exceptions
  • ErrorName::ImageIndexError: - if the specified coordinates are out-of-bound

mint rank() const noexcept πŸ”—

Get container rank.

bool empty() const noexcept πŸ”—

Check whether container is empty.

mint dimension(mint index) const πŸ”—

Get dimension value at position index.

const MArrayDimensions &dimensions() const πŸ”—

Get a const reference to dimensions object.

T &operator[](const std::vector<mint> &indices) πŸ”—

Get a reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

const T &operator[](const std::vector<mint> &indices) const πŸ”—

Get a constant reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

reference operator[](mint index) πŸ”—

Get a reference to the data element at given position.

Parameters
  • [in] index: - position of desired data element

const_reference operator[](mint index) const πŸ”—

Get a constant reference to the data element at given position.

Parameters
  • [in] index: - position of desired data element

T &at(mint index) πŸ”—

Get a reference to the data element at given position with bound checking.

Parameters
  • [in] index: - position of desired data element

Exceptions
  • indexError(): - if index is out-of-bounds

const T &at(mint index) const πŸ”—

Get a constant reference to the data element at given position with bound checking.

Parameters
  • [in] index: - position of desired data element

Exceptions
  • indexError(): - if index is out-of-bounds

T &at(const std::vector<mint> &indices) πŸ”—

Get a reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

Exceptions
  • indexError(): - if indices are out-of-bounds

const T &at(const std::vector<mint> &indices) const πŸ”—

Get a constant reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

Exceptions
  • indexError(): - if indices are out-of-bounds

value_type *data() noexcept πŸ”—

Get raw pointer to underlying data.

const value_type *data() const noexcept πŸ”—

Get raw pointer to const underlying data.

mint size() const noexcept πŸ”—

Get total number of elements in the container.

iterator begin() noexcept πŸ”—

Get iterator at the beginning of underlying data.

const_iterator begin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

const_iterator cbegin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

iterator end() noexcept πŸ”—

Get iterator after the end of underlying data.

const_iterator end() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

const_iterator cend() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

reverse_iterator rbegin() noexcept πŸ”—

Get iterator at the beginning of underlying data.

const_reverse_iterator rbegin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

const_reverse_iterator crbegin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

reverse_iterator rend() noexcept πŸ”—

Get iterator after the end of underlying data.

const_reverse_iterator rend() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

const_reverse_iterator crend() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

reference front() πŸ”—

Get reference to the first element.

Note

For empty container the behavior is undefined.

const_reference front() const πŸ”—

Get constant reference to the first element.

Note

For empty container the behavior is undefined.

reference back() πŸ”—

Get reference to the last element.

Note

For empty container the behavior is undefined.

const_reference back() const πŸ”—

Get constant reference to the last element.

Note

For empty container the behavior is undefined.

std::vector<value_type> asVector() const πŸ”—

Copy contents of the data to a std::vector of matching type.

Return

std::vector with the copy of the data

GenericImage convert(imagedata_t t, mbool interleavingQ) const πŸ”—

Convert this object to a new GenericImage of given datatype, optionally changing interleaving.

Parameters
  • t: - destination data type

  • interleavingQ: - whether the converted GenericImage should be interleaved or not

Return

converted GenericImage owned by the Library

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_convertType.html

GenericImage convert(imagedata_t t) const πŸ”—

Convert this object to a new GenericImage of given datatype.

Parameters
  • t: - destination data type

Return

converted GenericImage owned by the Library

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_convertType.html

colorspace_t colorspace() const override πŸ”—

Get colorspace which describes how colors are represented as numbers.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getColorSpace.html

mint rows() const override πŸ”—

Get number of rows.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getRowCount.html

mint columns() const override πŸ”—

Get number of columns.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getColumnCount.html

mint slices() const override πŸ”—

Get number of slices.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getSliceCount.html

mint channels() const override πŸ”—

Get number of channels.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getChannels.html

bool alphaChannelQ() const override πŸ”—

Check if there is an alpha channel in the image.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_alphaChannelQ.html

bool interleavedQ() const override πŸ”—

Check if the image is interleaved.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_interleavedQ.html

bool is3D() const override πŸ”—

Check if the image is 3D.

mint getRank() const override πŸ”—

Get rank.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getRank.html

mint getFlattenedLength() const override πŸ”—

Get the total number of pixels in the image.

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getFlattenedLength.html

imagedata_t type() const override πŸ”—

Get the data type of the image.

Return

type of elements (see definition of imagedata_t)

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getDataType.html

void *rawData() const override πŸ”—

Get access to raw image data.

Use with caution.

Return

pointer to the raw data

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MImage_getRawData.html

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

LLU::NumericArray<T> πŸ”—

NumericArray<T> is an extension of GenericNumericArray which is aware that it holds data of type T and therefore can provide an API to iterate over the data and modify it. The table below shows the correspondence between NumericArray C++ types and Wolfram Language types:

C++ type

Wolfram Language type

std::int8_t

β€œInteger8”

std::uint8_t

β€œUnsignedInteger8”

std::int16_t

β€œInteger16”

std::uint16_t

β€œUnsignedInteger16”

std::int32_t

β€œInteger32”

std::uint32_t

β€œUnsignedInteger32”

std::int64_t

β€œInteger64”

std::uint64_t

β€œUnsignedInteger64”

float

β€œReal32”

double

β€œReal64”

std::complex<float>

β€œComplexReal32”

std::complex<double>

β€œComplexReal64”

Here is an example of the NumericArray class in action:

1
2
3
4
5
6
7
8
/* Take a NumericArray of type "Integer32" and make a copy with reversed order of elements */
LIBRARY_LINK_FUNCTION(ReverseNumericArray) {
   LLU::MArgumentManager mngr {libData, Argc, Args, Res};
   auto inputNA = mngr.getNumericArray<std::int32_t, LLU::Passing::Constant>(0);
   LLU::NumericArray<std::int32_t> outNA { std::crbegin(inputNA), std::crend(inputNA), inputNA.dimensions() };
   mngr.set(outNA);
   return LLU::ErrorCode::NoError;
}

On the Wolfram Language side, we can load and use this function as follows:

`LLU`PacletFunctionSet[ReverseNumericArray, "ReverseNumericArray", {{NumericArray, "Constant"}}, NumericArray];

ReverseNumericArray[NumericArray[{{2, 3, 4}, {5, 6, 7}}, "Integer32"]]

(* Out[] = NumericArray[{{7, 6, 5}, {4, 3, 2}}, "Integer32"] *)
template<typename T>
class LLU::NumericArray : public LLU::TypedNumericArray<T>, public LLU::MContainer<MArgumentType::NumericArray> πŸ”—

This is a class template, where template parameter T is the type of data elements. NumericArray is derived from MArray.

NumericArray<> classes automate creation and deletion of MNumericArrays. They are strongly typed (no void* to underlying memory) and almost all functions from <algorithms> can be used on NumericArray.

Template Parameters
  • T: - type of underlying data

Public Types

using value_type = T πŸ”—

Type of elements stored.

using iterator = value_type* πŸ”—

Iterator type.

using const_iterator = const value_type* πŸ”—

Constant iterator type.

using reverse_iterator = std::reverse_iterator<iterator> πŸ”—

Reverse iterator type.

using const_reverse_iterator = std::reverse_iterator<const_iterator> πŸ”—

Constant reverse iterator type.

using reference = value_type& πŸ”—

Reference type.

using const_reference = const value_type& πŸ”—

Constant reference type.

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

NumericArray(std::initializer_list<T> v) πŸ”—

Constructs flat NumericArray based on a list of elements.

Parameters
Exceptions
  • see: NumericArray<T>::NumericArray(InputIt, InputIt, std::initializer_list<mint>)

Warning

It is user’s responsibility to make sure that length of v fits into mint!

template<class Container, typename = std::enable_if_t<is_iterable_container_with_matching_type_v<Container, T> && has_size_v<Container>>>
NumericArray(const Container &c) πŸ”—

Constructs flat NumericArray with contents copied from a given collection of data.

Template Parameters
  • Container: - any iterable (begin(), end()) collection of data that has a value_type alias member and a size() member function

Parameters
  • c: - const reference to a collection from which data will be copied to the NumericArray

template<class Container, typename = std::enable_if_t<is_iterable_container_with_matching_type_v<Container, T>>>
NumericArray(const Container &c, MArrayDimensions dims) πŸ”—

Constructs a NumericArray with contents copied from a given collection of data and dimensions passed as parameter.

Template Parameters
  • Container: - any iterable (begin(), end()) collection of data that has a value_type alias member

Parameters
  • c: - const reference to a collection from which data will be copied to the NumericArray

  • dims: - dimensions of the NumericArray

template<class InputIt, typename = enable_if_input_iterator<InputIt>>
NumericArray(InputIt first, InputIt last) πŸ”—

Constructs flat NumericArray with elements from range [first, last)

Parameters
  • [in] first: - iterator to the beginning of range

  • [in] last: - iterator past the end of range

Template Parameters
  • InputIt: - any iterator conforming to InputIterator concept

Exceptions
  • see: NumericArray<T>::NumericArray(InputIt, InputIt, std::initializer_list<mint>)

Warning

It is user’s responsibility to make sure that length of range fits into mint!

Note

Be aware that efficiency of this constructor strongly depends on whether the InputIt is also a RandomAccessIterator

NumericArray(T init, MArrayDimensions dims) πŸ”—

Constructs the NumericArray of given shape with all elements initialized to given value.

Parameters
  • [in] init: - value of type T to initialize all elements of the NumericArray

  • [in] dims: - container with NumericArray dimensions

template<class InputIt, typename = enable_if_input_iterator<InputIt>>
NumericArray(InputIt first, InputIt last, MArrayDimensions dims) πŸ”—

Constructs the NumericArray of given shape with elements from range [first, last)

Parameters
  • [in] first: - iterator to the beginning of range

  • [in] last: - iterator past the end of range

  • [in] dims: - container with NumericArray dimensions

Template Parameters
  • Container: - any type of container that has member value_type and this type is convertible to mint

Exceptions
  • ErrorName::NumericArrayNewError: - if number of elements in v does not match total NumericArray size indicated by dims

  • see: NumericArray<T>::createInternal() and MArray<T>::MArray(Container&&)

NumericArray(MNumericArray na, Ownership owner) πŸ”—

Constructs NumericArray based on MNumericArray.

Parameters
  • [in] na: - LibraryLink structure to be wrapped

  • [in] owner: - who manages the memory the raw MNumericArray

Exceptions
  • ErrorName::NumericArrayTypeError: - if the NumericArray template type T does not match the actual data type of the MNumericArray

NumericArray(GenericNumericArray na) πŸ”—

Create new NumericArray from a GenericNumericArray.

Parameters
Exceptions
  • ErrorName::NumericArrayTypeError: - if the NumericArray template type T does not match the actual data type of the generic NumericArray

NumericArray(const GenericNumericArray &other, NA::ConversionMethod method, double param = 0.0) πŸ”—

Create NumericArray from generic NumericArray.

Parameters
  • [in] other: - const reference to a generic NumericArray

  • [in] method: - conversion method to be used, when in doubt use NA::ConversionMethod::ClipRound as default

  • [in] param: - conversion tolerance

NumericArray() = default πŸ”—

Default constructor, creates a β€œhollow” NumericArray that does not have underlying MNumericArray.

NumericArray clone() const πŸ”—

Clone this NumericArray, performing a deep copy of the underlying MNumericArray.

Note

The cloned MNumericArray always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new NumericArray

mint rank() const noexcept πŸ”—

Get container rank.

bool empty() const noexcept πŸ”—

Check whether container is empty.

mint dimension(mint index) const πŸ”—

Get dimension value at position index.

const MArrayDimensions &dimensions() const πŸ”—

Get a const reference to dimensions object.

T &operator[](const std::vector<mint> &indices) πŸ”—

Get a reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

const T &operator[](const std::vector<mint> &indices) const πŸ”—

Get a constant reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

reference operator[](mint index) πŸ”—

Get a reference to the data element at given position.

Parameters
  • [in] index: - position of desired data element

const_reference operator[](mint index) const πŸ”—

Get a constant reference to the data element at given position.

Parameters
  • [in] index: - position of desired data element

T &at(mint index) πŸ”—

Get a reference to the data element at given position with bound checking.

Parameters
  • [in] index: - position of desired data element

Exceptions
  • indexError(): - if index is out-of-bounds

const T &at(mint index) const πŸ”—

Get a constant reference to the data element at given position with bound checking.

Parameters
  • [in] index: - position of desired data element

Exceptions
  • indexError(): - if index is out-of-bounds

T &at(const std::vector<mint> &indices) πŸ”—

Get a reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

Exceptions
  • indexError(): - if indices are out-of-bounds

const T &at(const std::vector<mint> &indices) const πŸ”—

Get a constant reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

Exceptions
  • indexError(): - if indices are out-of-bounds

value_type *data() noexcept πŸ”—

Get raw pointer to underlying data.

const value_type *data() const noexcept πŸ”—

Get raw pointer to const underlying data.

mint size() const noexcept πŸ”—

Get total number of elements in the container.

iterator begin() noexcept πŸ”—

Get iterator at the beginning of underlying data.

const_iterator begin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

const_iterator cbegin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

iterator end() noexcept πŸ”—

Get iterator after the end of underlying data.

const_iterator end() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

const_iterator cend() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

reverse_iterator rbegin() noexcept πŸ”—

Get iterator at the beginning of underlying data.

const_reverse_iterator rbegin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

const_reverse_iterator crbegin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

reverse_iterator rend() noexcept πŸ”—

Get iterator after the end of underlying data.

const_reverse_iterator rend() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

const_reverse_iterator crend() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

reference front() πŸ”—

Get reference to the first element.

Note

For empty container the behavior is undefined.

const_reference front() const πŸ”—

Get constant reference to the first element.

Note

For empty container the behavior is undefined.

reference back() πŸ”—

Get reference to the last element.

Note

For empty container the behavior is undefined.

const_reference back() const πŸ”—

Get constant reference to the last element.

Note

For empty container the behavior is undefined.

std::vector<value_type> asVector() const πŸ”—

Copy contents of the data to a std::vector of matching type.

Return

std::vector with the copy of the data

GenericNumericArray convert(numericarray_data_t t, NA::ConversionMethod method, double param) const πŸ”—

Convert this object to a new GenericNumericArray of given datatype, using specified conversion method.

Parameters
  • t: - destination data type

  • method: - conversion method

  • param: - conversion method parameter (aka tolerance)

Return

converted GenericNumericArray owned by the Library

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_convertType.html

mint getRank() const override πŸ”—

Get rank.

Return

number of dimensions in the array

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getRank.html

mint const *getDimensions() const override πŸ”—

Get dimensions.

Return

raw pointer to dimensions of the array

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getDimensions.html

mint getFlattenedLength() const override πŸ”—

Get length.

Return

total number of elements

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getFlattenedLength.html

numericarray_data_t type() const override πŸ”—

Get the data type of this array.

Return

type of elements (see definition of numericarray_data_t)

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getDataType.html

void *rawData() const noexcept override πŸ”—

Get access to the raw data.

Use with caution.

Return

pointer to the raw data

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MNumericArray_getData.html

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

LLU::Tensor<T> πŸ”—

In the same way as MTensor is closely related to MNumericArray, LLU::Tensor has almost exactly the same interface as LLU::NumericArray. Tensor supports only 3 types of data, meaning that template<typename T> LLU::Tensor class template can be instantiated with only 3 types T:

  • mint

  • double

  • std::complex<double>

Here is an example of the Tensor class in action:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/* Take a Tensor of real numbers and return the mean value */
LIBRARY_LINK_FUNCTION(GetMeanValue) {
   LLU::MArgumentManager mngr {libData, Argc, Args, Res};

   auto t = mngr.getTensor<double>(0);

   auto total = std::accumulate(t.begin(), t.end(), 0.0);

   auto result = total / t.size();
   mngr.set(result);
   return LLU::ErrorCode::NoError;
}

On the Wolfram Language side, we can load and use this function as follows:

`LLU`PacletFunctionSet[MeanValue, "MeanValue", {{Real, _}}, Real];

MeanValue[N @ {{Pi, Pi, Pi}, {E, E, E}}]

(* Out[] = 2.9299372 *)
template<typename T>
class LLU::Tensor : public LLU::TypedTensor<T>, public LLU::MContainer<MArgumentType::Tensor> πŸ”—

This is a class template, where template parameter T is the type of data elements. Tensor is derived from MArray.

Tensor<> classes automate creation and deletion of MTensors. They are strongly typed (no void* to underlying memory) and almost all functions from <algorithms> can be used on Tensor.

Template Parameters
  • T: - type of underlying data

Public Types

using value_type = T πŸ”—

Type of elements stored.

using iterator = value_type* πŸ”—

Iterator type.

using const_iterator = const value_type* πŸ”—

Constant iterator type.

using reverse_iterator = std::reverse_iterator<iterator> πŸ”—

Reverse iterator type.

using const_reverse_iterator = std::reverse_iterator<const_iterator> πŸ”—

Constant reverse iterator type.

using reference = value_type& πŸ”—

Reference type.

using const_reference = const value_type& πŸ”—

Constant reference type.

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

Tensor(std::initializer_list<T> v) πŸ”—

Constructs flat Tensor based on a list of elements.

Parameters
  • [in] v: - initializer list with Tensor elements

Exceptions
  • see: Tensor<T>::Tensor(InputIt, InputIt, std::initializer_list<mint>)

Warning

It is user’s responsibility to make sure that length of v fits into mint!

template<class Container, typename = std::enable_if_t<is_iterable_container_with_matching_type_v<Container, T> && has_size_v<Container>>>
Tensor(const Container &c) πŸ”—

Constructs flat Tensor with contents copied from a given collection of data.

Template Parameters
  • Container: - any iterable (begin(), end()) collection of data that has a value_type alias member and a size() member function

Parameters
  • c: - const reference to a collection from which data will be copied to the Tensor

template<class Container, typename = std::enable_if_t<is_iterable_container_with_matching_type_v<Container, T>>>
Tensor(const Container &c, MArrayDimensions dims) πŸ”—

Constructs a Tensor with contents copied from a given collection of data and dimensions passed as parameter.

Template Parameters
  • Container: - any iterable (begin(), end()) collection of data that has a value_type alias member

Parameters
  • c: - const reference to a collection from which data will be copied to the Tensor

  • dims: - dimensions of the Tensor

template<class InputIt, typename = enable_if_input_iterator<InputIt>>
Tensor(InputIt first, InputIt last) πŸ”—

Constructs flat Tensor with elements from range [first, last)

Parameters
  • [in] first: - iterator to the beginning of range

  • [in] last: - iterator past the end of range

Template Parameters
  • InputIt: - any iterator conforming to InputIterator concept

Exceptions
  • see: Tensor<T>::Tensor(InputIt, InputIt, std::initializer_list<mint>)

Warning

It is user’s responsibility to make sure that length of range fits into mint!

Note

Be aware that efficiency of this constructor strongly depends on whether the InputIt is also a RandomAccessIterator

Tensor(T init, MArrayDimensions dims) πŸ”—

Constructs the Tensor of given shape with all elements initialized to given value.

Parameters
  • [in] init: - value of type T to initialize all elements of the Tensor

  • [in] dims: - MArrayDimensions object with Tensor dimensions

template<class InputIt, typename = enable_if_input_iterator<InputIt>>
Tensor(InputIt first, InputIt last, MArrayDimensions dims) πŸ”—

Constructs the Tensor of given shape with elements from range [first, last)

Parameters
  • [in] first: - iterator to the beginning of range

  • [in] last: - iterator past the end of range

  • [in] dims: - container with Tensor dimensions

Template Parameters
  • InputIt: - any iterator conforming to InputIterator concept

Exceptions
  • ErrorName::TensorNewError: - if number of elements in v does not match total Tensor size indicated by dims

Tensor(MTensor t, Ownership owner) πŸ”—

Constructs Tensor based on MTensor.

Parameters
  • [in] t: - LibraryLink structure to be wrapped

  • [in] owner: - who manages the memory the raw MTensor

Exceptions
  • ErrorName::TensorTypeError: - if the Tensor template type T does not match the actual data type of the MTensor

Tensor(GenericTensor t) πŸ”—

Create new Tensor from a GenericTensor.

Parameters
Exceptions
  • ErrorName::TensorTypeError: - if the Tensor template type T does not match the actual data type of the generic Tensor

Tensor() = default πŸ”—

Default constructor, creates a Tensor that does not wrap over any raw MTensor.

Tensor clone() const πŸ”—

Clone this Tensor, performing a deep copy of the underlying MTensor.

Note

The cloned MTensor always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new Tensor

mint rank() const noexcept πŸ”—

Get container rank.

bool empty() const noexcept πŸ”—

Check whether container is empty.

mint dimension(mint index) const πŸ”—

Get dimension value at position index.

const MArrayDimensions &dimensions() const πŸ”—

Get a const reference to dimensions object.

T &operator[](const std::vector<mint> &indices) πŸ”—

Get a reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

const T &operator[](const std::vector<mint> &indices) const πŸ”—

Get a constant reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

reference operator[](mint index) πŸ”—

Get a reference to the data element at given position.

Parameters
  • [in] index: - position of desired data element

const_reference operator[](mint index) const πŸ”—

Get a constant reference to the data element at given position.

Parameters
  • [in] index: - position of desired data element

T &at(mint index) πŸ”—

Get a reference to the data element at given position with bound checking.

Parameters
  • [in] index: - position of desired data element

Exceptions
  • indexError(): - if index is out-of-bounds

const T &at(mint index) const πŸ”—

Get a constant reference to the data element at given position with bound checking.

Parameters
  • [in] index: - position of desired data element

Exceptions
  • indexError(): - if index is out-of-bounds

T &at(const std::vector<mint> &indices) πŸ”—

Get a reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

Exceptions
  • indexError(): - if indices are out-of-bounds

const T &at(const std::vector<mint> &indices) const πŸ”—

Get a constant reference to the data element at given position in a multidimensional container.

Parameters
  • [in] indices: - vector with coordinates of desired data element

Exceptions
  • indexError(): - if indices are out-of-bounds

value_type *data() noexcept πŸ”—

Get raw pointer to underlying data.

const value_type *data() const noexcept πŸ”—

Get raw pointer to const underlying data.

mint size() const noexcept πŸ”—

Get total number of elements in the container.

iterator begin() noexcept πŸ”—

Get iterator at the beginning of underlying data.

const_iterator begin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

const_iterator cbegin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

iterator end() noexcept πŸ”—

Get iterator after the end of underlying data.

const_iterator end() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

const_iterator cend() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

reverse_iterator rbegin() noexcept πŸ”—

Get iterator at the beginning of underlying data.

const_reverse_iterator rbegin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

const_reverse_iterator crbegin() const noexcept πŸ”—

Get constant iterator at the beginning of underlying data.

reverse_iterator rend() noexcept πŸ”—

Get iterator after the end of underlying data.

const_reverse_iterator rend() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

const_reverse_iterator crend() const noexcept πŸ”—

Get constant iterator after the end of underlying data.

reference front() πŸ”—

Get reference to the first element.

Note

For empty container the behavior is undefined.

const_reference front() const πŸ”—

Get constant reference to the first element.

Note

For empty container the behavior is undefined.

reference back() πŸ”—

Get reference to the last element.

Note

For empty container the behavior is undefined.

const_reference back() const πŸ”—

Get constant reference to the last element.

Note

For empty container the behavior is undefined.

std::vector<value_type> asVector() const πŸ”—

Copy contents of the data to a std::vector of matching type.

Return

std::vector with the copy of the data

mint getRank() const override πŸ”—

Get rank.

Return

number of dimensions in this tensor

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MTensor_getRank.html

mint const *getDimensions() const override πŸ”—

Get dimensions.

Return

raw pointer to dimensions of this tensor

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MTensor_getDimensions.html

mint getFlattenedLength() const override πŸ”—

Get total length.

Return

total number of elements

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MTensor_getFlattenedLength.html

mint type() const override πŸ”—

Get the data type of this tensor.

Return

type of elements (MType_Integer, MType_Real or MType_Complex)

See

http://reference.wolfram.com/language/LibraryLink/ref/callback/MTensor_getType.html

void *rawData() const override πŸ”—

Get raw pointer to the data of this tensor.

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

LLU::SparseArray<T> πŸ”—

LLU::SparseArray is a wrapper over an MSparseArray which holds elements of type T. MSparseArray supports only 3 types of data, meaning that template<typename T> LLU::SparseArray class template can be instantiated with only 3 types T:

  • mint

  • double

  • std::complex<double>

Here is an example of the SparseArray class in action:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
template<typename T>
void sparseModifyValues(LLU::SparseArray<T>& sa, LLU::TensorTypedView<T> newValues) {

   // extract a Tensor with explicit values of the SparseArray
   // this does not make a copy of the values so modifying the Tensor will modify the values in the SparseArray
   auto values = sa.explicitValues();
   if (values.size() < newValues.size()) {
     throw std::runtime_error {"Too many values provided."};
   }

   // copy new values in place of the old ones
   std::copy(std::cbegin(newValues), std::cend(newValues), std::begin(values));

   // Recompute explicit positions (necessary since one of the new values might be equal to the implicit value of the SparseArray)
   sa.resparsify();
}

LLU_LIBRARY_FUNCTION(ModifyValues) {
   auto sp = mngr.getGenericSparseArray<LLU::Passing::Shared>(0);
   auto values = mngr.getGenericTensor<LLU::Passing::Constant>(1);

   // Operate on the GenericSparseArray as if its type was known
   LLU::asTypedSparseArray(sp, [&values](auto&& sparseArray) {
      using T = typename std::remove_reference_t<decltype(sparseArray)>::value_type;
      sparseModifyValues(sparseArray, LLU::TensorTypedView<T> {values});
   });
}

On the Wolfram Language side, we can load and use this function as follows:

(* Our function takes a shared SparseArray to modify it in-place. The SparseArray can be of any type. *)
`LLU`PacletFunctionSet[$ModifyValues, {{LibraryDataType[SparseArray, _, _], "Shared"}, {_, _, "Constant"}}, "Void"];

sparse = SparseArray[{{3.5, 0., 0., 0.}, {.5, -7., 0., 0.}, {4., 0., 3., 0.}, {0., 0., 0., 1.}}];
$ModifyValues[sparse, {3.5, .5, -7.}];
Normal[sparse]

(* Out[] = {{3.5, 0., 0., 0.}, {.5, -7., 0., 0.}, {4., 0., 3., 0.}, {0., 0., 0., 1.}} *)
template<typename T>
class LLU::SparseArray : public LLU::MContainer<MArgumentType::SparseArray> πŸ”—

Strongly typed wrapper for MSparseArray.

Template Parameters
  • T: - any type supported by MSparseArray (mint, double or std::complex<double>)

Public Types

using Container = Argument::CType<Type> πŸ”—

The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called β€œContainer”.

Public Functions

SparseArray() = default πŸ”—

Default constructor, creates a SparseArray that does not wrap over any raw MSparseArray.

SparseArray(MSparseArray t, Ownership owner) πŸ”—

Constructs SparseArray based on MSparseArray.

Parameters
  • [in] t: - LibraryLink structure to be wrapped

  • [in] owner: - who manages the memory the raw MSparseArray

Exceptions
  • ErrorName::SparseArrayTypeError: - if the SparseArray template type T does not match the actual data type of the MSparseArray

SparseArray(GenericSparseArray t) πŸ”—

Create new SparseArray from a GenericSparseArray.

Parameters
Exceptions
  • ErrorName::SparseArrayTypeError: - if the SparseArray template type T does not match the actual data type of the generic SparseArray

SparseArray(const Tensor<mint> &positions, const Tensor<T> &values, const Tensor<mint> &dimensions, T implicitValue) πŸ”—

Create a new SparseArray from positions, values, dimensions and an implicit value.

Parameters
  • positions: - positions of all the explicit values in the array

  • values: - explicit values to be stored in the array

  • dimensions: - dimensions of the new SparseArray

  • implicitValue: - implicit value (the one that is not stored) of the new SparseArray

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_fromExplicitPositions.html

SparseArray(const Tensor<T> &data, T implicitValue) πŸ”—

Create a new SparseArray from data array and an implicit value.

Parameters
  • data: - a tensor whose contents will be copied and sparsified

  • implicitValue: - implicit value (the one that is not stored) of the new SparseArray

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_fromMTensor.html

SparseArray(const SparseArray &s, T implicitValue) πŸ”—

Create a copy of given SparseArray with different implicit value.

Parameters
  • s: - other SparseArray of type T

  • implicitValue: - implicit value (the one that is not stored) of the new SparseArray

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_resetImplicitValue.html

mint rank() const πŸ”—

Get the rank (number of dimensions) of this sparse array.

Return

the rank of this array

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getRank.html

T implicitValue() const πŸ”—

Get the implicit value of this sparse array.

Return

implicit value (the one that is not stored)

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getImplicitValue.html

void setImplicitValue(T newImplicitValue) πŸ”—

Change the implicit value of this array.

Parameters
  • newImplicitValue: - new implicit value

Note

The underlying MSparseArray object may be replaced in the process.

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_resetImplicitValue.html

Tensor<T> explicitValues() const πŸ”—

Get a tensor with the values corresponding to the explicitly stored positions in the sparse array.

Return

Tensor of rank 1 with length equal to the number of explicit positions in the array

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getExplicitValues.html

Tensor<mint> rowPointers() const πŸ”—

Get a row pointer array for this sparse array.

The values returned are the cumulative number of explicitly represented elements for each row, so the values will be non-decreasing.

Return

Tensor of integers of rank 1

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getRowPointers.html

Tensor<mint> columnIndices() const πŸ”—

Get the column indices for the explicitly stored positions in this sparse array.

The first dimension of the resulting tensor is the number of explicit positions, and the second dimension is equal to rank() - 1.

Return

Tensor of rank 2

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getColumnIndices.html

Tensor<mint> explicitPositions() const πŸ”—

Get the explicitly specified positions in this sparse array.

The first dimension of the resulting tensor is the number of explicit positions, and the second dimension is equal to rank().

Return

Tensor of rank 2

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getExplicitPositions.html

Tensor<T> toTensor() const πŸ”—

Expand this sparse array to a regular tensor.

Return

Tensor of the same data type as this array

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_toMTensor.html

MContainer clone() const πŸ”—

Clone this MContainer, performs a deep copy of the underlying MSparseArray.

Note

The cloned MContainer always belongs to the library (Ownership::Library) because LibraryLink has no idea of its existence.

Return

new MContainer, by value

GenericTensor getImplicitValueAsTensor() const πŸ”—

Get the implicit value of this sparse array.

Return

Rank 0 tensor of the same type as the value type of this sparse array.

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getImplicitValue.html

void setImplicitValueFromTensor(const GenericTensor &implicitValue) πŸ”—

Change the implicit value of this array.

Parameters
  • implicitValue: - new implicit value

Note

The underlying MSparseArray object may be replaced in the process.

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_resetImplicitValue.html

mint getRank() const πŸ”—

Get the rank (number of dimensions) of this sparse array.

Return

the rank of this array

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getRank.html

mint const *getDimensions() const πŸ”—

Get dimensions of this sparse array.

Return

a read-only raw array of container dimensions

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getDimensions.html

GenericTensor getExplicitValues() const πŸ”—

Get a tensor with the values corresponding to the explicitly stored positions in the sparse array.

Return

GenericTensor of rank 1 with length equal to the number of explicit positions in the array or an empty wrapper for β€œpattern sparse arrays”

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getExplicitValues.html

GenericTensor getRowPointers() const πŸ”—

Get a row pointer array for this sparse array.

The values returned are the cumulative number of explicitly represented elements for each row, so the values will be non-decreasing.

Return

GenericTensor of rank 1 and integer type or an empty GenericTensor

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getRowPointers.html

GenericTensor getColumnIndices() const πŸ”—

Get the column indices for the explicitly stored positions in this sparse array.

The first dimension of the resulting tensor is the number of explicit positions, and the second dimension is equal to getRank() - 1.

Return

GenericTensor of rank 2 or an empty GenericTensor

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getColumnIndices.html

GenericTensor getExplicitPositions() const πŸ”—

Get the explicitly specified positions in this sparse array.

The first dimension of the resulting tensor is the number of explicit positions, and the second dimension is equal to getRank().

Return

GenericTensor of rank 2 or an empty GenericTensor

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_getExplicitPositions.html

GenericTensor toGenericTensor() const πŸ”—

Expand this sparse array to a regular tensor.

Return

GenericTensor of the same data type as this array

See

https://reference.wolfram.com/language/LibraryLink/ref/callback/MSparseArray_toMTensor.html

void resparsify() πŸ”—

Use current implicit value to recalculate the sparse array after the data has been modified.

mint type() const πŸ”—

Get the data type of this MSparseArray.

Return

type of elements (MType_Integer, MType_Real or MType_Complex)

Container getContainer() const noexcept πŸ”—

Get internal container.

Return

a handle to the internal container

Container abandonContainer() const noexcept πŸ”—

Give a handle to internal container and stop owning it.

Should be used with caution as it may potentially result with resource leak.

Return

a handle to the internal container

mint shareCount() const noexcept πŸ”—

Return share count of internal container, if present and 0 otherwise.

void pass(MArgument &res) const πŸ”—

Pass the internal container as result of a LibraryLink function.

Parameters
  • res: - MArgument which will hold internal container of this MContainerBase

Ownership getOwner() const noexcept πŸ”—

Get ownership information.

Return

the owner of the internal container

Iterators πŸ”—

All container classes in LLU are equipped with iterators. For Image, Tensor and NumericArray we get random-access iterators similar to those of, for instance, std::vector, because these containers also allocate space for their data as a contiguous piece of memory. Reverse and constant iterators are available as well.

Warning

Bear in mind that iterators for Image, Tensor and NumericArray are not aware of the container dimensions in the sense that the iteration happens in the order in which data is laid out in memory. For 2D arrays this is often row-major order but it gets more complicated for multidimensional arrays and for Images.

DataStore wrappers have different iterators, because DataStore has a list-like structure with nodes of type DataStoreNode. The list is unidirectional, so reverse iterator is not available. The default iterator over GenericDataList, obtained with begin and end, is a proxy iterator of type DataStoreIterator.

class LLU::DataStoreIterator πŸ”—

Proxy input iterator over DataStoreNodes, when dereferenced yields GenericDataNode proxy objects.

Public Types

using value_type = GenericDataNode πŸ”—

This iterator returns proxy objects of type GenericDataNode.

using reference = value_type πŸ”—

DataStoreIterator is a proxy iterator and so the reference type is the same as value_type.

using iterator_category = std::input_iterator_tag πŸ”—

As with all proxy iterators, DataStoreIterator is only an input iterator.

using pointer = value_type πŸ”—

DataStoreIterator is a proxy iterator and so the pointer type is the same as value_type.

using difference_type = mint πŸ”—

Provide difference_type as required for input iterators.

Public Functions

DataStoreIterator(DataStoreNode n) πŸ”—

Create a DataStoreIterator pointing to a given node.

reference operator*() const πŸ”—

Get proxy object of the current node.

Return

proxy object of current node

pointer operator->() const πŸ”—

Get proxy object of the current node.

Return

proxy object of current node

DataStoreIterator &operator++() πŸ”—

Pre-increment operator.

Return

this

DataStoreIterator operator++(int) πŸ”—

Post-increment operator.

Return

”old” copy of the iterator object

Friends

friend bool operator==(const DataStoreIterator &lhs, const DataStoreIterator &rhs) πŸ”—

β€œEqual to” operator for DataStoreIterators

Parameters
Return

true iff both iterators point to the same node

friend bool operator!=(const DataStoreIterator &lhs, const DataStoreIterator &rhs) πŸ”—

β€œNot equal to” operator for DataStoreIterators

Parameters
Return

false iff both iterators point to the same node

The object obtained by dereferencing a DataStoreIterator is of type GenericDataNode.

struct LLU::GenericDataNode πŸ”—

Basic wrapper over DataStoreNode, provides class-like interface and conversion of the underlying value from MArgument to TypedArgument.

Public Functions

GenericDataNode next() const noexcept πŸ”—

Get GenericDataNode wrapper over the next node.

Return

next node wrapped in GenericDataNode

MArgumentType type() const noexcept πŸ”—

Get type of the node value.

Return

type of the node value

std::string_view name() const noexcept πŸ”—

Get node name.

Return

string view over the name of the node

Argument::TypedArgument value() const πŸ”—

Get value of the node as the variant type.

Return

TypedArgument variant holding the value of the node

template<typename T>
T as() const πŸ”—

Get node value if it is of type T, otherwise throw an exception.

Template Parameters
  • T: - any type from LLU::NodeType namespace

Return

node value of type T

operator bool() const πŸ”—

Bool conversion operator.

Return

true iff the node is not null

GenericDataNode *operator->() πŸ”—

Member of pointer operator, used by DataList iterators.

Public Members

DataStoreNode node πŸ”—

Raw DataStore node.

LLU::DataList<T> offers more types of iterators but again all of them are proxy iterators. The default one is NodeIterator

template<typename T>
struct LLU::NodeIterator : public LLU::Detail::DataListIteratorPrimitive πŸ”—

Simple proxy input iterator that goes over a DataStore and returns proxy DataNodes when dereferenced.

Template Parameters
  • T: - data node type, see LLU::NodeType namespace for supported node types

Public Types

using value_type = DataNode<T> πŸ”—

This iterator iterates over values of type DataNode<T>

using reference = value_type πŸ”—

NodeIterator is a proxy iterator and so the reference type is the same as value_type.

Public Functions

reference operator*() const πŸ”—

Get current proxy DataNode.

Return

proxy object for the currently pointed to node

NodeIterator &operator++() πŸ”—

Pre-increment operator.

Return

this

NodeIterator operator++(int) πŸ”—

Post-increment operator.

Return

”old” copy of the iterator object

The object obtained by dereferencing a NodeIterator is of type DataNode.

template<typename T>
class LLU::DataNode πŸ”—

Wrapper over DataStoreNode structure from LibraryLink.

Public Functions

DataNode(DataStoreNode dsn) πŸ”—

Create DataNode from raw DataStoreNode structure.

Parameters
  • dsn: - raw node

DataNode(GenericDataNode gn) πŸ”—

Create DataNode from raw GenericDataNode.

Parameters
  • gn: - generic data node

T &value() πŸ”—

Get node value.

Return

Returns a reference to node value

const T &value() const πŸ”—

Get node value.

Return

Returns a reference to node value

std::string_view name() const πŸ”—

Get node name.

Return

string_view to the node name

Note

If you store the result of this function make sure it does not outlive the underlying DataStore node, otherwise make a string copy

bool hasNext() const πŸ”—

Check if this node has a successor.

Return

true iff the current node is not the last one in its DataList

GenericDataNode next() const πŸ”—

Get next node as GenericDataNode (because the next node may not necessarily have value of type T)

Return

GenericDataNode wrapper of next node, or empty if this is the last node

MArgumentType type() noexcept πŸ”—

Get the actual type of node value.

This is useful when working on a β€œgeneric” DataList.

Return

Actual type of node value

template<std::size_t N>
decltype(auto) get() πŸ”—

Get N-th element of DataNode in a tuple-like way.

This function enables structured bindings to DataNodes.

Template Parameters
  • N: - index (only 0 and 1 are valid)

Return

either the node name for N == 0 or node value for N == 1

Every data node has a (possibly empty) name and a value. Sometimes you might only be interested in node values, or only in names; DataList provides specialized iterators for this. You may obtain them with valueBegin() and nameBegin(), respectively.

To get those specialized iterators in a range-based for loop, where you cannot directly choose which variant of begin() method to use, you can utilize one of the iterator adaptors that LLU defines. For instance,

// Get a DataList of complex numbers as argument to the library function
auto dataList = manager.getDataList<LLU::NodeType::Complex>(0);

// Create a new DataList to store node names of the original DataList as node values in the new list
DataList<LLU::NodeType::UTF8String> keys;
for (auto name : LLU::NameAdaptor {dataList}) {
   keys.push_back(name);
}

// Create a new DataList to store node values of the original DataList, without node names
DataList<LLU::NodeType::Complex> values;
for (auto value : LLU::ValueAdaptor {dataList}) {
   values.push_back(value);
}

It is possible to write the same code using the default iterator (NodeIterator) and structured bindings:

// Get a DataList of complex numbers as argument to the library function
auto dataList = manager.getDataList<LLU::NodeType::Complex>(0);

DataList<LLU::NodeType::UTF8String> keys;
DataList<LLU::NodeType::Complex> values;

// Iterate over the dataList once, accessing both node name and value
for (auto [name, value] : dataList) {
   keys.push_back(name);
   values.push_back(value);
}