40  template <
typename T, 
int Al>
 
   46    [[nodiscard]] T &
get() noexcept { 
return x; }
 
   49    [[nodiscard]] T 
const &
get() const noexcept { 
return x; }
 
 
   73  template <
typename T, AddressSpace AdrSp = Host>
 
   85  template <
typename T, Allocator A = mallocator<>>
 
   87    static_assert(std::is_nothrow_destructible_v<T>, 
"nda::mem::handle_heap requires the value_type to have a non-throwing destructor");
 
   97#ifndef NDA_DEBUG_LEAK_CHECK 
   98    static inline A allocator; 
 
  104    mutable std::shared_ptr<void> sptr;
 
  107    using blk_T_t = std::pair<T *, size_t>;
 
  110    static void destruct(blk_T_t b) 
noexcept {
 
  114      if (
data == 
nullptr) 
return;
 
  118        for (
size_t i = 0; i < 
size; ++i) 
data[i].~T();
 
  122      allocator.deallocate({(
char *)
data, 
size * 
sizeof(T)});
 
  126    static void deleter(
void *p) 
noexcept { destruct(*((blk_T_t *)p)); }
 
  143      if (not sptr) sptr.reset(
new blk_T_t{_data, _size}, deleter);
 
 
  153      if (not sptr and not(
is_null())) destruct({_data, _size});
 
 
  176      if (not sptr and not(
is_null())) destruct({_data, _size});
 
  181      sptr  = std::move(h.sptr);
 
 
  195      if constexpr (std::is_trivially_copyable_v<T>) {
 
  198        for (
size_t i = 0; i < _size; ++i) 
new (_data + i) T(h[i]);
 
 
  219    template <OwningHandle<value_type> H>
 
  222      if constexpr (std::is_trivially_copyable_v<T>) {
 
  226                      "Constructing an nda::mem::handle_heap from a handle of a different address space requires a trivially copyable value_type");
 
  227        for (
size_t i = 0; i < _size; ++i) 
new (_data + i) T(h[i]);
 
 
  238    template <Allocator AS>
 
  249      if (
size == 0) 
return;
 
  250      auto b = allocator.allocate(
size * 
sizeof(T));
 
  251      if (not b.ptr) 
throw std::bad_alloc{};
 
 
  261      if (
size == 0) 
return;
 
  262      auto b = allocator.allocate_zero(
size * 
sizeof(T));
 
  263      if (not b.ptr) 
throw std::bad_alloc{};
 
 
  280      if (
size == 0) 
return;
 
  283        b = allocator.allocate_zero(
size * 
sizeof(T));
 
  285        b = allocator.allocate(
size * 
sizeof(T));
 
  286      if (not b.
ptr) 
throw std::bad_alloc{};
 
  292        for (
size_t i = 0; i < 
size; ++i) 
new (_data + i) T();
 
 
  302    [[nodiscard]] T &
operator[](
long i) 
noexcept { 
return _data[i]; }
 
  310    [[nodiscard]] T 
const &
operator[](
long i) 
const noexcept { 
return _data[i]; }
 
  319      EXPECTS((_data == 
nullptr) == (_size == 0));
 
  321      return _data == 
nullptr;
 
 
  328    [[nodiscard]] T *
data() const noexcept { 
return _data; }
 
  334    [[nodiscard]] 
long size() const noexcept { 
return _size; }
 
 
  345  template <
typename T, 
size_t Size>
 
  347    static_assert(std::is_copy_constructible_v<T>, 
"nda::mem::handle_stack requires the value_type to be copy constructible");
 
  348    static_assert(std::is_nothrow_destructible_v<T>, 
"nda::mem::handle_stack requires the value_type to have a non-throwing destructor");
 
  352    std::array<char, 
sizeof(T) * Size> buffer;
 
  366      if constexpr (!std::is_trivial_v<T>) {
 
  368        for (
size_t i = 0; i < Size; ++i) 
data()[i].~T();
 
 
  404      for (
size_t i = 0; i < Size; ++i) 
new (
data() + i) T(h[i]);
 
 
  413      static_assert(std::is_scalar_v<T> or 
is_complex_v<T>, 
"nda::mem::handle_stack can only be initialized to zero for scalar and complex types");
 
  414      for (
size_t i = 0; i < Size; ++i) 
data()[i] = 0;
 
 
  426        for (
size_t i = 0; i < Size; ++i) 
new (
data() + i) T();
 
 
  450    static constexpr bool is_null() noexcept { 
return false; }
 
  456    [[nodiscard]] T *
data() const noexcept { 
return (T *)buffer.data(); }
 
  462    static constexpr long size() noexcept { 
return Size; }
 
 
  478  template <
typename T, 
size_t Size>
 
  480    static_assert(Size > 0, 
"Size == 0 makes no sense in nda::mem::handle_sso");
 
  481    static_assert(std::is_copy_constructible_v<T>, 
"nda::mem::handle_sso requires the value_type to be copy constructible");
 
  482    static_assert(std::is_nothrow_destructible_v<T>, 
"nda::mem::handle_sso requires the value_type to have a non-throwing destructor");
 
  486    std::array<char, 
sizeof(T) * Size> buffer;
 
  495    void clean() 
noexcept {
 
  497      if constexpr (!std::is_trivial_v<T>) {
 
  499        for (
size_t i = 0; i < _size; ++i) 
data()[i].~T();
 
  534          _data = (T *)buffer.data();
 
  535          for (
size_t i = 0; i < _size; ++i) 
new (
data() + i) T(h[i]);
 
 
  557          _data = (T *)buffer.data();
 
  558          for (
size_t i = 0; i < _size; ++i) 
new (_data + i) T(h[i]);
 
 
  572      if constexpr (std::is_trivially_copyable_v<T>) {
 
  575        for (
size_t i = 0; i < _size; ++i) 
new (_data + i) T(h[i]);
 
 
  586      if (
this == &h) 
return *
this; 
 
  589      if (_size == 0) 
return *
this;
 
  592        if (not b.ptr) 
throw std::bad_alloc{};
 
  595        _data = (T *)buffer.data();
 
  597      for (
size_t i = 0; i < _size; ++i) 
new (_data + i) T(h[i]);
 
 
  606    template <OwningHandle<value_type> H>
 
  609      if constexpr (std::is_trivially_copyable_v<T>) {
 
  613                      "Constructing an nda::mem::handle_sso from a handle of a different address space requires a trivially copyable value_type");
 
  614        for (
size_t i = 0; i < _size; ++i) 
new (_data + i) T(h[i]);
 
 
  624      if (
size == 0) 
return;
 
  627        _data = (T *)buffer.data();
 
  630        if (not b.ptr) 
throw std::bad_alloc{};
 
 
  644      static_assert(std::is_scalar_v<T> or 
is_complex_v<T>, 
"nda::mem::handle_sso can only be initialized to zero for scalar and complex types");
 
  645      if (
size == 0) 
return;
 
  648        _data = (T *)buffer.data();
 
  649        for (
size_t i = 0; i < _size; ++i) 
data()[i] = 0;
 
  652        if (not b.ptr) 
throw std::bad_alloc{};
 
 
  668      if (
size == 0) 
return;
 
  671        _data = (T *)buffer.data();
 
  678        if (not b.
ptr) 
throw std::bad_alloc{};
 
  684        for (
size_t i = 0; i < 
size; ++i) 
new (_data + i) T();
 
 
  694    [[nodiscard]] T &
operator[](
long i) 
noexcept { 
return _data[i]; }
 
  702    [[nodiscard]] T 
const &
operator[](
long i) 
const noexcept { 
return _data[i]; }
 
  708    [[nodiscard]] 
bool on_heap()
 const { 
return _size > Size; }
 
  716      EXPECTS((_data == 
nullptr) == (_size == 0));
 
  718      return _data == 
nullptr;
 
 
  725    [[nodiscard]] T *
data() const noexcept { 
return _data; }
 
  731    [[nodiscard]] 
long size() const noexcept { 
return _size; }
 
 
  740  template <
typename T, AddressSpace AdrSp>
 
  742    static_assert(std::is_nothrow_destructible_v<T>, 
"nda::mem::handle_shared requires the value_type to have a non-throwing destructor");
 
  752    using blk_t = std::pair<T *, size_t>;
 
  755    std::shared_ptr<void> sptr;
 
  776       : _data(
data), _size(
size), sptr{foreign_handle, foreign_decref} {}
 
 
  784    template <Allocator A>
 
  787       : _data(h.
data()), _size(h.
size()) {
 
  788      if (not h.is_null()) sptr = h.get_sptr();
 
 
  797    [[nodiscard]] T &
operator[](
long i) 
noexcept { 
return _data[i]; }
 
  805    [[nodiscard]] T 
const &
operator[](
long i) 
const noexcept { 
return _data[i]; }
 
  814      EXPECTS((_data == 
nullptr) == (_size == 0));
 
  816      return _data == 
nullptr;
 
 
  823    [[nodiscard]] 
long refcount() const noexcept { 
return sptr.use_count(); }
 
  829    [[nodiscard]] T *
data() const noexcept { 
return _data; }
 
  835    [[nodiscard]] 
long size() const noexcept { 
return _size; }
 
 
  844  template <
typename T, AddressSpace AdrSp = Host>
 
  848    using T0 = std::remove_const_t<T>;
 
  889      requires(address_space == H::address_space and (std::is_const_v<value_type> or !std::is_const_v<typename H::value_type>)
 
  890               and std::is_same_v<const value_type, const typename H::value_type>)
 
  892      if constexpr (std::is_same_v<H, handle_heap<T0>>) _parent = &h;
 
 
  901    [[nodiscard]] T &
operator[](
long i) 
noexcept { 
return _data[i]; }
 
  909    [[nodiscard]] T 
const &
operator[](
long i) 
const noexcept { 
return _data[i]; }
 
  915    [[nodiscard]] 
bool is_null() const noexcept { 
return _data == 
nullptr; }
 
  927    [[nodiscard]] T *
data() const noexcept { 
return _data; }
 
 
@ Host
Using declaration for the Host address space (see nda::mem::AddressSpace).
Provides custom allocators for the nda library.
Wrap an allocator to check for memory leaks.
static void deallocate(blk_t b) noexcept
Deallocate memory using nda::mem::free.
static blk_t allocate_zero(size_t s) noexcept
Allocate memory and set it to zero.
static blk_t allocate(size_t s) noexcept
Allocate memory using nda::mem::malloc.
Provides concepts for the nda library.
static constexpr bool init_dcmplx
Should we initialize memory for complex double types to zero.
static constexpr do_not_initialize_t do_not_initialize
Instance of nda::mem::do_not_initialize_t.
void memcpy(void *dest, void const *src, size_t count)
Call the correct memcpy function based on the given address spaces.
static constexpr init_zero_t init_zero
Instance of nda::mem::init_zero_t.
constexpr bool is_complex_v
Constexpr variable that is true if type T is a std::complex type.
Macros used in the nda library.
Provides a generic memcpy and memcpy2D function for different address spaces.
Wraps an arbitrary type to have a specified alignment.
T & get() noexcept
Get reference to the wrapped object.
T const & get() const noexcept
Get const reference to the wrapped object.
T x
Wrapped object of type T.
Memory block consisting of a pointer and its size.
char * ptr
Pointer to the memory block.
Tag used in constructors to indicate that the memory should not be initialized.
handle_borrowed(T *ptr) noexcept
Construct a borrowed handle from a pointer to the data.
handle_heap< T0 > const * parent() const
Get a pointer to the parent handle.
handle_borrowed(H const &h, long offset=0) noexcept
Construct a borrowed handle from a another handle.
static constexpr auto address_space
handle_borrowed & operator=(handle_borrowed &&)=default
Default move assignment operator.
handle_borrowed & operator=(handle_borrowed const &)=default
Default copy assignment operator.
handle_borrowed()=default
Default constructor leaves the handle in a null state (nullptr).
T & operator[](long i) noexcept
Subscript operator to access the data.
bool is_null() const noexcept
Check if the handle is in a null state.
T const & operator[](long i) const noexcept
Subscript operator to access the data.
handle_borrowed(handle_borrowed const &)=default
Default copy constructor.
T value_type
Value type of the data.
T * data() const noexcept
Get a pointer to the stored data.
A handle for a memory block on the heap.
long size() const noexcept
Get the size of the handle.
~handle_heap() noexcept
Destructor for the handle.
A allocator_type
nda::mem::Allocator type.
handle_heap & operator=(handle_heap const &h)
Copy assignment operator utilizes the copy constructor and move assignment operator to make a deep co...
T const & operator[](long i) const noexcept
Subscript operator to access the data.
handle_heap(handle_heap &&h) noexcept
Move constructor simply copies the pointers and size and resets the source handle to a null state.
handle_heap(long size, init_zero_t)
Construct a handle by allocating memory for the data of a given size and initializing it to zero.
T * data() const noexcept
Get a pointer to the stored data.
handle_heap(long size)
Construct a handle by allocating memory for the data of a given size and initializing it depending on...
handle_heap & operator=(handle_heap< T, AS > const &h)
Assignment operator utilizes another constructor and move assignment to make a deep copy of the data ...
handle_heap(long size, do_not_initialize_t)
Construct a handle by allocating memory for the data of a given size but without initializing it.
T value_type
Value type of the data.
bool is_null() const noexcept
handle_heap(handle_heap const &h)
Copy constructor makes a deep copy of the data from another handle.
T & operator[](long i) noexcept
Subscript operator to access the data.
static constexpr auto address_space
handle_heap & operator=(handle_heap &&h) noexcept
Move assignment operator first releases the resources held by the current handle and then moves the r...
handle_heap()=default
Default constructor leaves the handle in a null state (nullptr and size 0).
std::shared_ptr< void > get_sptr() const
Get a shared pointer to the memory block.
handle_heap(H const &h)
Construct a handle by making a deep copy of the data from another handle.
handle_shared(handle_heap< T, A > const &h) noexcept
Construct a shared handle from an nda::mem::handle_heap.
handle_shared()=default
Default constructor leaves the handle in a null state (nullptr and size 0).
T & operator[](long i) noexcept
Subscript operator to access the data.
static constexpr auto address_space
long refcount() const noexcept
Get the reference count of the shared object.
bool is_null() const noexcept
Check if the handle is in a null state.
T value_type
Value type of the data.
T const & operator[](long i) const noexcept
Subscript operator to access the data.
handle_shared(T *data, size_t size, void *foreign_handle, void(*foreign_decref)(void *)) noexcept
Construct a handle from a shared object from a foreign library.
T * data() const noexcept
long size() const noexcept
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
handle_sso()
Default constructor.
long size() const noexcept
Get the size of the handle.
~handle_sso() noexcept
Destructor for the handle.
handle_sso & operator=(handle_sso const &h)
Copy assignment operator first cleans up the current handle and then makes a deep copy of the data fr...
T & operator[](long i) noexcept
Subscript operator to access the data.
bool is_null() const noexcept
Check if the handle is in a null state.
handle_sso & operator=(handle_sso &&h) noexcept
Move assignment operator first releases the resources held by the current handle and then either copi...
handle_sso(long size)
Construct a handle for the data of a given size and initialize it depending on the value type.
handle_sso(handle_sso const &h)
Copy construct a handle by making a deep copy of the data from the source handle.
T value_type
Value type of the data.
T * data() const noexcept
Get a pointer to the stored data.
bool on_heap() const
Check if the data is/should be stored on the heap.
handle_sso(long size, do_not_initialize_t)
Construct a handle for the data of a given size and do not initialize it.
handle_sso(long size, init_zero_t)
Construct a handle for the data of a given size and initialize it to zero (only for scalar and comple...
handle_sso(handle_sso &&h) noexcept
Move constructor either copies the heap pointers or makes a deep copy of the stack data.
handle_sso(H const &h)
Construct a handle by making a deep copy of the data from another owning handle.
T const & operator[](long i) const noexcept
Subscript operator to access the data.
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated (always on Host).
handle_stack()=default
Default constructor leaves the data uninitialized.
handle_stack(long)
Construct a handle and initialize the data depending on the value type.
T & operator[](long i) noexcept
Subscript operator to access the data.
T * data() const noexcept
Get a pointer to the stored data.
handle_stack & operator=(handle_stack const &h)
Copy assignment operator makes a deep copy of the data from the source handle using placement new.
~handle_stack() noexcept
Destructor for the handle.
handle_stack(handle_stack const &h) noexcept
Copy constructor simply calls the copy assignment operator.
handle_stack(long, do_not_initialize_t)
Construct a handle and do not initialize the data.
handle_stack(handle_stack &&h) noexcept
Move constructor simply calls the copy assignment operator.
handle_stack & operator=(handle_stack &&h) noexcept
Move assignment operator simply calls the copy assignment operator.
handle_stack(long, init_zero_t)
Construct a handle and initialize the data to zero (only for scalar and complex types).
static constexpr long size() noexcept
Get the size of the handle.
static constexpr bool is_null() noexcept
Check if the handle is in a null state.
T value_type
Value type of the data.
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Tag used in constructors to indicate that the memory should be initialized to zero.