TRIQS/nda 2.0.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 // NB: with a custom deleter, shared_ptr does NOT delete the managed object itself,
127 // so we must free the blk_T_t node allocated by `new blk_T_t{...}` in get_sptr().
128 static void deleter(void *p) noexcept {
129 destruct(*((blk_T_t *)p));
130 delete (blk_T_t *)p;
131 }
132
133 public:
135 using value_type = T;
136
138 using allocator_type = A;
139
141 static constexpr auto address_space = allocator_type::address_space;
142
147 std::shared_ptr<void> get_sptr() const {
148 if (not sptr) sptr.reset(new blk_T_t{_data, _size}, deleter);
149 return sptr;
150 }
151
157 ~handle_heap() noexcept {
158 if (not sptr and not(is_null())) destruct({_data, _size});
159 }
160
162 handle_heap() = default;
163
168 handle_heap(handle_heap &&h) noexcept : _data(h._data), _size(h._size), sptr(std::move(h.sptr)) {
169 h._data = nullptr;
170 h._size = 0;
171 }
172
180 // release current resources if they are not shared and not null
181 if (not sptr and not(is_null())) destruct({_data, _size});
182
183 // move the resources from the source handle
184 _data = h._data;
185 _size = h._size;
186 sptr = std::move(h.sptr);
187
188 // reset the source handle to a null state
189 h._data = nullptr;
190 h._size = 0;
191 return *this;
192 }
193
199 if (is_null()) return;
200 if constexpr (std::is_trivially_copyable_v<T>) {
201 memcpy<address_space, address_space>(_data, h.data(), h.size() * sizeof(T));
202 } else {
203 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
204 }
205 }
206
214 *this = handle_heap{h};
215 return *this;
216 }
217
224 template <OwningHandle<value_type> H>
225 explicit handle_heap(H const &h) : handle_heap(h.size(), do_not_initialize) {
226 if (is_null()) return;
227 if constexpr (std::is_trivially_copyable_v<T>) {
228 memcpy<address_space, H::address_space>((void *)_data, (void *)h.data(), _size * sizeof(T));
229 } else {
230 static_assert(address_space == H::address_space,
231 "Constructing an nda::mem::handle_heap from a handle of a different address space requires a trivially copyable value_type");
232 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
233 }
234 }
235
243 template <Allocator AS>
245 *this = handle_heap{h};
246 return *this;
247 }
248
254 if (size == 0) return;
255 auto b = allocator.allocate(size * sizeof(T));
256 if (not b.ptr) throw std::bad_alloc{};
257 _data = (T *)b.ptr;
258 _size = size;
259 }
260
266 if (size == 0) return;
267 auto b = allocator.allocate_zero(size * sizeof(T));
268 if (not b.ptr) throw std::bad_alloc{};
269 _data = (T *)b.ptr;
270 _size = size;
271 }
272
285 if (size == 0) return;
286 blk_t b;
287 if constexpr (is_complex_v<T> && init_dcmplx)
288 b = allocator.allocate_zero(size * sizeof(T));
289 else
290 b = allocator.allocate(size * sizeof(T));
291 if (not b.ptr) throw std::bad_alloc{};
292 _data = (T *)b.ptr;
293 _size = size;
294
295 // call placement new for non trivial and non complex types
296 if constexpr (!std::is_trivial_v<T> and !is_complex_v<T>) {
297 for (size_t i = 0; i < size; ++i) new (_data + i) T();
298 }
299 }
300
307 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
308
315 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
316
321 [[nodiscard]] bool is_null() const noexcept {
322#ifdef NDA_DEBUG
323 // check the invariants in debug mode
324 EXPECTS((_data == nullptr) == (_size == 0));
325#endif
326 return _data == nullptr;
327 }
328
333 [[nodiscard]] T *data() const noexcept { return _data; }
334
339 [[nodiscard]] long size() const noexcept { return _size; }
340 };
341
350 template <typename T, size_t Size>
352 static_assert(std::is_copy_constructible_v<T>, "nda::mem::handle_stack requires the value_type to be copy constructible");
353 static_assert(std::is_nothrow_destructible_v<T>, "nda::mem::handle_stack requires the value_type to have a non-throwing destructor");
354
355 private:
356 // Memory buffer on the stack to store the data.
357 std::array<char, sizeof(T) * Size> buffer;
358
359 public:
361 using value_type = T;
362
364 static constexpr auto address_space = Host;
365
370 ~handle_stack() noexcept {
371 if constexpr (!std::is_trivial_v<T>) {
372 // explicitly call the destructor for each non-trivial object
373 for (size_t i = 0; i < Size; ++i) data()[i].~T();
374 }
375 }
376
378 handle_stack() = default;
379
385 handle_stack(handle_stack &&h) noexcept { operator=(h); }
386
393 operator=(h);
394 return *this;
395 }
396
402 handle_stack(handle_stack const &h) noexcept { operator=(h); }
403
409 for (size_t i = 0; i < Size; ++i) new (data() + i) T(h[i]);
410 return *this;
411 }
412
415
417 handle_stack(long /*size*/, init_zero_t) {
418 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");
419 for (size_t i = 0; i < Size; ++i) data()[i] = 0;
420 }
421
429 handle_stack(long /*size*/) : handle_stack{} {
430 if constexpr (!std::is_trivial_v<T> and !is_complex_v<T>) {
431 for (size_t i = 0; i < Size; ++i) new (data() + i) T();
432 }
433 }
434
441 [[nodiscard]] T &operator[](long i) noexcept { return data()[i]; }
442
449 [[nodiscard]] T const &operator[](long i) const noexcept { return data()[i]; }
450
455 static constexpr bool is_null() noexcept { return false; }
456
461 [[nodiscard]] T *data() const noexcept { return (T *)buffer.data(); }
462
467 static constexpr long size() noexcept { return Size; }
468 };
469
483 template <typename T, size_t Size>
484 struct handle_sso { // struct alignas(alignof(T)) handle_sso {
485 static_assert(Size > 0, "Size == 0 makes no sense in nda::mem::handle_sso");
486 static_assert(std::is_copy_constructible_v<T>, "nda::mem::handle_sso requires the value_type to be copy constructible");
487 static_assert(std::is_nothrow_destructible_v<T>, "nda::mem::handle_sso requires the value_type to have a non-throwing destructor");
488
489 private:
490 // Memory buffer on the stack to store the data.
491 std::array<char, sizeof(T) * Size> buffer;
492
493 // Pointer to the start of the actual data.
494 T *_data = nullptr;
495
496 // Size of the data (number of T elements). Invariant: size > 0 iif data != nullptr.
497 size_t _size = 0;
498
499 // Release the handled memory.
500 void clean() noexcept {
501 if (is_null()) return;
502 if constexpr (!std::is_trivial_v<T>) {
503 // explicitly call the destructor for each non-trivial object
504 for (size_t i = 0; i < _size; ++i) data()[i].~T();
505 }
506 if (on_heap()) mallocator<>::deallocate({(char *)_data, _size * sizeof(T)});
507 _data = nullptr;
508 _size = 0;
509 }
510
511 public:
513 using value_type = T;
514
516 static constexpr auto address_space = Host;
517
519 handle_sso() {}; // NOLINT (user-defined constructor to avoid value initialization of the buffer)
520
527 ~handle_sso() noexcept { clean(); }
528
534 handle_sso(handle_sso &&h) noexcept : _size(h._size) {
535 if (on_heap()) {
536 _data = h._data;
537 } else {
538 if (_size != 0) {
539 _data = (T *)buffer.data();
540 for (size_t i = 0; i < _size; ++i) new (data() + i) T(h[i]);
541 }
542 }
543 h._data = nullptr;
544 h._size = 0;
545 }
546
556 clean();
557 _size = h._size;
558 if (on_heap()) {
559 _data = h._data;
560 } else {
561 if (_size != 0) {
562 _data = (T *)buffer.data();
563 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
564 }
565 }
566 h._data = nullptr;
567 h._size = 0;
568 return *this;
569 }
570
576 if (is_null()) return;
577 if constexpr (std::is_trivially_copyable_v<T>) {
578 memcpy<address_space, address_space>((void *)_data, (void *)h.data(), _size * sizeof(T));
579 } else {
580 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
581 }
582 }
583
591 if (this == &h) return *this; // self assignment
592 clean();
593 _size = h._size;
594 if (_size == 0) return *this;
595 if (on_heap()) {
596 auto b = mallocator<>::allocate(_size * sizeof(T));
597 if (not b.ptr) throw std::bad_alloc{};
598 _data = (T *)b.ptr;
599 } else {
600 _data = (T *)buffer.data();
601 }
602 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
603 return *this;
604 }
605
611 template <OwningHandle<value_type> H>
612 explicit handle_sso(H const &h) : handle_sso(h.size(), do_not_initialize) {
613 if (is_null()) return;
614 if constexpr (std::is_trivially_copyable_v<T>) {
615 memcpy<address_space, H::address_space>((void *)_data, (void *)h.data(), _size * sizeof(T));
616 } else {
617 static_assert(address_space == H::address_space,
618 "Constructing an nda::mem::handle_sso from a handle of a different address space requires a trivially copyable value_type");
619 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
620 }
621 }
622
629 if (size == 0) return;
630 _size = size;
631 if (not on_heap()) {
632 _data = (T *)buffer.data();
633 } else {
634 auto b = mallocator<>::allocate(size * sizeof(T));
635 if (not b.ptr) throw std::bad_alloc{};
636 _data = (T *)b.ptr;
637 }
638 }
639
649 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");
650 if (size == 0) return;
651 _size = size;
652 if (not on_heap()) {
653 _data = (T *)buffer.data();
654 for (size_t i = 0; i < _size; ++i) data()[i] = 0;
655 } else {
656 auto b = mallocator<>::allocate_zero(size * sizeof(T)); //, alignof(T));
657 if (not b.ptr) throw std::bad_alloc{};
658 _data = (T *)b.ptr;
659 }
660 }
661
673 if (size == 0) return;
674 _size = size;
675 if (not on_heap()) {
676 _data = (T *)buffer.data();
677 } else {
678 blk_t b;
679 if constexpr (is_complex_v<T> && init_dcmplx)
680 b = mallocator<>::allocate_zero(size * sizeof(T));
681 else
682 b = mallocator<>::allocate(size * sizeof(T));
683 if (not b.ptr) throw std::bad_alloc{};
684 _data = (T *)b.ptr;
685 }
686
687 // call placement new for non trivial and non complex types
688 if constexpr (!std::is_trivial_v<T> and !is_complex_v<T>) {
689 for (size_t i = 0; i < size; ++i) new (_data + i) T();
690 }
691 }
692
699 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
700
707 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
708
713 [[nodiscard]] bool on_heap() const { return _size > Size; }
714
719 [[nodiscard]] bool is_null() const noexcept {
720#ifdef NDA_DEBUG
721 EXPECTS((_data == nullptr) == (_size == 0));
722#endif
723 return _data == nullptr;
724 }
725
730 [[nodiscard]] T *data() const noexcept { return _data; }
731
736 [[nodiscard]] long size() const noexcept { return _size; }
737 };
738
745 template <typename T, AddressSpace AdrSp>
747 static_assert(std::is_nothrow_destructible_v<T>, "nda::mem::handle_shared requires the value_type to have a non-throwing destructor");
748
749 private:
750 // Pointer to the start of the actual data.
751 T *_data = nullptr;
752
753 // Size of the data (number of T elements). Invariant: size > 0 iif data != 0.
754 size_t _size = 0;
755
756 // Type of the memory block, i.e. a pointer to the data and its size.
757 using blk_t = std::pair<T *, size_t>;
758
759 // For shared ownership (points to a blk_T_t).
760 std::shared_ptr<void> sptr;
761
762 public:
764 using value_type = T;
765
767 static constexpr auto address_space = AdrSp;
768
770 handle_shared() = default;
771
780 handle_shared(T *data, size_t size, void *foreign_handle, void (*foreign_decref)(void *)) noexcept
781 : _data(data), _size(size), sptr{foreign_handle, foreign_decref} {}
782
789 template <Allocator A>
791 requires(A::address_space == address_space)
792 : _data(h.data()), _size(h.size()) {
793 if (not h.is_null()) sptr = h.get_sptr();
794 }
795
802 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
803
810 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
811
816 [[nodiscard]] bool is_null() const noexcept {
817#ifdef NDA_DEBUG
818 // Check the Invariants in Debug Mode
819 EXPECTS((_data == nullptr) == (_size == 0));
820#endif
821 return _data == nullptr;
822 }
823
828 [[nodiscard]] long refcount() const noexcept { return sptr.use_count(); }
829
834 [[nodiscard]] T *data() const noexcept { return _data; }
835
840 [[nodiscard]] long size() const noexcept { return _size; }
841 };
842
849 template <typename T, AddressSpace AdrSp = Host>
851 private:
852 // Value type of the data with const removed.
853 using T0 = std::remove_const_t<T>;
854
855 // Parent handle (required for regular -> shared promotion in Python Converter).
856 handle_heap<T0> const *_parent = nullptr;
857
858 // Pointer to the start of the actual data.
859 T *_data = nullptr;
860
861 public:
863 using value_type = T;
864
866 static constexpr auto address_space = AdrSp;
867
869 handle_borrowed() = default;
870
873
876
879
884 handle_borrowed(T *ptr) noexcept : _data(ptr) {}
885
893 template <Handle H>
894 requires(address_space == H::address_space and (std::is_const_v<value_type> or !std::is_const_v<typename H::value_type>)
895 and std::is_same_v<const value_type, const typename H::value_type>)
896 handle_borrowed(H const &h, long offset = 0) noexcept : _data(h.data() + offset) {
897 if constexpr (std::is_same_v<H, handle_heap<T0>>) _parent = &h;
898 }
899
906 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
907
914 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
915
920 [[nodiscard]] bool is_null() const noexcept { return _data == nullptr; }
921
926 [[nodiscard]] handle_heap<T0> const *parent() const { return _parent; }
927
932 [[nodiscard]] T *data() const noexcept { return _data; }
933 };
934
936
937} // namespace nda::mem
@ 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.
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:884
handle_heap< T0 > const * parent() const
Get a pointer to the parent handle.
Definition handle.hpp:926
handle_borrowed(H const &h, long offset=0) noexcept
Construct a borrowed handle from another handle.
Definition handle.hpp:896
static constexpr auto address_space
Definition handle.hpp:866
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:906
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:920
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:914
handle_borrowed(handle_borrowed const &)=default
Default copy constructor.
T value_type
Value type of the data.
Definition handle.hpp:863
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:932
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:339
~handle_heap() noexcept
Destructor for the handle.
Definition handle.hpp:157
A allocator_type
nda::mem::Allocator type.
Definition handle.hpp:138
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:213
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:315
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:168
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:265
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:333
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:284
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:244
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:253
T value_type
Value type of the data.
Definition handle.hpp:135
bool is_null() const noexcept
Definition handle.hpp:321
handle_heap(handle_heap const &h)
Copy constructor makes a deep copy of the data from another handle.
Definition handle.hpp:198
T & operator[](long i) noexcept
Subscript operator to access the data.
Definition handle.hpp:307
static constexpr auto address_space
Definition handle.hpp:141
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:179
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:147
handle_heap(H const &h)
Construct a handle by making a deep copy of the data from another handle.
Definition handle.hpp:225
handle_shared(handle_heap< T, A > const &h) noexcept
Construct a shared handle from an nda::mem::handle_heap.
Definition handle.hpp:790
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:802
static constexpr auto address_space
Definition handle.hpp:767
long refcount() const noexcept
Get the reference count of the shared object.
Definition handle.hpp:828
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:816
T value_type
Value type of the data.
Definition handle.hpp:764
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:810
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:780
T * data() const noexcept
Definition handle.hpp:834
long size() const noexcept
Definition handle.hpp:840
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
Definition handle.hpp:516
handle_sso()
Default constructor.
Definition handle.hpp:519
long size() const noexcept
Get the size of the handle.
Definition handle.hpp:736
~handle_sso() noexcept
Destructor for the handle.
Definition handle.hpp:527
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:590
T & operator[](long i) noexcept
Subscript operator to access the data.
Definition handle.hpp:699
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:719
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:555
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:672
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:575
T value_type
Value type of the data.
Definition handle.hpp:513
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:730
bool on_heap() const
Check if the data is/should be stored on the heap.
Definition handle.hpp:713
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:628
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:648
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:534
handle_sso(H const &h)
Construct a handle by making a deep copy of the data from another owning handle.
Definition handle.hpp:612
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:707
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated (always on Host).
Definition handle.hpp:364
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:429
T & operator[](long i) noexcept
Subscript operator to access the data.
Definition handle.hpp:441
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:461
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:408
~handle_stack() noexcept
Destructor for the handle.
Definition handle.hpp:370
handle_stack(handle_stack const &h) noexcept
Copy constructor simply calls the copy assignment operator.
Definition handle.hpp:402
handle_stack(long, do_not_initialize_t)
Construct a handle and do not initialize the data.
Definition handle.hpp:414
handle_stack(handle_stack &&h) noexcept
Move constructor simply calls the copy assignment operator.
Definition handle.hpp:385
handle_stack & operator=(handle_stack &&h) noexcept
Move assignment operator simply calls the copy assignment operator.
Definition handle.hpp:392
handle_stack(long, init_zero_t)
Construct a handle and initialize the data to zero (only for scalar and complex types).
Definition handle.hpp:417
static constexpr long size() noexcept
Get the size of the handle.
Definition handle.hpp:467
static constexpr bool is_null() noexcept
Check if the handle is in a null state.
Definition handle.hpp:455
T value_type
Value type of the data.
Definition handle.hpp:361
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:449
Tag used in constructors to indicate that the memory should be initialized to zero.
Definition handle.hpp:59