Skip to content

About

C++ wrappers for conveniently wrapping Wolfram LibraryLink code.

Topics

Resources

Contributing

Stars

41 stars

Watchers

19 watching

Forks

Repository files navigation

LibraryLink Utilities

LLU logo

LibraryLink Utilities (abbr. LLU) is an open-source library consisting of modern C++ wrappers over most parts of LibraryLink - the Wolfram Language framework for connecting to C and C++ libraries. The official documentation including use instructions can be found here:

https://wolframresearch.github.io/LibraryLinkUtilities/

This documentation is split into modules. Each describes a core part of LLU providing general overview, examples and detailed description of related C++ entities.

Please use GitHub to report bugs, make suggestions and request features.

Motivation

LibraryLink is a great tool for connecting Wolfram Language to external C/C++ libraries and is widely used by Wolfram Research and Wolfram Language developers for developing paclets. LibraryLink Utilities makes it even easier to use LibraryLink by providing features such as:

  • automatic resource management
  • exception handling
  • container iterators
  • class-like interface for data structures, for example rank() as member function of Tensor class instead of separate function mint MTensor_getRank(MTensor)
  • type safety
  • lazy loading of library functions
  • progress monitoring of library functions
  • standardized approach to exchange custom data types between C++ and WL code

Example

Let's demonstrate some advantages of LLU by comparing the same function written with and without LLU. Below we will implement a simple function repeatCharacters that takes a string s and a tensor t and returns a new string s2 that consists of each character s[i] from original string but repeated t[i] times. So, for example

repeatCharacters("abc", {3, 2, 1})

gives

"aaabbc"

This is the C - style implementation:

// global variable which is the buffer for strings returned to LibraryLink
char* outString = NULL;

EXTERN_C DLLEXPORT int repeatCharacters(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) {
  char* string = NULL;
  MNumericArray counts;
  uint8_t* countsData = NULL;
  size_t outStringIndex = 0;
  size_t len, j;
  mint sum = 0;
  mint c;

  string = MArgument_getUTF8String(Args[0]);
  counts = MArgument_getMNumericArray(Args[1]);

  // check NumericArray type
  if (libData->numericarrayLibraryFunctions->MNumericArray_getType(counts) != MNumericArray_Type_UBit8) {
     libData->UTF8String_disown(string);
     return LIBRARY_TYPE_ERROR;
  }

  // check NumericArray rank
  if (libData->numericarrayLibraryFunctions->MNumericArray_getRank(counts) != 1) {
     libData->UTF8String_disown(string);
     return LIBRARY_RANK_ERROR;
  }

  // check if NumericArray length is equal to input string length
  len = strlen(string);
  if (libData->numericarrayLibraryFunctions->MNumericArray_getFlattenedLength(counts) != len) {
     libData->UTF8String_disown(string);
     return LIBRARY_DIMENSION_ERROR;
  }

  // before we allocate memory for the output string, we have to sum all NumericArray elements
  // to see how many bytes are needed
  countsData = (uint8_t*) libData->numericarrayLibraryFunctions->MNumericArray_getData(counts);
  for (j = 0; j < len; j++) {
     sum += countsData[j];
  }

  // free memory owned by global buffer, if any (for example from the previous call to this function)
  free(outString);
  outString = NULL;

  // allocate memory for output string, outString has to be a global variable,
  // because it will be returned to LibraryLink
  outString = (char*) malloc(sum + 1);
  if (!outString) {
     libData->UTF8String_disown(string);
     return LIBRARY_FUNCTION_ERROR;
  }

  // populate output string
  for (j = 0; j < len; j++) {
     for (c = 0; c < countsData[j]; c++) {
        outString[outStringIndex++] = string[j];
     }
  }

  // add null terminator
  outString[sum] = '\0';

  // clean up and set result
  libData->UTF8String_disown(string);
  MArgument_setUTF8String(Res, outString);

  return LIBRARY_NO_ERROR;
}

and this is the corresponding C++ version written with LibraryLink Utilities:

EXTERN_C DLLEXPORT int repeatCharactersLLU(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) {
  auto err = LLU::ErrorCode::NoError;
  try {
     // Create manager object
     LLU::MArgumentManager mngr {libData, Argc, Args, Res};

     // Read string and NumericArray arguments
     auto string = mngr.getString(0);
     auto counts = mngr.getNumericArray<std::uint8_t>(1);

     // check NumericArray rank
     if (counts.rank() != 1) {
        LLU::ErrorManager::throwException(LLU::ErrorName::RankError);
     }

     // check if NumericArray length is equal to input string length
     if (counts.size() != string.size()) {
        LLU::ErrorManager::throwException(LLU::ErrorName::DimensionsError);
     }

     // before we allocate memory for the output string, we have to sum all NumericArray elements
     // to see how many bytes are needed
     auto sum = std::accumulate(std::cbegin(counts), std::cend(counts), static_cast<size_t>(0));

     // allocate memory for the output string
     std::string outString;
     outString.reserve(sum);

     // populate the output string
     for (mint i = 0; i < counts.size(); i++) {
        outString.append(std::string(counts[i], string[i]));
     }

     // clean up and set the result
     mngr.set(std::move(outString));
  } catch (const LLU::LibraryLinkError& e) {
     err = e.which();
  }
  return err;
}

Limitations with respect to LibraryLink

There are a few LibraryLink features currently not covered by LLU, most notably:

  • Tensor subsetting: MTensor_getTensor
  • Callbacks
  • Wolfram IO Library (asynchronous tasks)

Contributors

  • Rafał Chojna (rafalc) - main developer
  • Sean Cheren (scheren) - top-level code for error handling, CMake improvements
  • Rebecca Frederick (rebeccaf) - CMake improvements

About

C++ wrappers for conveniently wrapping Wolfram LibraryLink code.

Topics

Resources

Contributing

Stars

41 stars

Watchers

19 watching

Forks

Releases

Packages

Contributors

Languages