TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
handle.hpp
Go to the documentation of this file.
1// Copyright (c) 2018--present, The Simons Foundation
2// This file is part of TRIQS/nda and is licensed under the Apache License, Version 2.0.
3// SPDX-License-Identifier: Apache-2.0
4// See LICENSE in the root of this distribution for details.
5
11
12#pragma once
13
14#include "./allocators.hpp"
15#include "./memcpy.hpp"
16#include "../concepts.hpp"
17#include "../macros.hpp"
18
19#include <array>
20#include <memory>
21#include <type_traits>
22#include <utility>
23
24namespace nda::mem {
25
30
32 static constexpr bool init_dcmplx = true;
33
40 template <typename T, int Al>
41 struct alignas(Al) aligner {
43 T x;
44
46 [[nodiscard]] T &get() noexcept { return x; }
47
49 [[nodiscard]] T const &get() const noexcept { return x; }
50 };
51
54
56 inline static constexpr do_not_initialize_t do_not_initialize{};
57
59 struct init_zero_t {};
60
62 inline static constexpr init_zero_t init_zero{};
63
65
70
72 // Forward declaration.
73 template <typename T, AddressSpace AdrSp = Host>
74 struct handle_shared;
76
85 template <typename T, Allocator A = mallocator<>>
86 struct handle_heap {
87 static_assert(std::is_nothrow_destructible_v<T>, "nda::mem::handle_heap requires the value_type to have a non-throwing destructor");
88
89 private:
90 // Pointer to the start of the actual data.
91 T *_data = nullptr;
92
93 // Size of the data (number of T elements). Invariant: size > 0 iif data != nullptr.
94 size_t _size = 0;
95
96 // Allocator to use.
97#ifndef NDA_DEBUG_LEAK_CHECK
98 static inline A allocator; // NOLINT (allocator is not specific to a single instance)
99#else
100 static inline leak_check<A> allocator; // NOLINT (allocator is not specific to a single instance)
101#endif
102
103 // For shared ownership (points to a blk_T_t).
104 mutable std::shared_ptr<void> sptr;
105
106 // Type of the memory block, i.e. a pointer to the data and its size.
107 using blk_T_t = std::pair<T *, size_t>;
108
109 // Release the handled memory (data pointer and size are not set to null here).
110 static void destruct(blk_T_t b) noexcept {
111 auto [data, size] = b;
112
113 // do nothing if the data is null
114 if (data == nullptr) return;
115
116 // if needed, call the destructors of the objects stored
117 if constexpr (A::address_space == Host and !(std::is_trivial_v<T> or nda::is_complex_v<T>)) {
118 for (size_t i = 0; i < size; ++i) data[i].~T();
119 }
120
121 // deallocate the memory block
122 allocator.deallocate({(char *)data, size * sizeof(T)});
123 }
124
125 // Deleter for the shared pointer.
126 static void deleter(void *p) noexcept { destruct(*((blk_T_t *)p)); }
127
128 public:
130 using value_type = T;
131
133 using allocator_type = A;
134
136 static constexpr auto address_space = allocator_type::address_space;
137
142 std::shared_ptr<void> get_sptr() const {
143 if (not sptr) sptr.reset(new blk_T_t{_data, _size}, deleter);
144 return sptr;
145 }
146
152 ~handle_heap() noexcept {
153 if (not sptr and not(is_null())) destruct({_data, _size});
154 }
155
157 handle_heap() = default;
158
163 handle_heap(handle_heap &&h) noexcept : _data(h._data), _size(h._size), sptr(std::move(h.sptr)) {
164 h._data = nullptr;
165 h._size = 0;
166 }
167
175 // release current resources if they are not shared and not null
176 if (not sptr and not(is_null())) destruct({_data, _size});
177
178 // move the resources from the source handle
179 _data = h._data;
180 _size = h._size;
181 sptr = std::move(h.sptr);
182
183 // reset the source handle to a null state
184 h._data = nullptr;
185 h._size = 0;
186 return *this;
187 }
188
194 if (is_null()) return;
195 if constexpr (std::is_trivially_copyable_v<T>) {
196 memcpy<address_space, address_space>(_data, h.data(), h.size() * sizeof(T));
197 } else {
198 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
199 }
200 }
201
209 *this = handle_heap{h};
210 return *this;
211 }
212
219 template <OwningHandle<value_type> H>
220 explicit handle_heap(H const &h) : handle_heap(h.size(), do_not_initialize) {
221 if (is_null()) return;
222 if constexpr (std::is_trivially_copyable_v<T>) {
223 memcpy<address_space, H::address_space>((void *)_data, (void *)h.data(), _size * sizeof(T));
224 } else {
225 static_assert(address_space == H::address_space,
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]);
228 }
229 }
230
238 template <Allocator AS>
240 *this = handle_heap{h};
241 return *this;
242 }
243
249 if (size == 0) return;
250 auto b = allocator.allocate(size * sizeof(T));
251 if (not b.ptr) throw std::bad_alloc{};
252 _data = (T *)b.ptr;
253 _size = size;
254 }
255
261 if (size == 0) return;
262 auto b = allocator.allocate_zero(size * sizeof(T));
263 if (not b.ptr) throw std::bad_alloc{};
264 _data = (T *)b.ptr;
265 _size = size;
266 }
267
280 if (size == 0) return;
281 blk_t b;
282 if constexpr (is_complex_v<T> && init_dcmplx)
283 b = allocator.allocate_zero(size * sizeof(T));
284 else
285 b = allocator.allocate(size * sizeof(T));
286 if (not b.ptr) throw std::bad_alloc{};
287 _data = (T *)b.ptr;
288 _size = size;
289
290 // call placement new for non trivial and non complex types
291 if constexpr (!std::is_trivial_v<T> and !is_complex_v<T>) {
292 for (size_t i = 0; i < size; ++i) new (_data + i) T();
293 }
294 }
295
302 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
303
310 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
311
316 [[nodiscard]] bool is_null() const noexcept {
317#ifdef NDA_DEBUG
318 // check the invariants in debug mode
319 EXPECTS((_data == nullptr) == (_size == 0));
320#endif
321 return _data == nullptr;
322 }
323
328 [[nodiscard]] T *data() const noexcept { return _data; }
329
334 [[nodiscard]] long size() const noexcept { return _size; }
335 };
336
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");
349
350 private:
351 // Memory buffer on the stack to store the data.
352 std::array<char, sizeof(T) * Size> buffer;
353
354 public:
356 using value_type = T;
357
359 static constexpr auto address_space = Host;
360
365 ~handle_stack() noexcept {
366 if constexpr (!std::is_trivial_v<T>) {
367 // explicitly call the destructor for each non-trivial object
368 for (size_t i = 0; i < Size; ++i) data()[i].~T();
369 }
370 }
371
373 handle_stack() = default;
374
380 handle_stack(handle_stack &&h) noexcept { operator=(h); }
381
388 operator=(h);
389 return *this;
390 }
391
397 handle_stack(handle_stack const &h) noexcept { operator=(h); }
398
404 for (size_t i = 0; i < Size; ++i) new (data() + i) T(h[i]);
405 return *this;
406 }
407
410
412 handle_stack(long /*size*/, init_zero_t) {
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;
415 }
416
424 handle_stack(long /*size*/) : handle_stack{} {
425 if constexpr (!std::is_trivial_v<T> and !is_complex_v<T>) {
426 for (size_t i = 0; i < Size; ++i) new (data() + i) T();
427 }
428 }
429
436 [[nodiscard]] T &operator[](long i) noexcept { return data()[i]; }
437
444 [[nodiscard]] T const &operator[](long i) const noexcept { return data()[i]; }
445
450 static constexpr bool is_null() noexcept { return false; }
451
456 [[nodiscard]] T *data() const noexcept { return (T *)buffer.data(); }
457
462 static constexpr long size() noexcept { return Size; }
463 };
464
478 template <typename T, size_t Size>
479 struct handle_sso { // struct alignas(alignof(T)) handle_sso {
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");
483
484 private:
485 // Memory buffer on the stack to store the data.
486 std::array<char, sizeof(T) * Size> buffer;
487
488 // Pointer to the start of the actual data.
489 T *_data = nullptr;
490
491 // Size of the data (number of T elements). Invariant: size > 0 iif data != nullptr.
492 size_t _size = 0;
493
494 // Release the handled memory.
495 void clean() noexcept {
496 if (is_null()) return;
497 if constexpr (!std::is_trivial_v<T>) {
498 // explicitly call the destructor for each non-trivial object
499 for (size_t i = 0; i < _size; ++i) data()[i].~T();
500 }
501 if (on_heap()) mallocator<>::deallocate({(char *)_data, _size * sizeof(T)});
502 _data = nullptr;
503 _size = 0;
504 }
505
506 public:
508 using value_type = T;
509
511 static constexpr auto address_space = Host;
512
514 handle_sso() {}; // NOLINT (user-defined constructor to avoid value initialization of the buffer)
515
522 ~handle_sso() noexcept { clean(); }
523
529 handle_sso(handle_sso &&h) noexcept : _size(h._size) {
530 if (on_heap()) {
531 _data = h._data;
532 } else {
533 if (_size != 0) {
534 _data = (T *)buffer.data();
535 for (size_t i = 0; i < _size; ++i) new (data() + i) T(h[i]);
536 }
537 }
538 h._data = nullptr;
539 h._size = 0;
540 }
541
551 clean();
552 _size = h._size;
553 if (on_heap()) {
554 _data = h._data;
555 } else {
556 if (_size != 0) {
557 _data = (T *)buffer.data();
558 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
559 }
560 }
561 h._data = nullptr;
562 h._size = 0;
563 return *this;
564 }
565
571 if (is_null()) return;
572 if constexpr (std::is_trivially_copyable_v<T>) {
573 memcpy<address_space, address_space>((void *)_data, (void *)h.data(), _size * sizeof(T));
574 } else {
575 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
576 }
577 }
578
586 if (this == &h) return *this; // self assignment
587 clean();
588 _size = h._size;
589 if (_size == 0) return *this;
590 if (on_heap()) {
591 auto b = mallocator<>::allocate(_size * sizeof(T));
592 if (not b.ptr) throw std::bad_alloc{};
593 _data = (T *)b.ptr;
594 } else {
595 _data = (T *)buffer.data();
596 }
597 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
598 return *this;
599 }
600
606 template <OwningHandle<value_type> H>
607 explicit handle_sso(H const &h) : handle_sso(h.size(), do_not_initialize) {
608 if (is_null()) return;
609 if constexpr (std::is_trivially_copyable_v<T>) {
610 memcpy<address_space, H::address_space>((void *)_data, (void *)h.data(), _size * sizeof(T));
611 } else {
612 static_assert(address_space == H::address_space,
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]);
615 }
616 }
617
624 if (size == 0) return;
625 _size = size;
626 if (not on_heap()) {
627 _data = (T *)buffer.data();
628 } else {
629 auto b = mallocator<>::allocate(size * sizeof(T));
630 if (not b.ptr) throw std::bad_alloc{};
631 _data = (T *)b.ptr;
632 }
633 }
634
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;
646 _size = size;
647 if (not on_heap()) {
648 _data = (T *)buffer.data();
649 for (size_t i = 0; i < _size; ++i) data()[i] = 0;
650 } else {
651 auto b = mallocator<>::allocate_zero(size * sizeof(T)); //, alignof(T));
652 if (not b.ptr) throw std::bad_alloc{};
653 _data = (T *)b.ptr;
654 }
655 }
656
668 if (size == 0) return;
669 _size = size;
670 if (not on_heap()) {
671 _data = (T *)buffer.data();
672 } else {
673 blk_t b;
674 if constexpr (is_complex_v<T> && init_dcmplx)
675 b = mallocator<>::allocate_zero(size * sizeof(T));
676 else
677 b = mallocator<>::allocate(size * sizeof(T));
678 if (not b.ptr) throw std::bad_alloc{};
679 _data = (T *)b.ptr;
680 }
681
682 // call placement new for non trivial and non complex types
683 if constexpr (!std::is_trivial_v<T> and !is_complex_v<T>) {
684 for (size_t i = 0; i < size; ++i) new (_data + i) T();
685 }
686 }
687
694 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
695
702 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
703
708 [[nodiscard]] bool on_heap() const { return _size > Size; }
709
714 [[nodiscard]] bool is_null() const noexcept {
715#ifdef NDA_DEBUG
716 EXPECTS((_data == nullptr) == (_size == 0));
717#endif
718 return _data == nullptr;
719 }
720
725 [[nodiscard]] T *data() const noexcept { return _data; }
726
731 [[nodiscard]] long size() const noexcept { return _size; }
732 };
733
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");
743
744 private:
745 // Pointer to the start of the actual data.
746 T *_data = nullptr;
747
748 // Size of the data (number of T elements). Invariant: size > 0 iif data != 0.
749 size_t _size = 0;
750
751 // Type of the memory block, i.e. a pointer to the data and its size.
752 using blk_t = std::pair<T *, size_t>;
753
754 // For shared ownership (points to a blk_T_t).
755 std::shared_ptr<void> sptr;
756
757 public:
759 using value_type = T;
760
762 static constexpr auto address_space = AdrSp;
763
765 handle_shared() = default;
766
775 handle_shared(T *data, size_t size, void *foreign_handle, void (*foreign_decref)(void *)) noexcept
776 : _data(data), _size(size), sptr{foreign_handle, foreign_decref} {}
777
784 template <Allocator A>
786 requires(A::address_space == address_space)
787 : _data(h.data()), _size(h.size()) {
788 if (not h.is_null()) sptr = h.get_sptr();
789 }
790
797 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
798
805 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
806
811 [[nodiscard]] bool is_null() const noexcept {
812#ifdef NDA_DEBUG
813 // Check the Invariants in Debug Mode
814 EXPECTS((_data == nullptr) == (_size == 0));
815#endif
816 return _data == nullptr;
817 }
818
823 [[nodiscard]] long refcount() const noexcept { return sptr.use_count(); }
824
829 [[nodiscard]] T *data() const noexcept { return _data; }
830
835 [[nodiscard]] long size() const noexcept { return _size; }
836 };
837
844 template <typename T, AddressSpace AdrSp = Host>
846 private:
847 // Value type of the data with const removed.
848 using T0 = std::remove_const_t<T>;
849
850 // Parent handle (required for regular -> shared promotion in Python Converter).
851 handle_heap<T0> const *_parent = nullptr;
852
853 // Pointer to the start of the actual data.
854 T *_data = nullptr;
855
856 public:
858 using value_type = T;
859
861 static constexpr auto address_space = AdrSp;
862
864 handle_borrowed() = default;
865
868
871
874
879 handle_borrowed(T *ptr) noexcept : _data(ptr) {}
880
888 template <Handle H>
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>)
891 handle_borrowed(H const &h, long offset = 0) noexcept : _data(h.data() + offset) {
892 if constexpr (std::is_same_v<H, handle_heap<T0>>) _parent = &h;
893 }
894
901 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
902
909 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
910
915 [[nodiscard]] bool is_null() const noexcept { return _data == nullptr; }
916
921 [[nodiscard]] handle_heap<T0> const *parent() const { return _parent; }
922
927 [[nodiscard]] T *data() const noexcept { return _data; }
928 };
929
931
932} // namespace nda::mem
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.
Definition handle.hpp:32
static constexpr do_not_initialize_t do_not_initialize
Instance of nda::mem::do_not_initialize_t.
Definition handle.hpp:56
void memcpy(void *dest, void const *src, size_t count)
Call the correct memcpy function based on the given address spaces.
Definition memcpy.hpp:40
static constexpr init_zero_t init_zero
Instance of nda::mem::init_zero_t.
Definition handle.hpp:62
constexpr bool is_complex_v
Constexpr variable that is true if type T is a std::complex type.
Definition traits.hpp:65
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.
Definition handle.hpp:41
T & get() noexcept
Get reference to the wrapped object.
Definition handle.hpp:46
T const & get() const noexcept
Get const reference to the wrapped object.
Definition handle.hpp:49
T x
Wrapped object of type T.
Definition handle.hpp:43
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.
Definition handle.hpp:53
handle_borrowed(T *ptr) noexcept
Construct a borrowed handle from a pointer to the data.
Definition handle.hpp:879
handle_heap< T0 > const * parent() const
Get a pointer to the parent handle.
Definition handle.hpp:921
handle_borrowed(H const &h, long offset=0) noexcept
Construct a borrowed handle from a another handle.
Definition handle.hpp:891
static constexpr auto address_space
Definition handle.hpp:861
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.
Definition handle.hpp:901
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:915
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:909
handle_borrowed(handle_borrowed const &)=default
Default copy constructor.
T value_type
Value type of the data.
Definition handle.hpp:858
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:927
A handle for a memory block on the heap.
Definition handle.hpp:86
long size() const noexcept
Get the size of the handle.
Definition handle.hpp:334
~handle_heap() noexcept
Destructor for the handle.
Definition handle.hpp:152
A allocator_type
nda::mem::Allocator type.
Definition handle.hpp:133
handle_heap & operator=(handle_heap const &h)
Copy assignment operator utilizes the copy constructor and move assignment operator to make a deep co...
Definition handle.hpp:208
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:310
handle_heap(handle_heap &&h) noexcept
Move constructor simply copies the pointers and size and resets the source handle to a null state.
Definition handle.hpp:163
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.
Definition handle.hpp:260
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:328
handle_heap(long size)
Construct a handle by allocating memory for the data of a given size and initializing it depending on...
Definition handle.hpp:279
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 ...
Definition handle.hpp:239
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.
Definition handle.hpp:248
T value_type
Value type of the data.
Definition handle.hpp:130
bool is_null() const noexcept
Definition handle.hpp:316
handle_heap(handle_heap const &h)
Copy constructor makes a deep copy of the data from another handle.
Definition handle.hpp:193
T & operator[](long i) noexcept
Subscript operator to access the data.
Definition handle.hpp:302
static constexpr auto address_space
Definition handle.hpp:136
handle_heap & operator=(handle_heap &&h) noexcept
Move assignment operator first releases the resources held by the current handle and then moves the r...
Definition handle.hpp:174
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.
Definition handle.hpp:142
handle_heap(H const &h)
Construct a handle by making a deep copy of the data from another handle.
Definition handle.hpp:220
handle_shared(handle_heap< T, A > const &h) noexcept
Construct a shared handle from an nda::mem::handle_heap.
Definition handle.hpp:785
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.
Definition handle.hpp:797
static constexpr auto address_space
Definition handle.hpp:762
long refcount() const noexcept
Get the reference count of the shared object.
Definition handle.hpp:823
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:811
T value_type
Value type of the data.
Definition handle.hpp:759
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:805
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.
Definition handle.hpp:775
T * data() const noexcept
Definition handle.hpp:829
long size() const noexcept
Definition handle.hpp:835
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
Definition handle.hpp:511
handle_sso()
Default constructor.
Definition handle.hpp:514
long size() const noexcept
Get the size of the handle.
Definition handle.hpp:731
~handle_sso() noexcept
Destructor for the handle.
Definition handle.hpp:522
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...
Definition handle.hpp:585
T & operator[](long i) noexcept
Subscript operator to access the data.
Definition handle.hpp:694
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:714
handle_sso & operator=(handle_sso &&h) noexcept
Move assignment operator first releases the resources held by the current handle and then either copi...
Definition handle.hpp:550
handle_sso(long size)
Construct a handle for the data of a given size and initialize it depending on the value type.
Definition handle.hpp:667
handle_sso(handle_sso const &h)
Copy construct a handle by making a deep copy of the data from the source handle.
Definition handle.hpp:570
T value_type
Value type of the data.
Definition handle.hpp:508
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:725
bool on_heap() const
Check if the data is/should be stored on the heap.
Definition handle.hpp:708
handle_sso(long size, do_not_initialize_t)
Construct a handle for the data of a given size and do not initialize it.
Definition handle.hpp:623
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...
Definition handle.hpp:643
handle_sso(handle_sso &&h) noexcept
Move constructor either copies the heap pointers or makes a deep copy of the stack data.
Definition handle.hpp:529
handle_sso(H const &h)
Construct a handle by making a deep copy of the data from another owning handle.
Definition handle.hpp:607
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:702
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated (always on Host).
Definition handle.hpp:359
handle_stack()=default
Default constructor leaves the data uninitialized.
handle_stack(long)
Construct a handle and initialize the data depending on the value type.
Definition handle.hpp:424
T & operator[](long i) noexcept
Subscript operator to access the data.
Definition handle.hpp:436
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:456
handle_stack & operator=(handle_stack const &h)
Copy assignment operator makes a deep copy of the data from the source handle using placement new.
Definition handle.hpp:403
~handle_stack() noexcept
Destructor for the handle.
Definition handle.hpp:365
handle_stack(handle_stack const &h) noexcept
Copy constructor simply calls the copy assignment operator.
Definition handle.hpp:397
handle_stack(long, do_not_initialize_t)
Construct a handle and do not initialize the data.
Definition handle.hpp:409
handle_stack(handle_stack &&h) noexcept
Move constructor simply calls the copy assignment operator.
Definition handle.hpp:380
handle_stack & operator=(handle_stack &&h) noexcept
Move assignment operator simply calls the copy assignment operator.
Definition handle.hpp:387
handle_stack(long, init_zero_t)
Construct a handle and initialize the data to zero (only for scalar and complex types).
Definition handle.hpp:412
static constexpr long size() noexcept
Get the size of the handle.
Definition handle.hpp:462
static constexpr bool is_null() noexcept
Check if the handle is in a null state.
Definition handle.hpp:450
T value_type
Value type of the data.
Definition handle.hpp:356
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:444
Tag used in constructors to indicate that the memory should be initialized to zero.
Definition handle.hpp:59