LibraryLink Utilities  3.0.1
Modern C++ wrapper over LibraryLink and WSTP
Base.hpp
Go to the documentation of this file.
1 
6 #ifndef LLU_CONTAINERS_GENERIC_BASE_HPP
7 #define LLU_CONTAINERS_GENERIC_BASE_HPP
8 
9 #include <type_traits>
10 
12 #include "LLU/LibraryData.h"
13 #include "LLU/MArgument.h"
14 #include "LLU/Utilities.hpp"
15 
17 
18 namespace LLU {
19 
22  enum struct Ownership : uint8_t {
23  LibraryLink,
24  Library,
25  Shared
26  };
27 
34  template<MArgumentType Type>
36  public:
39 
40  public:
44  MContainerBase() = default;
45 
51  MContainerBase(Container c, Ownership owner) : container {c}, owner {owner} {
52  if (!c) {
54  }
55  }
56 
58  MContainerBase(const MContainerBase& mc) = delete;
59 
64  MContainerBase(MContainerBase&& mc) noexcept : container {mc.container}, owner { mc.owner} {
65  mc.container = nullptr;
66  }
67 
69  MContainerBase& operator=(const MContainerBase& mc) = delete;
70 
77  if (this != &mc) {
78  reset(mc.container, mc.owner);
79  mc.container = nullptr;
80  }
81  return *this;
82  }
83 
85  virtual ~MContainerBase() noexcept {
86  if (owner == Ownership::Shared) {
87  disown();
88  } else if (owner == Ownership::Library) {
89  free();
90  }
91  }
92 
97  Container getContainer() const noexcept {
98  return container;
99  }
100 
107  Container abandonContainer() const noexcept {
108  owner = Ownership::LibraryLink;
109  return container;
110  }
111 
115  mint shareCount() const noexcept {
116  if (container) {
117  return shareCountImpl();
118  }
119  return 0;
120  }
121 
126  void pass(MArgument& res) const {
127  if (container) {
128  passImpl(res);
129  }
130  // Per LibraryLink documentation: returning a Shared container does not affect the memory management, so we only need to cover
131  // the case where the library owns the container. In such case the ownership is passed to the LibraryLink
132  if (owner == Ownership::Library) {
133  owner = Ownership::LibraryLink;
134  }
135  }
136 
141  Ownership getOwner() const noexcept {
142  return owner;
143  }
144 
145  protected:
151  if (container == nullptr) {
152  return nullptr;
153  }
154  return cloneImpl();
155  }
156 
158  void disown() const noexcept {
159  if (!container || !LibraryData::hasLibraryData()) {
160  return;
161  }
162  if constexpr (Type == MArgumentType::DataStore) {
163  // Disowning does nothing for DataStore as it cannot be shared.
164  } else if constexpr (Type == MArgumentType::Image) {
165  LibraryData::ImageAPI()->MImage_disown(container);
166  } else if constexpr (Type == MArgumentType::NumericArray) {
167  LibraryData::NumericArrayAPI()->MNumericArray_disown(container);
168  } else if constexpr (Type == MArgumentType::SparseArray) {
169  LibraryData::SparseArrayAPI()->MSparseArray_disown(container);
170  } else if constexpr (Type == MArgumentType::Tensor) {
171  LibraryData::API()->MTensor_disown(container);
172  } else {
173  static_assert(alwaysFalse<Type>, "Unsupported MContainer type.");
174  }
175  }
176 
178  void free() const noexcept {
179  if (!container || !LibraryData::hasLibraryData()) {
180  return;
181  }
182  if constexpr (Type == MArgumentType::DataStore) {
183  LibraryData::DataStoreAPI()->deleteDataStore(container);
184  } else if constexpr (Type == MArgumentType::Image) {
185  LibraryData::ImageAPI()->MImage_free(container);
186  } else if constexpr (Type == MArgumentType::NumericArray) {
187  LibraryData::NumericArrayAPI()->MNumericArray_free(container);
188  } else if constexpr (Type == MArgumentType::SparseArray) {
189  LibraryData::SparseArrayAPI()->MSparseArray_free(container);
190  } else if constexpr (Type == MArgumentType::Tensor) {
191  LibraryData::API()->MTensor_free(container);
192  } else {
193  static_assert(alwaysFalse<Type>, "Unsupported MContainer type.");
194  }
195  }
196 
202  void reset(Container newCont, Ownership newOwnerMode = Ownership::Library) noexcept {
203  if (newCont != container) {
204  switch (owner) {
205  case Ownership::Shared:
206  disown();
207  break;
208  case Ownership::Library:
209  free();
210  break;
211  case Ownership::LibraryLink: break;
212  }
213  container = newCont;
214  }
215  owner = newOwnerMode;
216  }
217 
218  private:
220  virtual Container cloneImpl() const = 0;
221 
222  virtual mint shareCountImpl() const = 0;
223 
228  virtual void passImpl(MArgument& res) const = 0;
229 
231  Container container {};
232 
233  mutable Ownership owner = Ownership::Library;
234  };
235 
241  template<MArgumentType Type, typename std::enable_if_t<Argument::ContainerTypeQ<Type>, int> = 0>
242 #ifdef _WIN32
243  class MContainer; // On Windows we cannot provide a body with static_assert because of ridiculous MSVC compiler errors (probably a bug).
244 #else // On other platforms we get a nice, compile-time error.
245  class MContainer {
246  static_assert(alwaysFalse<Type>, "Trying to instantiate unspecialized MContainer template.");
247  };
248 #endif
249 } // namespace LLU
250 
251 #endif // LLU_CONTAINERS_GENERIC_BASE_HPP
LLU::MContainerBase
Template of the base class for all generic containers.
Definition: Base.hpp:35
LLU::MContainerBase::getOwner
Ownership getOwner() const noexcept
Get ownership information.
Definition: Base.hpp:141
LLU::Argument::CType
std::conditional_t< T==MArgumentType::MArgument, MArgument, std::variant_alternative_t< static_cast< size_t >(T), PrimitiveAny > > CType
Type alias that binds given MArgumentType (enumerated value) to the corresponding type of MArgument.
Definition: MArgument.h:53
LLU::MContainerBase::reset
void reset(Container newCont, Ownership newOwnerMode=Ownership::Library) noexcept
Set a new internal container safely disposing of the old one.
Definition: Base.hpp:202
LLU::MContainerBase::operator=
MContainerBase & operator=(MContainerBase &&mc) noexcept
Move-assignment operator disposes of the current raw container and steals the new one keeping its own...
Definition: Base.hpp:76
LLU
Main namespace of LibraryLink Utilities.
Definition: Queue.h:13
LLU::MContainer
MContainer is an abstract class template for generic containers. Only specializations shall be used.
Definition: Base.hpp:245
LLU::Ownership::Shared
@ Shared
When the container is shared LLU only needs to decrease share count when it's done....
LLU::MContainerBase::disown
void disown() const noexcept
Disown internal container if present.
Definition: Base.hpp:158
LibraryData.h
LLU::LibraryData::SparseArrayAPI
static const st_WolframSparseLibrary_Functions * SparseArrayAPI()
Get a pointer to structure with function pointers to MSparseArray API.
Definition: LibraryData.cpp:37
LLU::MContainerBase::shareCount
mint shareCount() const noexcept
Return share count of internal container, if present and 0 otherwise.
Definition: Base.hpp:115
LLU::MContainerBase::MContainerBase
MContainerBase()=default
Default constructor, creates an empty wrapper.
LLU::MContainerBase::operator=
MContainerBase & operator=(const MContainerBase &mc)=delete
Copy-assignment is deleted, same as copy-constructor.
LLU::MContainerBase::MContainerBase
MContainerBase(Container c, Ownership owner)
Create MContainerBase from a raw container and its owner.
Definition: Base.hpp:51
LLU::LibraryData::API
static WolframLibraryData API()
Get currently owned WolframLibraryData, if any.
Definition: LibraryData.cpp:22
LLU::MContainerBase::MContainerBase
MContainerBase(const MContainerBase &mc)=delete
Container wrappers are non-copyable, they act somewhat like unique_ptr around the raw container.
LLU::MContainerBase< MArgumentType::NumericArray >::Container
Argument::CType< Type > Container
The type of underlying LibraryLink structure (e.g. MTensor, MImage, etc.) will be called "Container".
Definition: Base.hpp:38
LLU::MContainerBase::MContainerBase
MContainerBase(MContainerBase &&mc) noexcept
Move-constructor steals the raw container keeping the ownership info.
Definition: Base.hpp:64
LLU::Ownership::Library
@ Library
The library (LLU) is responsible for managing the container's memory. Used for Manual passing and con...
LLU::ErrorName::CreateFromNullError
const std::string CreateFromNullError
attempting to create a generic container from nullptr
LLU::LibraryData::ImageAPI
static const st_WolframImageLibrary_Functions * ImageAPI()
Get a pointer to structure with function pointers to MImage API.
Definition: LibraryData.cpp:41
LLU::MContainerBase::getContainer
Container getContainer() const noexcept
Get internal container.
Definition: Base.hpp:97
LLU::MContainerBase::cloneContainer
Container cloneContainer() const
Clone the raw container, if it's present.
Definition: Base.hpp:150
LLU::MContainerBase::pass
void pass(MArgument &res) const
Pass the internal container as result of a LibraryLink function.
Definition: Base.hpp:126
ErrorManager.h
Definition of the ErrorManager class responsible for error registration and throwing.
LLU::ErrorManager::throwException
static void throwException(const std::string &errorName, T &&... args)
Throw exception with given name.
Definition: ErrorManager.h:199
LLU::MContainerBase::~MContainerBase
virtual ~MContainerBase() noexcept
Destructor takes appropriate action depending on the ownership info.
Definition: Base.hpp:85
LLU::LibraryData::NumericArrayAPI
static const st_WolframNumericArrayLibrary_Functions * NumericArrayAPI()
Get a pointer to structure with function pointers to MNumericArray API.
Definition: LibraryData.cpp:33
LLU::MContainerBase::abandonContainer
Container abandonContainer() const noexcept
Give a handle to internal container and stop owning it.
Definition: Base.hpp:107
LLU::MContainerBase::free
void free() const noexcept
Free internal container if present.
Definition: Base.hpp:178
LLU::Ownership::LibraryLink
@ LibraryLink
LibraryLink is responsible for managing the container's memory. Corresponds to Automatic and "Constan...
LLU::LibraryData::hasLibraryData
static bool hasLibraryData()
Check if libData is populated.
Definition: LibraryData.cpp:18
LLU::LibraryData::DataStoreAPI
static const st_WolframIOLibrary_Functions * DataStoreAPI()
Get a pointer to structure with function pointers to DataStore API.
Definition: LibraryData.cpp:45
MArgument.h
Template class and utilities to work with MArgument in type-safe manner.
Interfaces.h
LLU::Ownership
Ownership
An enum listing possible owners of a LibraryLink container.
Definition: Base.hpp:22
Utilities.hpp
Short but generally useful functions.