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 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 2018 Centre national de la recherche scientifique (CNRS)
3// Copyright (c) 2018-2023 Simons Foundation
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0.txt
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17// Authors: Miguel Morales, Olivier Parcollet, Nils Wentzell
18
19/**
20 * @file
21 * @brief Provides various handles to take care of memory management for nda::basic_array
22 * and nda::basic_array_view types.
23 */
24
25#pragma once
26
27#include "./allocators.hpp"
28#include "./memcpy.hpp"
29#include "../concepts.hpp"
30#include "../macros.hpp"
31
32#include <array>
33#include <memory>
34#include <type_traits>
35#include <utility>
36
37namespace nda::mem {
38
39 /**
40 * @addtogroup mem_utils
41 * @{
42 */
43
44 /// Should we initialize memory for complex double types to zero.
45 static constexpr bool init_dcmplx = true;
46
47 /**
48 * @brief Wraps an arbitrary type to have a specified alignment.
49 *
50 * @tparam T Given type.
51 * @tparam Al Alignment.
52 */
53 template <typename T, int Al>
54 struct alignas(Al) aligner {
55 /// Wrapped object of type T.
56 T x;
57
58 /// Get reference to the wrapped object.
59 [[nodiscard]] T &get() noexcept { return x; }
60
61 /// Get const reference to the wrapped object.
62 [[nodiscard]] T const &get() const noexcept { return x; }
63 };
64
65 /// Tag used in constructors to indicate that the memory should not be initialized.
67
68 /// Instance of nda::mem::do_not_initialize_t.
69 inline static constexpr do_not_initialize_t do_not_initialize{};
70
71 /// Tag used in constructors to indicate that the memory should be initialized to zero.
72 struct init_zero_t {};
73
74 /// Instance of nda::mem::init_zero_t.
75 inline static constexpr init_zero_t init_zero{};
76
77 /** @} */
78
79 /**
80 * @addtogroup mem_handles
81 * @{
82 */
83
84 /// @cond
85 // Forward declaration.
86 template <typename T, AddressSpace AdrSp = Host>
87 struct handle_shared;
88 /// @endcond
89
90 /**
91 * @brief A handle for a memory block on the heap.
92 *
93 * @details By default it uses nda::mem::mallocator to allocate/deallocate memory.
94 *
95 * @tparam T Value type of the data.
96 * @tparam A nda::mem::Allocator type.
97 */
98 template <typename T, Allocator A = mallocator<>>
99 struct handle_heap {
100 static_assert(std::is_nothrow_destructible_v<T>, "nda::mem::handle_heap requires the value_type to have a non-throwing destructor");
101
102 private:
103 // Pointer to the start of the actual data.
104 T *_data = nullptr;
105
106 // Size of the data (number of T elements). Invariant: size > 0 iif data != nullptr.
107 size_t _size = 0;
108
109 // Allocator to use.
110#ifndef NDA_DEBUG_LEAK_CHECK
111 static inline A allocator; // NOLINT (allocator is not specific to a single instance)
112#else
113 static inline leak_check<A> allocator; // NOLINT (allocator is not specific to a single instance)
114#endif
115
116 // For shared ownership (points to a blk_T_t).
117 mutable std::shared_ptr<void> sptr;
118
119 // Type of the memory block, i.e. a pointer to the data and its size.
120 using blk_T_t = std::pair<T *, size_t>;
121
122 // Release the handled memory (data pointer and size are not set to null here).
123 static void destruct(blk_T_t b) noexcept {
124 auto [data, size] = b;
125
126 // do nothing if the data is null
127 if (data == nullptr) return;
128
129 // if needed, call the destructors of the objects stored
130 if constexpr (A::address_space == Host and !(std::is_trivial_v<T> or nda::is_complex_v<T>)) {
131 for (size_t i = 0; i < size; ++i) data[i].~T();
132 }
133
134 // deallocate the memory block
135 allocator.deallocate({(char *)data, size * sizeof(T)});
136 }
137
138 // Deleter for the shared pointer.
139 static void deleter(void *p) noexcept { destruct(*((blk_T_t *)p)); }
140
141 public:
142 /// Value type of the data.
143 using value_type = T;
144
145 /// nda::mem::Allocator type.
146 using allocator_type = A;
147
148 /// nda::mem::AddressSpace in which the memory is allocated.
149 static constexpr auto address_space = allocator_type::address_space;
150
151 /**
152 * @brief Get a shared pointer to the memory block.
153 * @return A copy of the shared pointer stored in the current handle.
154 */
155 std::shared_ptr<void> get_sptr() const {
156 if (not sptr) sptr.reset(new blk_T_t{_data, _size}, deleter);
157 return sptr;
158 }
159
160 /**
161 * @brief Destructor for the handle.
162 * @details If the shared pointer is set, it does nothing. Otherwise, it explicitly calls the destructor of
163 * non-trivial objects and deallocates the memory.
164 */
165 ~handle_heap() noexcept {
166 if (not sptr and not(is_null())) destruct({_data, _size});
167 }
168
169 /// Default constructor leaves the handle in a null state (`nullptr` and size 0).
170 handle_heap() = default;
171
172 /**
173 * @brief Move constructor simply copies the pointers and size and resets the source handle to a null state.
174 * @param h Source handle.
175 */
176 handle_heap(handle_heap &&h) noexcept : _data(h._data), _size(h._size), sptr(std::move(h.sptr)) {
177 h._data = nullptr;
178 h._size = 0;
179 }
180
181 /**
182 * @brief Move assignment operator first releases the resources held by the current handle and then moves the
183 * resources from the source to the current handle.
184 *
185 * @param h Source handle.
186 */
188 // release current resources if they are not shared and not null
189 if (not sptr and not(is_null())) destruct({_data, _size});
190
191 // move the resources from the source handle
192 _data = h._data;
193 _size = h._size;
194 sptr = std::move(h.sptr);
195
196 // reset the source handle to a null state
197 h._data = nullptr;
198 h._size = 0;
199 return *this;
200 }
201
202 /**
203 * @brief Copy constructor makes a deep copy of the data from another handle.
204 * @param h Source handle.
205 */
206 explicit handle_heap(handle_heap const &h) : handle_heap(h.size(), do_not_initialize) {
207 if (is_null()) return;
208 if constexpr (std::is_trivially_copyable_v<T>) {
209 memcpy<address_space, address_space>(_data, h.data(), h.size() * sizeof(T));
210 } else {
211 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
212 }
213 }
214
215 /**
216 * @brief Copy assignment operator utilizes the copy constructor and move assignment operator to make a deep copy of
217 * the data and size from the source handle.
218 *
219 * @param h Source handle.
220 */
222 *this = handle_heap{h};
223 return *this;
224 }
225
226 /**
227 * @brief Construct a handle by making a deep copy of the data from another handle.
228 *
229 * @tparam H nda::mem::OwningHandle type.
230 * @param h Source handle.
231 */
232 template <OwningHandle<value_type> H>
233 explicit handle_heap(H const &h) : handle_heap(h.size(), do_not_initialize) {
234 if (is_null()) return;
235 if constexpr (std::is_trivially_copyable_v<T>) {
236 memcpy<address_space, H::address_space>((void *)_data, (void *)h.data(), _size * sizeof(T));
237 } else {
238 static_assert(address_space == H::address_space,
239 "Constructing an nda::mem::handle_heap from a handle of a different address space requires a trivially copyable value_type");
240 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
241 }
242 }
243
244 /**
245 * @brief Assignment operator utilizes another constructor and move assignment to make a deep copy of the data and
246 * size from the source handle.
247 *
248 * @tparam AS Allocator type of the source handle.
249 * @param h Source handle with a different allocator.
250 */
251 template <Allocator AS>
252 handle_heap &operator=(handle_heap<T, AS> const &h) {
253 *this = handle_heap{h};
254 return *this;
255 }
256
257 /**
258 * @brief Construct a handle by allocating memory for the data of a given size but without initializing it.
259 * @param size Size of the data (number of elements).
260 */
262 if (size == 0) return;
263 auto b = allocator.allocate(size * sizeof(T));
264 if (not b.ptr) throw std::bad_alloc{};
265 _data = (T *)b.ptr;
266 _size = size;
267 }
268
269 /**
270 * @brief Construct a handle by allocating memory for the data of a given size and initializing it to zero.
271 * @param size Size of the data (number of elements).
272 */
274 if (size == 0) return;
275 auto b = allocator.allocate_zero(size * sizeof(T));
276 if (not b.ptr) throw std::bad_alloc{};
277 _data = (T *)b.ptr;
278 _size = size;
279 }
280
281 /**
282 * @brief Construct a handle by allocating memory for the data of a given size and initializing it depending on the
283 * value type.
284 *
285 * @details The data is initialized as follows:
286 * - If `T` is std::complex and nda::mem::init_dcmplx is true, the data is initialized to zero.
287 * - If `T` is not trivial and not complex, the data is default constructed by placement new operator calls.
288 * - Otherwise, the data is not initialized.
289 *
290 * @param size Size of the data (number of elements).
291 */
292 handle_heap(long size) {
293 if (size == 0) return;
294 blk_t b;
295 if constexpr (is_complex_v<T> && init_dcmplx)
296 b = allocator.allocate_zero(size * sizeof(T));
297 else
298 b = allocator.allocate(size * sizeof(T));
299 if (not b.ptr) throw std::bad_alloc{};
300 _data = (T *)b.ptr;
301 _size = size;
302
303 // call placement new for non trivial and non complex types
304 if constexpr (!std::is_trivial_v<T> and !is_complex_v<T>) {
305 for (size_t i = 0; i < size; ++i) new (_data + i) T();
306 }
307 }
308
309 /**
310 * @brief Subscript operator to access the data.
311 *
312 * @param i Index of the element to access.
313 * @return Reference to the element at the given index.
314 */
315 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
316
317 /**
318 * @brief Subscript operator to access the data.
319 *
320 * @param i Index of the element to access.
321 * @return Const reference to the element at the given index.
322 */
323 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
324
325 /**
326 * @brief Check if the handle is in a null state.
327 * @return True if the data is a `nullptr` (and the size is 0).
328 */
329 [[nodiscard]] bool is_null() const noexcept {
330#ifdef NDA_DEBUG
331 // check the invariants in debug mode
332 EXPECTS((_data == nullptr) == (_size == 0));
333#endif
334 return _data == nullptr;
335 }
336
337 /**
338 * @brief Get a pointer to the stored data.
339 * @return Pointer to the start of the handled memory.
340 */
341 [[nodiscard]] T *data() const noexcept { return _data; }
342
343 /**
344 * @brief Get the size of the handle.
345 * @return Number of elements of type `T` in the handled memory.
346 */
347 [[nodiscard]] long size() const noexcept { return _size; }
348 };
349
350 /**
351 * @brief A handle for a memory block on the stack.
352 *
353 * @note This handle only works with the `Host` nda::mem::AddressSpace.
354 *
355 * @tparam T Value type of the data.
356 * @tparam Size Size of the data (number of elements).
357 */
358 template <typename T, size_t Size>
360 static_assert(std::is_copy_constructible_v<T>, "nda::mem::handle_stack requires the value_type to be copy constructible");
361 static_assert(std::is_nothrow_destructible_v<T>, "nda::mem::handle_stack requires the value_type to have a non-throwing destructor");
362
363 private:
364 // Memory buffer on the stack to store the data.
365 std::array<char, sizeof(T) * Size> buffer;
366
367 public:
368 /// Value type of the data.
369 using value_type = T;
370
371 /// nda::mem::AddressSpace in which the memory is allocated (always on `Host`).
372 static constexpr auto address_space = Host;
373
374 /**
375 * @brief Destructor for the handle.
376 * @details For non-trivial objects, it explicitly calls their destructors. Otherwise, it does nothing.
377 */
378 ~handle_stack() noexcept {
379 if constexpr (!std::is_trivial_v<T>) {
380 // explicitly call the destructor for each non-trivial object
381 for (size_t i = 0; i < Size; ++i) data()[i].~T();
382 }
383 }
384
385 /// Default constructor leaves the data uninitialized.
386 handle_stack() = default;
387
388 /**
389 * @brief Move constructor simply calls the copy assignment operator.
390 * @details If an exception occurs in the constructor of `T`, the program terminates.
391 * @param h Source handle.
392 */
393 handle_stack(handle_stack &&h) noexcept { operator=(h); }
394
395 /**
396 * @brief Move assignment operator simply calls the copy assignment operator.
397 * @details If an exception occurs in the constructor of `T`, the program terminates.
398 * @param h Source handle.
399 */
401 operator=(h);
402 return *this;
403 }
404
405 /**
406 * @brief Copy constructor simply calls the copy assignment operator.
407 * @details If an exception occurs in the constructor of `T`, the program terminates.
408 * @param h Source handle.
409 */
410 handle_stack(handle_stack const &h) noexcept { operator=(h); }
411
412 /**
413 * @brief Copy assignment operator makes a deep copy of the data from the source handle using placement new.
414 * @param h Source handle.
415 */
417 for (size_t i = 0; i < Size; ++i) new (data() + i) T(h[i]);
418 return *this;
419 }
420
421 /// Construct a handle and do not initialize the data.
423
424 /// Construct a handle and initialize the data to zero (only for scalar and complex types).
425 handle_stack(long /*size*/, init_zero_t) {
426 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");
427 for (size_t i = 0; i < Size; ++i) data()[i] = 0;
428 }
429
430 /**
431 * @brief Construct a handle and initialize the data depending on the value type.
432 *
433 * @details The data is initialized as follows:
434 * - If `T` is not trivial and not complex, the data is default constructed by placement new operator calls.
435 * - Otherwise, the data is not initialized.
436 */
437 handle_stack(long /*size*/) : handle_stack{} {
438 if constexpr (!std::is_trivial_v<T> and !is_complex_v<T>) {
439 for (size_t i = 0; i < Size; ++i) new (data() + i) T();
440 }
441 }
442
443 /**
444 * @brief Subscript operator to access the data.
445 *
446 * @param i Index of the element to access.
447 * @return Reference to the element at the given index.
448 */
449 [[nodiscard]] T &operator[](long i) noexcept { return data()[i]; }
450
451 /**
452 * @brief Subscript operator to access the data.
453 *
454 * @param i Index of the element to access.
455 * @return Const reference to the element at the given index.
456 */
457 [[nodiscard]] T const &operator[](long i) const noexcept { return data()[i]; }
458
459 /**
460 * @brief Check if the handle is in a null state.
461 * @return False (there is no null state on the stack).
462 */
463 static constexpr bool is_null() noexcept { return false; }
464
465 /**
466 * @brief Get a pointer to the stored data.
467 * @return Pointer to the start of the handled memory.
468 */
469 [[nodiscard]] T *data() const noexcept { return (T *)buffer.data(); }
470
471 /**
472 * @brief Get the size of the handle.
473 * @return Number of elements of type `T` in the handled memory.
474 */
475 static constexpr long size() noexcept { return Size; }
476 };
477
478 /**
479 * @brief A handle for a memory block on the heap or stack depending on the size of the data.
480 *
481 * @details If the size of the data is less than or equal to the template parameter `Size`, the data is stored on the
482 * stack, otherwise it is stored on the heap (nda::mem::mallocator is used to allocate/deallocate memory on the heap).
483 *
484 * It simulates the small string optimization (SSO) for strings.
485 *
486 * @note This handle only works with the `Host` nda::mem::AddressSpace.
487 *
488 * @tparam T Value type of the data.
489 * @tparam Size Max. size of the data to store on the stack (number of elements).
490 */
491 template <typename T, size_t Size>
492 struct handle_sso { // struct alignas(alignof(T)) handle_sso {
493 static_assert(Size > 0, "Size == 0 makes no sense in nda::mem::handle_sso");
494 static_assert(std::is_copy_constructible_v<T>, "nda::mem::handle_sso requires the value_type to be copy constructible");
495 static_assert(std::is_nothrow_destructible_v<T>, "nda::mem::handle_sso requires the value_type to have a non-throwing destructor");
496
497 private:
498 // Memory buffer on the stack to store the data.
499 std::array<char, sizeof(T) * Size> buffer;
500
501 // Pointer to the start of the actual data.
502 T *_data = nullptr;
503
504 // Size of the data (number of T elements). Invariant: size > 0 iif data != nullptr.
505 size_t _size = 0;
506
507 // Release the handled memory.
508 void clean() noexcept {
509 if (is_null()) return;
510 if constexpr (!std::is_trivial_v<T>) {
511 // explicitly call the destructor for each non-trivial object
512 for (size_t i = 0; i < _size; ++i) data()[i].~T();
513 }
514 if (on_heap()) mallocator<>::deallocate({(char *)_data, _size * sizeof(T)});
515 _data = nullptr;
516 _size = 0;
517 }
518
519 public:
520 /// Value type of the data.
521 using value_type = T;
522
523 /// nda::mem::AddressSpace in which the memory is allocated.
524 static constexpr auto address_space = Host;
525
526 /// Default constructor.
527 handle_sso(){}; // NOLINT (user-defined constructor to avoid value initialization of the buffer)
528
529 /**
530 * @brief Destructor for the handle.
531 *
532 * @details For non-trivial objects, it explicitly calls their destructors. Additionally, it deallocates the memory
533 * if it is stored on the heap and resets the handle to its null state.
534 */
535 ~handle_sso() noexcept { clean(); }
536
537 /**
538 * @brief Move constructor either copies the heap pointers or makes a deep copy of the stack data.
539 * @details In both cases, it resets the source handle to a null state.
540 * @param h Source handle.
541 */
542 handle_sso(handle_sso &&h) noexcept : _size(h._size) {
543 if (on_heap()) {
544 _data = h._data;
545 } else {
546 if (_size != 0) {
547 _data = (T *)buffer.data();
548 for (size_t i = 0; i < _size; ++i) new (data() + i) T(h[i]);
549 }
550 }
551 h._data = nullptr;
552 h._size = 0;
553 }
554
555 /**
556 * @brief Move assignment operator first releases the resources held by the current handle and then either copies
557 * the heap pointers or makes a deep copy of the stack data.
558 *
559 * @details In both cases, it resets the source handle to a null state.
560 *
561 * @param h Source handle.
562 */
564 clean();
565 _size = h._size;
566 if (on_heap()) {
567 _data = h._data;
568 } else {
569 if (_size != 0) {
570 _data = (T *)buffer.data();
571 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
572 }
573 }
574 h._data = nullptr;
575 h._size = 0;
576 return *this;
577 }
578
579 /**
580 * @brief Copy construct a handle by making a deep copy of the data from the source handle.
581 * @param h Source handle.
582 */
584 if (is_null()) return;
585 if constexpr (std::is_trivially_copyable_v<T>) {
586 memcpy<address_space, address_space>((void *)_data, (void *)h.data(), _size * sizeof(T));
587 } else {
588 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
589 }
590 }
591
592 /**
593 * @brief Copy assignment operator first cleans up the current handle and then makes a deep copy of the data from
594 * the source handle.
595 *
596 * @param h Source handle.
597 */
598 handle_sso &operator=(handle_sso const &h) noexcept {
599 if (this == &h) return *this; // self assignment
600 clean();
601 _size = h._size;
602 if (_size == 0) return *this;
603 if (on_heap()) {
604 auto b = mallocator<>::allocate(_size * sizeof(T));
605 if (not b.ptr) throw std::bad_alloc{};
606 _data = (T *)b.ptr;
607 } else {
608 _data = (T *)buffer.data();
609 }
610 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
611 return *this;
612 }
613
614 /**
615 * @brief Construct a handle by making a deep copy of the data from another owning handle.
616 * @details Depending on the size, the memory of the data is either allocated on the heap or on the stack.
617 * @param h Source handle.
618 */
619 template <OwningHandle<value_type> H>
620 explicit handle_sso(H const &h) : handle_sso(h.size(), do_not_initialize) {
621 if (is_null()) return;
622 if constexpr (std::is_trivially_copyable_v<T>) {
623 memcpy<address_space, H::address_space>((void *)_data, (void *)h.data(), _size * sizeof(T));
624 } else {
625 static_assert(address_space == H::address_space,
626 "Constructing an nda::mem::handle_sso from a handle of a different address space requires a trivially copyable value_type");
627 for (size_t i = 0; i < _size; ++i) new (_data + i) T(h[i]);
628 }
629 }
630
631 /**
632 * @brief Construct a handle for the data of a given size and do not initialize it.
633 * @details Depending on the size, the memory of the data is either allocated on the heap or on the stack.
634 * @param size Size of the data (number of elements).
635 */
637 if (size == 0) return;
638 _size = size;
639 if (not on_heap()) {
640 _data = (T *)buffer.data();
641 } else {
642 auto b = mallocator<>::allocate(size * sizeof(T));
643 if (not b.ptr) throw std::bad_alloc{};
644 _data = (T *)b.ptr;
645 }
646 }
647
648 /**
649 * @brief Construct a handle for the data of a given size and initialize it to zero (only for scalar and complex
650 * types).
651 *
652 * @details Depending on the size, the memory of the data is either allocated on the heap or on the stack.
653 *
654 * @param size Size of the data (number of elements).
655 */
657 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");
658 if (size == 0) return;
659 _size = size;
660 if (not on_heap()) {
661 _data = (T *)buffer.data();
662 for (size_t i = 0; i < _size; ++i) data()[i] = 0;
663 } else {
664 auto b = mallocator<>::allocate_zero(size * sizeof(T)); //, alignof(T));
665 if (not b.ptr) throw std::bad_alloc{};
666 _data = (T *)b.ptr;
667 }
668 }
669
670 /**
671 * @brief Construct a handle for the data of a given size and initialize it depending on the value type.
672 *
673 * @details The data is initialized as follows:
674 * - If `T` is std::complex and nda::mem::init_dcmplx is true, the data is initialized to zero.
675 * - If `T` is not trivial and not complex, the data is default constructed by placement new operator calls.
676 * - Otherwise, the data is not initialized.
677 *
678 * @param size Size of the data (number of elements).
679 */
680 handle_sso(long size) {
681 if (size == 0) return;
682 _size = size;
683 if (not on_heap()) {
684 _data = (T *)buffer.data();
685 } else {
686 blk_t b;
687 if constexpr (is_complex_v<T> && init_dcmplx)
688 b = mallocator<>::allocate_zero(size * sizeof(T));
689 else
690 b = mallocator<>::allocate(size * sizeof(T));
691 if (not b.ptr) throw std::bad_alloc{};
692 _data = (T *)b.ptr;
693 }
694
695 // call placement new for non trivial and non complex types
696 if constexpr (!std::is_trivial_v<T> and !is_complex_v<T>) {
697 for (size_t i = 0; i < size; ++i) new (_data + i) T();
698 }
699 }
700
701 /**
702 * @brief Subscript operator to access the data.
703 *
704 * @param i Index of the element to access.
705 * @return Reference to the element at the given index.
706 */
707 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
708
709 /**
710 * @brief Subscript operator to access the data.
711 *
712 * @param i Index of the element to access.
713 * @return Const reference to the element at the given index.
714 */
715 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
716
717 /**
718 * @brief Check if the data is/should be stored on the heap.
719 * @return True if the size is greater than the `Size`.
720 */
721 [[nodiscard]] bool on_heap() const { return _size > Size; }
722
723 /**
724 * @brief Check if the handle is in a null state.
725 * @return True if the data is a `nullptr` (and the size is 0).
726 */
727 [[nodiscard]] bool is_null() const noexcept {
728#ifdef NDA_DEBUG
729 EXPECTS((_data == nullptr) == (_size == 0));
730#endif
731 return _data == nullptr;
732 }
733
734 /**
735 * @brief Get a pointer to the stored data.
736 * @return Pointer to the start of the handled memory.
737 */
738 [[nodiscard]] T *data() const noexcept { return _data; }
739
740 /**
741 * @brief Get the size of the handle.
742 * @return Number of elements of type `T` in the handled memory.
743 */
744 [[nodiscard]] long size() const noexcept { return _size; }
745 };
746
747 /**
748 * @brief A handle for a memory block on the heap with shared ownership.
749 *
750 * @tparam T Value type of the data.
751 * @tparam AdrSp nda::mem::AddressSpace in which the memory is allocated.
752 */
753 template <typename T, AddressSpace AdrSp>
755 static_assert(std::is_nothrow_destructible_v<T>, "nda::mem::handle_shared requires the value_type to have a non-throwing destructor");
756
757 private:
758 // Pointer to the start of the actual data.
759 T *_data = nullptr;
760
761 // Size of the data (number of T elements). Invariant: size > 0 iif data != 0.
762 size_t _size = 0;
763
764 // Type of the memory block, i.e. a pointer to the data and its size.
765 using blk_t = std::pair<T *, size_t>;
766
767 // For shared ownership (points to a blk_T_t).
768 std::shared_ptr<void> sptr;
769
770 public:
771 /// Value type of the data.
772 using value_type = T;
773
774 /// nda::mem::AddressSpace in which the memory is allocated.
775 static constexpr auto address_space = AdrSp;
776
777 /// Default constructor leaves the handle in a null state (`nullptr` and size 0).
778 handle_shared() = default;
779
780 /**
781 * @brief Construct a handle from a shared object from a foreign library.
782 *
783 * @param data Pointer to the start of the shared data.
784 * @param size Size of the data (number of elements).
785 * @param foreign_handle Pointer to the shared object.
786 * @param foreign_decref Function to decrease the reference count of the shared object.
787 */
788 handle_shared(T *data, size_t size, void *foreign_handle, void (*foreign_decref)(void *)) noexcept
789 : _data(data), _size(size), sptr{foreign_handle, foreign_decref} {}
790
791 /**
792 * @brief Construct a shared handle from an nda::mem::handle_heap.
793 *
794 * @tparam A nda::mem::Allocator type of the source handle.
795 * @param h Source handle.
796 */
797 template <Allocator A>
798 handle_shared(handle_heap<T, A> const &h) noexcept
799 requires(A::address_space == address_space)
800 : _data(h.data()), _size(h.size()) {
801 if (not h.is_null()) sptr = h.get_sptr();
802 }
803
804 /**
805 * @brief Subscript operator to access the data.
806 *
807 * @param i Index of the element to access.
808 * @return Reference to the element at the given index.
809 */
810 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
811
812 /**
813 * @brief Subscript operator to access the data.
814 *
815 * @param i Index of the element to access.
816 * @return Const reference to the element at the given index.
817 */
818 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
819
820 /**
821 * @brief Check if the handle is in a null state.
822 * @return True if the data is a `nullptr` (and the size is 0).
823 */
824 [[nodiscard]] bool is_null() const noexcept {
825#ifdef NDA_DEBUG
826 // Check the Invariants in Debug Mode
827 EXPECTS((_data == nullptr) == (_size == 0));
828#endif
829 return _data == nullptr;
830 }
831
832 /**
833 * @brief Get the reference count of the shared object.
834 * @return Reference count of the shared pointer.
835 */
836 [[nodiscard]] long refcount() const noexcept { return sptr.use_count(); }
837
838 /**
839 * @brief Get a pointer to the stored data.
840 * @return Pointer to the start of the handled memory.
841 */
842 [[nodiscard]] T *data() const noexcept { return _data; }
843
844 /**
845 * @brief Get the size of the handle.
846 * @return Number of elements of type `T` in the handled memory.
847 */
848 [[nodiscard]] long size() const noexcept { return _size; }
849 };
850
851 /**
852 * @brief A non-owning handle for a memory block on the heap.
853 *
854 * @tparam T Value type of the data.
855 * @tparam AdrSp nda::mem::AddressSpace in which the memory is allocated.
856 */
857 template <typename T, AddressSpace AdrSp = Host>
859 private:
860 // Value type of the data with const removed.
861 using T0 = std::remove_const_t<T>;
862
863 // Parent handle (required for regular -> shared promotion in Python Converter).
864 handle_heap<T0> const *_parent = nullptr;
865
866 // Pointer to the start of the actual data.
867 T *_data = nullptr;
868
869 public:
870 /// Value type of the data.
871 using value_type = T;
872
873 /// nda::mem::AddressSpace in which the memory is allocated.
874 static constexpr auto address_space = AdrSp;
875
876 /// Default constructor leaves the handle in a null state (nullptr).
877 handle_borrowed() = default;
878
879 /// Default move assignment operator.
881
882 /// Default copy constructor.
884
885 /// Default copy assignment operator.
887
888 /**
889 * @brief Construct a borrowed handle from a pointer to the data.
890 * @param ptr Pointer to the start of the data.
891 */
892 handle_borrowed(T *ptr) noexcept : _data(ptr) {}
893
894 /**
895 * @brief Construct a borrowed handle from a another handle.
896 *
897 * @tparam H nda::mem::Handle type.
898 * @param h Other handle.
899 * @param offset Pointer offset from the start of the data (in number of elements).
900 */
901 template <Handle H>
902 requires(address_space == H::address_space and (std::is_const_v<value_type> or !std::is_const_v<typename H::value_type>)
903 and std::is_same_v<const value_type, const typename H::value_type>)
904 handle_borrowed(H const &h, long offset = 0) noexcept : _data(h.data() + offset) {
905 if constexpr (std::is_same_v<H, handle_heap<T0>>) _parent = &h;
906 }
907
908 /**
909 * @brief Subscript operator to access the data.
910 *
911 * @param i Index of the element to access.
912 * @return Reference to the element at the given index.
913 */
914 [[nodiscard]] T &operator[](long i) noexcept { return _data[i]; }
915
916 /**
917 * @brief Subscript operator to access the data.
918 *
919 * @param i Index of the element to access.
920 * @return Const reference to the element at the given index.
921 */
922 [[nodiscard]] T const &operator[](long i) const noexcept { return _data[i]; }
923
924 /**
925 * @brief Check if the handle is in a null state.
926 * @return True if the data is a `nullptr`.
927 */
928 [[nodiscard]] bool is_null() const noexcept { return _data == nullptr; }
929
930 /**
931 * @brief Get a pointer to the parent handle.
932 * @return Pointer to the parent handle.
933 */
934 [[nodiscard]] handle_heap<T0> const *parent() const { return _parent; }
935
936 /**
937 * @brief Get a pointer to the stored data.
938 * @return Pointer to the start of the handled memory.
939 */
940 [[nodiscard]] T *data() const noexcept { return _data; }
941 };
942
943 /** @} */
944
945} // namespace nda::mem
void swap(nda::basic_array_view< V1, R1, LP1, A1, AP1, OP1 > &a, nda::basic_array_view< V2, R2, LP2, A2, AP2, OP2 > &b)=delete
std::swap is deleted for nda::basic_array_view.
Iterator for nda::basic_array and nda::basic_array_view types.
A generic view of a multi-dimensional array.
basic_array_view(A &&a) noexcept
Generic constructor from any nda::MemoryArray type.
const_iterator end() const noexcept
Get a const iterator to the end of the view/array.
ValueType const * data() const noexcept
Get a pointer to the actual data (in general this is not the beginning of the memory block for a view...
static constexpr bool is_stride_order_C() noexcept
Is the stride order of the view/array in C-order?
iterator begin() noexcept
Get an iterator to the beginning of the view/array.
ValueType * data() noexcept
Get a pointer to the actual data (in general this is not the beginning of thr memory block for a view...
basic_array_view & operator=(RHS const &rhs) noexcept
Assignment operator makes a deep copy of the contents of an nda::ArrayOfRank object.
auto & operator/=(RHS const &rhs) noexcept
Division assignment operator.
static constexpr int rank
Number of dimensions of the view.
decltype(auto) operator[](T const &idx) const &noexcept(has_no_boundcheck)
Subscript operator to access the 1-dimensional view/array.
auto const & shape() const noexcept
Get the shape of the view/array.
static __inline__ decltype(auto) call(Self &&self, Ts const &...idxs) noexcept(has_no_boundcheck)
Implementation of the function call operator.
basic_array_view(layout_t const &idxm, ValueType *p) noexcept
Construct a view from a bare pointer to some contiguous data and a memory layout.
__inline__ decltype(auto) operator()(Ts const &...idxs) &noexcept(has_no_boundcheck)
Non-const overload of nda::basic_array_view::operator()(Ts const &...) const &.
decltype(auto) operator[](T const &x) &&noexcept(has_no_boundcheck)
Rvalue overload of nda::basic_array_view::operator[](T const &) const &.
basic_array_view(R &rg) noexcept
Construct a 1-dimensional view of a general contiguous range.
basic_array_view & operator=(basic_array_view const &rhs) noexcept
Copy assignment operator makes a deep copy of the contents of the view.
basic_array_view(std::array< ValueType, N > &a) noexcept
Construct a 1-dimensional view of a std::array.
auto const & strides() const noexcept
Get the strides of the view/array (see nda::idx_map for more details on how we define strides).
long shape(int i) const noexcept
storage_t storage() &&noexcept
Get the data storage of the view/array.
decltype(auto) operator[](T const &x) &noexcept(has_no_boundcheck)
Non-const overload of nda::basic_array_view::operator[](T const &) const &.
decltype(auto) operator()(_linear_index_t idx) noexcept
Non-const overload of nda::basic_array_view::operator()(_linear_index_t) const.
auto & operator+=(RHS const &rhs) noexcept
Addition assignment operator.
auto indices() const noexcept
Get a range that generates all valid index tuples.
basic_array_view()=default
Default constructor constructs an empty view with a default constructed memory handle and layout.
long is_contiguous() const noexcept
Is the memory layout of the view/array contiguous?
auto & operator=(R const &rhs) noexcept
Assignment operator makes a deep copy of a general contiguous range and assigns it to the 1-dimension...
storage_t & storage() &noexcept
Get the data storage of the view/array.
static constexpr bool is_stride_order_Fortran() noexcept
Is the stride order of the view/array in Fortran-order?
decltype(auto) operator()(_linear_index_t idx) const noexcept
Access the element of the view/array at the given nda::_linear_index_t.
__inline__ decltype(auto) operator()(Ts const &...idxs) const &noexcept(has_no_boundcheck)
Function call operator to access the view/array.
auto & operator*=(RHS const &rhs) noexcept
Multiplication assignment operator.
basic_array_view(std::array< std::remove_const_t< ValueType >, N > const &a) noexcept
Construct a 1-dimensional view of a std::array.
friend void deep_swap(basic_array_view a, basic_array_view b) noexcept
Swap two views by swapping their data.
iterator end() noexcept
Get an iterator to the end of the view/array.
long size() const noexcept
Get the total size of the view/array.
auto & operator-=(RHS const &rhs) noexcept
Subtraction assignment operator.
bool empty() const
Is the view/array empty?
basic_array_view(std::array< long, Rank > const &shape, ValueType *p) noexcept
Construct a view from a bare pointer to some contiguous data and a shape.
bool is_empty() const noexcept
friend void swap(basic_array_view &a, basic_array_view &b) noexcept
Swap two views by swapping their memory handles and layouts.
constexpr auto stride_order() const noexcept
Get the stride order of the memory layout of the view/array (see nda::idx_map for more details on how...
const_iterator cbegin() const noexcept
Get a const iterator to the beginning of the view/array.
basic_array_view(layout_t const &idxm, storage_t st)
Construct a view from a given layout and memory handle.
static constexpr int iterator_rank
Rank of the nda::array_iterator for the view/array.
basic_array_view(basic_array_view &&)=default
Default move constructor moves the memory handle and layout.
void rebind(basic_array_view< T, R, LP, A, AP, OP > v) noexcept
Rebind the current view to another view.
basic_array_view(basic_array_view const &)=default
Default copy constructor copies the memory handle and layout.
__inline__ decltype(auto) operator()(Ts const &...idxs) &&noexcept(has_no_boundcheck)
Rvalue overload of nda::basic_array_view::operator()(Ts const &...) const &.
long extent(int i) const noexcept
Get the extent of the ith dimension.
constexpr auto const & indexmap() const noexcept
Get the memory layout of the view/array.
const_iterator begin() const noexcept
Get a const iterator to the beginning of the view/array.
const_iterator cend() const noexcept
Get a const iterator to the end of the view/array.
storage_t const & storage() const &noexcept
Get the data storage of the view/array.
A generic multi-dimensional array.
auto & operator+=(RHS const &rhs) noexcept
Addition assignment operator.
decltype(auto) operator[](T const &idx) const &noexcept(has_no_boundcheck)
Subscript operator to access the 1-dimensional view/array.
basic_array(basic_array< ValueType, 2, LayoutPolicy, A2, ContainerPolicy > &&a) noexcept
Construct a 2-dimensional array from another 2-dimensional array with a different algebra.
basic_array & operator=(RHS const &rhs)
Assignment operator makes a deep copy of an nda::ArrayOfRank object.
static constexpr bool is_stride_order_Fortran() noexcept
Is the stride order of the view/array in Fortran-order?
ValueType const * data() const noexcept
Get a pointer to the actual data (in general this is not the beginning of the memory block for a view...
ValueType * data() noexcept
Get a pointer to the actual data (in general this is not the beginning of thr memory block for a view...
long shape(int i) const noexcept
const_iterator cbegin() const noexcept
Get a const iterator to the beginning of the view/array.
static constexpr int rank
Number of dimensions of the array.
static constexpr bool is_stride_order_C() noexcept
Is the stride order of the view/array in C-order?
storage_t & storage() &noexcept
Get the data storage of the view/array.
basic_array(basic_array< ValueType, Rank, LayoutPolicy, A, CP > a) noexcept
Construct an array from another array with a different algebra and/or container policy.
auto const & strides() const noexcept
Get the strides of the view/array (see nda::idx_map for more details on how we define strides).
basic_array(Ints... is)
Construct an array with the given dimensions.
static basic_array ones(Ints... is)
Make a one-initialized array with the given dimensions.
const_iterator begin() const noexcept
Get a const iterator to the beginning of the view/array.
auto as_array_view() const
Convert the current array to a view with an 'A' (array) algebra.
long extent(int i) const noexcept
Get the extent of the ith dimension.
basic_array(std::initializer_list< ValueType > const &l)
Construct a 1-dimensional array from an initializer list.
decltype(auto) operator[](T const &x) &&noexcept(has_no_boundcheck)
Rvalue overload of nda::basic_array_view::operator[](T const &) const &.
long is_contiguous() const noexcept
Is the memory layout of the view/array contiguous?
basic_array(std::initializer_list< std::initializer_list< ValueType > > const &l2)
Construct a 2-dimensional array from a double nested initializer list.
decltype(auto) operator()(_linear_index_t idx) noexcept
Non-const overload of nda::basic_array_view::operator()(_linear_index_t) const.
__inline__ decltype(auto) operator()(Ts const &...idxs) &noexcept(has_no_boundcheck)
Non-const overload of nda::basic_array_view::operator()(Ts const &...) const &.
bool empty() const
Is the view/array empty?
void resize(std::array< long, Rank > const &shape)
Resize the array to a new shape.
basic_array(Int sz, RHS const &val)
Construct a 1-dimensional array with the given size and initialize each element to the given scalar v...
static basic_array ones(std::array< Int, Rank > const &shape)
Make a one-initialized array with the given shape.
constexpr auto stride_order() const noexcept
Get the stride order of the memory layout of the view/array (see nda::idx_map for more details on how...
auto & operator/=(RHS const &rhs) noexcept
Division assignment operator.
auto as_array_view()
Convert the current array to a view with an 'A' (array) algebra.
basic_array(A const &a)
Construct an array from an nda::ArrayOfRank object with the same rank by copying each element.
static basic_array zeros(Ints... is)
Make a zero-initialized array with the given dimensions.
auto indices() const noexcept
Get a range that generates all valid index tuples.
static __inline__ decltype(auto) call(Self &&self, Ts const &...idxs) noexcept(has_no_boundcheck)
Implementation of the function call operator.
void resize(Ints const &...is)
Resize the array to a new shape.
storage_t storage() &&noexcept
Get the data storage of the view/array.
basic_array()
Default constructor constructs an empty array with a default constructed memory handle and layout.
bool is_empty() const noexcept
auto & operator=(R const &rhs) noexcept
Assignment operator makes a deep copy of a general contiguous range and assigns it to the 1-dimension...
storage_t const & storage() const &noexcept
Get the data storage of the view/array.
basic_array & operator=(basic_array const &)=default
Default copy assignment copies the memory handle and layout from the right hand side array.
basic_array & operator=(basic_array< ValueType, Rank, LayoutPolicy, A, CP > const &rhs)
Assignment operator makes a deep copy of another array with a different algebra and/or container poli...
basic_array(basic_array const &a)=default
Default copy constructor copies the memory handle and layout.
basic_array(std::initializer_list< std::initializer_list< std::initializer_list< ValueType > > > const &l3)
Construct a 3-dimensional array from a triple nested initializer list.
iterator begin() noexcept
Get an iterator to the beginning of the view/array.
basic_array(layout_t const &layout)
Construct an array with the given memory layout.
static basic_array rand(Ints... is)
Make a random-initialized array with the given dimensions.
basic_array(layout_t const &layout, storage_t &&storage) noexcept
Construct an array with the given memory layout and with an existing memory handle/storage.
static constexpr int iterator_rank
Rank of the nda::array_iterator for the view/array.
auto & operator-=(RHS const &rhs) noexcept
Subtraction assignment operator.
const_iterator end() const noexcept
Get a const iterator to the end of the view/array.
basic_array(basic_array &&)=default
Default move constructor moves the memory handle and layout.
__inline__ decltype(auto) operator()(Ts const &...idxs) &&noexcept(has_no_boundcheck)
Rvalue overload of nda::basic_array_view::operator()(Ts const &...) const &.
basic_array(std::array< Int, Rank > const &shape)
Construct an array with the given shape.
const_iterator cend() const noexcept
Get a const iterator to the end of the view/array.
auto const & shape() const noexcept
Get the shape of the view/array.
long size() const noexcept
Get the total size of the view/array.
decltype(auto) operator[](T const &x) &noexcept(has_no_boundcheck)
Non-const overload of nda::basic_array_view::operator[](T const &) const &.
auto & operator*=(RHS const &rhs) noexcept
Multiplication assignment operator.
basic_array & operator=(basic_array &&)=default
Default move assignment moves the memory handle and layout from the right hand side array.
static basic_array zeros(std::array< Int, Rank > const &shape)
Make a zero-initialized array with the given shape.
__inline__ decltype(auto) operator()(Ts const &...idxs) const &noexcept(has_no_boundcheck)
Function call operator to access the view/array.
constexpr auto const & indexmap() const noexcept
Get the memory layout of the view/array.
iterator end() noexcept
Get an iterator to the end of the view/array.
decltype(auto) operator()(_linear_index_t idx) const noexcept
Access the element of the view/array at the given nda::_linear_index_t.
static basic_array rand(std::array< Int, Rank > const &shape)
Make a random-initialized array with the given shape.
Layout that specifies how to map multi-dimensional indices to a linear/flat index.
Definition idx_map.hpp:103
__inline__ long operator()(Args const &...args) const noexcept(true)
Function call operator to map a given multi-dimensional index to a linear index.
Definition idx_map.hpp:512
static constexpr std::array< int, Rank > stride_order
Decoded stride order.
Definition idx_map.hpp:121
idx_map(idx_map< Rank, StaticExtents, StrideOrder, LP > const &idxm) noexcept
Construct a new map from an existing map with different layout properties.
Definition idx_map.hpp:327
static bool is_stride_order_valid(Int *lenptr, Int *strptr)
Check if a given shape and strides are compatible with the stride order.
Definition idx_map.hpp:244
static constexpr layout_info_t layout_info
Compile-time information about the layout (stride order and layout properties).
Definition idx_map.hpp:130
idx_map(idx_map &&)=default
Default move constructor.
long size() const noexcept
Get the total number of elements.
Definition idx_map.hpp:160
long min_stride() const noexcept
Get the value of the smallest stride.
Definition idx_map.hpp:190
idx_map(std::array< long, n_dynamic_extents > const &shape) noexcept
Construct a new map from an array with its dynamic extents.
Definition idx_map.hpp:404
auto transpose() const
Create a new map by permuting the indices/dimensions of the current map with a given permutation.
Definition idx_map.hpp:604
std::array< long, Rank > to_idx(long lin_idx) const
Calculate the multi-dimensional index from a given linear index.
Definition idx_map.hpp:543
bool is_stride_order_valid() const
Check if the shape and strides of the current map are compatible with its stride order.
Definition idx_map.hpp:259
idx_map(idx_map< Rank, SE, SO, LP > const &)
Construct a new map from an existing map with a different stride order.
Definition idx_map.hpp:418
bool operator==(idx_map< R, SE, SO, LP > const &rhs) const
Equal-to operator for two nda::idx_map objects.
Definition idx_map.hpp:585
static constexpr bool is_stride_order_C()
Is the stride order equal to C-order?
Definition idx_map.hpp:227
static constexpr int n_dynamic_extents
Number of dynamic dimensions/extents.
Definition idx_map.hpp:143
static constexpr uint64_t stride_order_encoded
Encoded stride order.
Definition idx_map.hpp:124
static constexpr int rank() noexcept
Get the rank of the map.
Definition idx_map.hpp:154
static constexpr std::array< int, Rank > static_extents
Decoded static extents.
Definition idx_map.hpp:118
bool is_strided_1d() const noexcept
Is the data strided in memory with a constant stride?
Definition idx_map.hpp:216
static constexpr int argument_is_allowed_for_call_or_slice
Alias template to check if type T can be used to either access a single element or a slice of element...
Definition idx_map.hpp:138
idx_map(std::array< Int, Rank > const &shape) noexcept
Construct a new map from a given shape and with contiguous strides.
Definition idx_map.hpp:390
std::array< long, Rank > const & lengths() const noexcept
Get the extents of all dimensions.
Definition idx_map.hpp:178
auto slice(Args const &...args) const
Get a new nda::idx_map by taking a slice of the current one.
Definition idx_map.hpp:570
static constexpr bool is_stride_order_Fortran()
Is the stride order equal to Fortran-order?
Definition idx_map.hpp:233
idx_map(idx_map const &)=default
Default copy constructor.
static constexpr int argument_is_allowed_for_call
Alias template to check if type T can be used to access a single element.
Definition idx_map.hpp:134
static constexpr long ce_size() noexcept
Get the size known at compile-time.
Definition idx_map.hpp:166
bool is_contiguous() const noexcept
Is the data contiguous in memory?
Definition idx_map.hpp:200
idx_map(idx_map< Rank, SE, StrideOrder, LP > const &idxm) noexcept(false)
Construct a new map from an existing map with different layout properties and different static extent...
Definition idx_map.hpp:350
idx_map(std::array< long, Rank > const &shape, std::array< long, Rank > const &strides) noexcept(!check_stride_order)
Construct a new map from a given shape and strides.
Definition idx_map.hpp:374
idx_map()
Default constructor.
Definition idx_map.hpp:310
std::array< long, Rank > const & strides() const noexcept
Get the strides of all dimensions.
Definition idx_map.hpp:184
idx_map & operator=(idx_map const &)=default
Default copy assignment operator.
static constexpr layout_prop_e layout_prop
Compile-time memory layout properties.
Definition idx_map.hpp:127
static constexpr uint64_t static_extents_encoded
Encoded static extents.
Definition idx_map.hpp:115
idx_map & operator=(idx_map &&)=default
Default move assignment operator.
idx_map(std::array< long, R > const &)
Construct a new map with a shape of a different rank.
Definition idx_map.hpp:430
Custom allocator that allocates a bucket of memory on the heap consisting of 64 chunks.
bucket(bucket &&)=default
Default move constructor.
bool empty() const noexcept
Check if the bucket is empty.
bucket()=default
Default constructor.
bool owns(blk_t b) const noexcept
Check if a given nda::mem::blk_t memory block is owned by the bucket.
void deallocate(blk_t b) noexcept
Deallocate a chunk of memory from the bucket by simply resetting the bitmask.
bool is_full() const noexcept
Check if the bucket is full.
auto mask() const noexcept
Get the bitmask of the bucket.
const char * data() const noexcept
Get a pointer to the start of the bucket.
static constexpr auto address_space
Only Host nda::mem::AddressSpace is supported for this allocator.
bucket(bucket const &)=delete
Deleted copy constructor.
bucket & operator=(bucket const &)=delete
Deleted copy assignment operator.
bucket & operator=(bucket &&)=default
Default move assignment operator.
blk_t allocate(size_t s) noexcept
Allocate a chunk of memory in the bucket and update the bitmask.
static constexpr int TotalChunkSize
Total size of the bucket in bytes.
blk_t allocate_zero(size_t s) noexcept
Allocate a chunk of memory in the bucket, set it to zero and update the bitmask.
Wrap an allocator to check for memory leaks.
bool empty() const
Check if the base allocator is empty.
long get_memory_used() const noexcept
Get the total memory used by the base allocator.
bool owns(blk_t b) const noexcept
Check if a given nda::mem::blk_t memory block is owned by the base allocator.
leak_check & operator=(leak_check &&)=default
Default move assignment operator.
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
leak_check(leak_check const &)=delete
Deleted copy constructor.
~leak_check()
Destructor that checks for memory leaks.
blk_t allocate_zero(size_t s)
Allocate memory, set it to zero and update the total memory used.
leak_check()=default
Default constructor.
blk_t allocate(size_t s)
Allocate memory and update the total memory used.
leak_check & operator=(leak_check const &)=delete
Deleted copy assignment operator.
void deallocate(blk_t b) noexcept
Deallocate memory and update the total memory used.
leak_check(leak_check &&)=default
Default move constructor.
Custom allocator that uses nda::mem::malloc to allocate memory.
mallocator & operator=(mallocator const &)=delete
Deleted copy assignment operator.
static void deallocate(blk_t b) noexcept
Deallocate memory using nda::mem::free.
mallocator & operator=(mallocator &&)=default
Default move assignment operator.
mallocator()=default
Default constructor.
mallocator(mallocator const &)=delete
Deleted copy constructor.
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.
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
mallocator(mallocator &&)=default
Default move constructor.
Custom allocator that uses multiple nda::mem::bucket allocators.
multi_bucket(multi_bucket &&)=default
Default move constructor.
bool owns(blk_t b) const noexcept
Check if a given nda::mem::blk_t memory block is owned by allocator.
blk_t allocate_zero(size_t s) noexcept
Allocate a chunk of memory in the current bucket or find a new one if the current one is full and set...
void deallocate(blk_t b) noexcept
Deallocate a chunk of memory from the bucket to which it belongs.
multi_bucket()
Default constructor.
bool empty() const noexcept
Check if the current allocator is empty.
static constexpr auto address_space
Only Host nda::mem::AddressSpace is supported for this allocator.
multi_bucket & operator=(multi_bucket &&)=default
Default move assignment operator.
auto const & buckets() const noexcept
Get the bucket vector.
blk_t allocate(size_t s) noexcept
Allocate a chunk of memory in the current bucket or find a new one if the current one is full.
multi_bucket(multi_bucket const &)=delete
Deleted copy constructor.
multi_bucket & operator=(multi_bucket const &)=delete
Deleted copy assignment operator.
Custom allocator that dispatches memory allocation to one of two allocators based on the size of the ...
blk_t allocate_zero(size_t s) noexcept
Allocate memory and set the memory to zero using the small allocator if the size is less than or equa...
segregator()=default
Default constructor.
segregator(segregator const &)=delete
Deleted copy constructor.
void deallocate(blk_t b) noexcept
Deallocate memory using the small allocator if the size is less than or equal to the Threshold,...
bool owns(blk_t b) const noexcept
Check if a given nda::mem::blk_t memory block is owned by the allocator.
segregator & operator=(segregator &&)=default
Default move assignment operator.
segregator(segregator &&)=default
Default move constructor.
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
segregator & operator=(segregator const &)=delete
Deleted copy assignment operator.
blk_t allocate(size_t s) noexcept
Allocate memory using the small allocator if the size is less than or equal to the Threshold,...
Wrap an allocator to gather statistics about memory allocation.
stats & operator=(stats &&)=default
Default move assignment operator.
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
blk_t allocate(uint64_t s)
Allocate memory and update the histogram.
auto const & histogram() const noexcept
Get the histogram of the allocation sizes.
void print_histogram(std::ostream &os) const
Print the histogram to a std::ostream.
blk_t allocate_zero(uint64_t s)
Allocate memory, set it to zero and update the histogram.
~stats()
Destructor that outputs the statistics about the memory allocation in debug mode.
stats & operator=(stats const &)=delete
Deleted copy assignment operator.
bool owns(blk_t b) const noexcept
Check if a given nda::mem::blk_t memory block is owned by the base allocator.
stats(stats const &)=delete
Deleted copy constructor.
void deallocate(blk_t b) noexcept
Deallocate memory.
stats(stats &&)=default
Default move constructor.
stats()=default
Default constructor.
#define CUSOLVER_CHECK(X, info,...)
#define NDA_RUNTIME_ERROR
auto rand(std::array< Int, Rank > const &shape)
Make an array of the given shape and initialize it with random values from the uniform distribution o...
decltype(auto) make_regular(A &&a)
Make a given object regular.
void resize_or_check_if_view(A &a, std::array< long, A::rank > const &sha)
Resize a given regular array to the given shape or check if a given view as the correct shape.
decltype(auto) to_unified(A &&a)
Convert an nda::MemoryArray to its regular type on unified memory.
auto make_const_view(basic_array< T, R, LP, A, CP > const &a)
Make an nda::basic_array_view with a const value type from a given nda::basic_array.
auto zeros(Ints... is)
Make an array of the given shape on the given address space and zero-initialize it.
auto zeros(std::array< Int, Rank > const &shape)
Make an array of the given shape on the given address space and zero-initialize it.
auto rand(Ints... is)
Make an array of the given dimensions and initialize it with random values from the uniform distribut...
auto arange(long first, long last, long step=1)
Make a 1-dimensional integer array and initialize it with values of a given nda::range.
decltype(auto) to_host(A &&a)
Convert an nda::MemoryArray to its regular type on host memory.
auto make_matrix_view(basic_array_view< T, R, LP, A, AP, OP > const &a)
Make an nda::matrix_view of a given nda::basic_array_view.
auto arange(long last)
Make a 1-dimensional integer array and initialize it with values of a given nda::range with a step si...
auto make_matrix_view(basic_array< T, R, LP, A, CP > const &a)
Make an nda::matrix_view of a given nda::basic_array.
auto ones(Ints... is)
Make an array with the given dimensions and one-initialize it.
auto make_const_view(basic_array_view< T, R, LP, A, AP, OP > const &a)
Make an nda::basic_array_view with a const value type from a given nda::basic_array_view.
decltype(auto) to_device(A &&a)
Convert an nda::MemoryArray to its regular type on device memory.
auto make_array_view(basic_array< T, R, LP, A, CP > const &a)
Make an nda::array_view of a given nda::basic_array.
auto make_array_const_view(basic_array< T, R, LP, A, CP > const &a)
Make an nda::array_const_view of a given nda::basic_array.
auto ones(std::array< Int, Rank > const &shape)
Make an array of the given shape and one-initialize it.
auto make_array_const_view(basic_array_view< T, R, LP, A, AP, OP > const &a)
Make an nda::array_const_view of a given nda::basic_array_view.
auto make_array_view(basic_array_view< T, R, LP, A, AP, OP > const &a)
Make an nda::array_view of a given nda::basic_array_view.
auto concatenate(A0 const &a0, As const &...as)
Join a sequence of nda::Array types along an existing axis.
long first_dim(A const &a)
Get the extent of the first dimension of the array.
constexpr bool is_view_v< basic_array_view< ValueType, Rank, Layout, Algebra, AccessorPolicy, OwningPolicy > >
Specialization of nda::is_view_v for nda::basic_array_view.
constexpr bool is_regular_v< basic_array< ValueType, Rank, Layout, Algebra, ContainerPolicy > >
Specialization of nda::is_regular_v for nda::basic_array.
constexpr char get_algebra< basic_array_view< ValueType, Rank, Layout, Algebra, AccessorPolicy, OwningPolicy > >
Specialization of nda::get_algebra for nda::basic_array_view types.
constexpr char get_algebra< basic_array< ValueType, Rank, Layout, Algebra, ContainerPolicy > >
Specialization of nda::get_algebra for nda::basic_array types.
constexpr uint64_t static_extents(int i0, Is... is)
Encode the given shape into a single integer using the nda::encode function.
constexpr char get_algebra< expr_unary< OP, A > >
Specialization of nda::get_algebra for nda::expr_unary types.
bool operator==(LHS const &lhs, RHS const &rhs)
Equal-to comparison operator for two nda::Array objects.
long second_dim(A const &a)
Get the extent of the second dimension of the array.
constexpr char get_algebra< expr< OP, L, R > >
Specialization of nda::get_algebra for nda::expr types.
__inline__ void clef_auto_assign(expr< tags::terminal, T > const &ex, RHS &&rhs)
Overload of clef_auto_assign function for terminal expressions.
__inline__ void clef_auto_assign(std::reference_wrapper< T > wrapper, RHS &&rhs)
Overload of clef_auto_assign function for std::reference_wrapper objects.
__inline__ void operator<<(expr< tags::function, F, placeholder< Is >... > const &ex, RHS &&rhs)
Assign values to the underlying object of a lazy function call expression.
__inline__ void clef_auto_assign_subscript(std::reference_wrapper< T > wrapper, RHS &&rhs)
Overload of clef_auto_assign_subscript function for std::reference_wrapper objects.
__inline__ void clef_auto_assign_subscript(expr< Tag, Childs... > const &ex, RHS const &rhs)
Overload of clef_auto_assign_subscript function for generic expressions.
__inline__ void clef_auto_assign_subscript(expr< tags::terminal, T > const &ex, RHS &&rhs)
Overload of clef_auto_assign_subscript function for terminal expressions.
__inline__ void clef_auto_assign(expr< Tag, Childs... > const &ex, RHS const &rhs)
Overload of clef_auto_assign function for generic expressions.
void clef_auto_assign(A &&a, F &&f)
Overload of nda::clef::clef_auto_assign function for nda::Array objects.
__inline__ void operator<<(expr< tags::subscript, T, placeholder< Is >... > const &ex, RHS &&rhs)
Assign values to the underlying object of a lazy subscript expression.
__inline__ decltype(auto) eval(T const &obj, Pairs &&...pairs)
Generic function to evaluate expressions and other types.
Definition eval.hpp:197
__inline__ auto make_function(T &&obj, Phs...)
Factory function for nda::clef::make_fun_impl objects.
Definition function.hpp:100
__inline__ auto if_else(C &&c, A &&a, B &&b)
Create a lazy ternary (if-else) expression.
#define CLEF_OPERATION(TAG, OP)
auto make_expr(T &&t)
Create a terminal expression node of an object.
Definition make_lazy.hpp:45
__inline__ auto op_dispatch(std::true_type, Args &&...args)
Dispatch operations containing at least one lazy operand.
__inline__ decltype(auto) op_dispatch(std::false_type, Args &&...args)
Dispatch operations containing only non-lazy operands.
auto make_expr_subscript(T &&t, Args &&...args)
Create a subscript expression from an object and a list of arguments.
Definition make_lazy.hpp:93
auto make_expr_call(F &&f, Args &&...args)
Create a function call expression from a callable object and a list of arguments.
Definition make_lazy.hpp:74
auto make_expr_from_clone(T &&t)
Create a terminal expression node of an object.
Definition make_lazy.hpp:57
constexpr bool is_clef_expression
Alias template for nda::clef::is_any_lazy.
Definition utils.hpp:161
constexpr bool is_lazy
Constexpr variable that is true if the type T is a lazy type.
Definition utils.hpp:153
constexpr bool force_copy_in_expr
Constexpr variable that is true if objects of type T should be forced to be copied into an expression...
Definition utils.hpp:137
constexpr bool is_function
Constexpr variable that is true if the type T is an nda::clef::make_fun_impl type.
Definition utils.hpp:165
constexpr bool is_any_lazy
Constexpr variable that is true if any of the given types is lazy.
Definition utils.hpp:157
constexpr uint64_t C_stride_order
C/Row-major stride order.
Definition idx_map.hpp:65
constexpr uint64_t Fortran_stride_order
Fortran/Column-major stride order.
Definition idx_map.hpp:57
__inline__ decltype(auto) slice_idx_map(idx_map< R, SE, SO, LP > const &idxm, Args const &...args)
Determine the resulting nda::idx_map when taking a slice of a given nda::idx_map.
constexpr bool layout_property_compatible(layout_prop_e from, layout_prop_e to)
Checks if two layout properties are compatible with each other.
Definition traits.hpp:237
constexpr bool has_contiguous(layout_prop_e lp)
Checks if a layout property has the contiguous property.
Definition traits.hpp:282
constexpr bool has_strided_1d(layout_prop_e lp)
Checks if a layout property has the strided_1d property.
Definition traits.hpp:266
auto get_block_layout(A const &a)
Check if a given nda::MemoryArray has a block-strided layout.
constexpr bool has_smallest_stride_is_one(layout_prop_e lp)
Checks if a layout property has the smallest_stride_is_one property.
Definition traits.hpp:274
layout_prop_e
Compile-time guarantees of the memory layout of an array/view.
Definition traits.hpp:222
AddressSpace
Enum providing identifiers for the different memory address spaces.
static constexpr bool have_host_compatible_addr_space
Constexpr variable that is true if all given types have an address space compatible with Host.
static constexpr bool have_compatible_addr_space
Constexpr variable that is true if all given types have compatible address spaces.
constexpr AddressSpace combine
Promotion rules for nda::mem::AddressSpace values.
static constexpr bool have_device_compatible_addr_space
Constexpr variable that is true if all given types have an address space compatible with Device.
static constexpr bool on_device
Constexpr variable that is true if all given types have a Device address space.
static constexpr bool on_unified
Constexpr variable that is true if all given types have a Unified address space.
static constexpr AddressSpace get_addr_space
Variable template providing the address space for different types.
static constexpr bool on_host
Constexpr variable that is true if all given types have a Host address space.
constexpr AddressSpace common_addr_space
Get common address space for a number of given nda::MemoryArray types.
static const auto check_adr_sp_valid
Check validity of a set of nda::mem::AddressSpace values.
static constexpr bool have_same_addr_space
Constexpr variable that is true if all given types have the same address space.
static constexpr bool have_cuda
Constexpr variable that is true if the project is configured with CUDA support.
Definition device.hpp:146
void memset2D(void *ptr, size_t pitch, int value, size_t width, size_t height)
Call CUDA's cudaMemset2D function or simulate its behavior on the Host based on the given address spa...
Definition memset.hpp:78
#define device_error_check(ARG1, ARG2)
Trigger a compilation error every time the nda::device_error_check function is called.
Definition device.hpp:140
static constexpr bool have_device
Constexpr variable that is true if the project is configured with GPU support.
Definition device.hpp:143
static constexpr bool init_dcmplx
Should we initialize memory for complex double types to zero.
Definition handle.hpp:45
void * malloc(size_t size)
Call the correct malloc function based on the given address space.
Definition malloc.hpp:49
static constexpr do_not_initialize_t do_not_initialize
Instance of nda::mem::do_not_initialize_t.
Definition handle.hpp:69
void memset(void *p, int value, size_t count)
Call the correct memset function based on the given address space.
Definition memset.hpp:49
void memcpy(void *dest, void const *src, size_t count)
Call the correct memcpy function based on the given address spaces.
Definition memcpy.hpp:51
static constexpr init_zero_t init_zero
Instance of nda::mem::init_zero_t.
Definition handle.hpp:75
void free(void *p)
Call the correct free function based on the given address space.
Definition malloc.hpp:75
constexpr std::array< int, N > transposition(int i, int j)
Get the permutation representing a single given transposition.
constexpr std::array< Int, N > inverse(std::array< Int, N > const &p)
Inverse of a permutation.
constexpr std::array< int, N > decode(uint64_t binary_representation)
Decode a uint64_t into a std::array<int, N>.
constexpr bool is_valid(std::array< Int, N > const &p)
Check if a given array is a valid permutation.
constexpr std::array< T, N > apply_inverse(std::array< Int, N > const &p, std::array< T, N > const &a)
Apply the inverse of a permutation to a std::array.
constexpr std::array< int, N > identity()
Get the identity permutation.
constexpr uint64_t encode(std::array< int, N > const &a)
Encode a std::array<int, N> in a uint64_t.
constexpr std::array< int, N > reverse_identity()
Get the reverse identity permutation.
constexpr std::array< int, N > cycle(int p, int pos=N)
Perform a forward (partial) cyclic permutation of the identity p times.
constexpr std::array< Int, N > compose(std::array< Int, N > const &p1, std::array< Int, N > const &p2)
Composition of two permutations.
constexpr std::array< T, N > apply(std::array< Int, N > const &p, std::array< T, N > const &a)
Apply a permutation to a std::array.
constexpr std::array< T, R > operator*(std::array< T, R > const &lhs, std::array< T, R > const &rhs)
Multiply two std::array objects element-wise.
Definition array.hpp:115
constexpr std::array< T, R - N > front_mpop(std::array< T, R > const &a)
Make a new std::array by popping the first N elements of an existing std::array.
Definition array.hpp:278
constexpr std::array< T, R+1 > append(std::array< T, R > const &a, U const &x)
Make a new std::array by appending one element at the end to an existing std::array.
Definition array.hpp:214
constexpr std::array< T, R+1 > front_append(std::array< T, R > const &a, U const &x)
Make a new std::array by prepending one element at the front to an existing std::array.
Definition array.hpp:232
constexpr std::array< T, R - 1 > pop(std::array< T, R > const &a)
Make a new std::array by popping the last element of an existing std::array.
Definition array.hpp:264
constexpr std::array< T, R > operator+(std::array< T, R > const &lhs, std::array< T, R > const &rhs)
Add two std::array objects element-wise.
Definition array.hpp:83
constexpr std::array< T, R > operator-(std::array< T, R > const &a)
Negate a std::array element-wise (unary minus).
Definition array.hpp:130
constexpr std::array< T, R1+R2 > join(std::array< T, R1 > const &a1, std::array< T, R2 > const &a2)
Make a new std::array by joining two existing std::array objects.
Definition array.hpp:309
constexpr std::array< T, R > operator*(T s, std::array< T, R > const &a)
Multiply a scalar and a std::array element-wise.
Definition array.hpp:146
constexpr std::vector< T > to_vector(std::array< T, R > const &a)
Convert a std::array to a std::vector.
Definition array.hpp:197
constexpr std::array< T, R > make_initialized_array(T v)
Create a new std::array object initialized with a specific value.
Definition array.hpp:165
constexpr auto sum(std::array< T, R > const &a)
Calculate the sum of all elements in a std::array.
Definition array.hpp:326
std::string to_string(std::array< T, R > const &a)
Get a string representation of a std::array.
Definition array.hpp:65
constexpr std::array< T, R > operator-(std::array< T, R > const &lhs, std::array< T, R > const &rhs)
Subtract two std::array objects element-wise.
Definition array.hpp:99
constexpr std::array< T, R > make_std_array(std::array< U, R > const &a)
Convert a std::array with value type U to a std::array with value type T.
Definition array.hpp:181
constexpr std::array< T, R - 1 > front_pop(std::array< T, R > const &a)
Make a new std::array by popping the first element of an existing std::array.
Definition array.hpp:293
constexpr auto product(std::array< T, R > const &a)
Calculate the product of all elements in a std::array.
Definition array.hpp:345
constexpr auto dot_product(std::array< T, R > const &a1, std::array< U, R > const &a2)
Calculate the dot product of two std::array objects.
Definition array.hpp:366
constexpr std::array< T, R - N > mpop(std::array< T, R > const &a)
Make a new std::array by popping the last N elements of an existing std::array.
Definition array.hpp:249
#define EXPECTS(X)
Definition macros.hpp:59
#define FORCEINLINE
Definition macros.hpp:41
#define EXPECTS_WITH_MESSAGE(X,...)
Definition macros.hpp:75
#define ENSURES(X)
Definition macros.hpp:69
#define AS_STRING(...)
Definition macros.hpp:31
#define ASSERT(X)
Definition macros.hpp:64
Contiguous layout policy with C-order (row-major order).
Definition policies.hpp:47
Strided (non-contiguous) layout policy with C-order (row-major order).
Definition policies.hpp:79
Contiguous layout policy with Fortran-order (column-major order).
Definition policies.hpp:63
Strided (non-contiguous) layout policy with Fortran-order (column-major order).
Definition policies.hpp:95
A small wrapper around a single long integer to be used as a linear index.
Definition traits.hpp:343
long value
Linear index.
Definition traits.hpp:345
Generic layout policy with arbitrary order.
Definition policies.hpp:115
Memory policy using an nda::mem::handle_borrowed.
Definition policies.hpp:108
static constexpr bool is_lazy
Constexpr variable that is true if any of the evaluators of the child nodes is lazy.
Definition eval.hpp:150
__inline__ decltype(auto) operator()(expr< Tag, Childs... > const &ex, Pairs &...pairs) const
Evaluate the given expression by applying the given nda::clef::pair objects.
Definition eval.hpp:170
__inline__ decltype(auto) operator()(make_fun_impl< T, Is... > const &f, Pairs &...pairs) const
Evaluate the nda::clef::make_fun_impl object.
Definition function.hpp:133
static constexpr bool is_lazy
Constexpr variable that is true if all the placeholders are assigned a value.
Definition function.hpp:120
static constexpr bool is_lazy
Constexpr variable that is true if the there is no nda::clef::pair containing an nda::clef::placehold...
Definition eval.hpp:92
__inline__ decltype(auto) operator()(placeholder< N >, pair< Is, Ts > &...pairs) const
Evaluate the placeholder.
Definition eval.hpp:101
static constexpr bool is_lazy
Constexpr variable that is always false.
Definition eval.hpp:126
__inline__ decltype(auto) operator()(std::reference_wrapper< T > const &wrapper, Pairs const &...pairs) const
Evaluate the std::reference_wrapper by redirecting the evaluation to the object contained in the wrap...
Definition eval.hpp:135
Generic evaluator for types which do not have a specialized evaluator.
Definition eval.hpp:55
__inline__ T const & operator()(T const &t, Pairs &...) const
Evaluate the object and ignore all given nda::clef::pair objects.
Definition eval.hpp:65
static constexpr bool is_lazy
Constexpr variable that is true if the type T is lazy.
Definition eval.hpp:57
Single node of the expression tree.
expr & operator=(expr const &)=delete
Copy assignment operator is deleted.
expr(expr &&ex) noexcept
Move constructor simply moves the child nodes from the source expression.
auto operator[](Args &&...args) const
Subscript operator.
expr & operator=(expr &&)=default
Default move assignment operator.
expr(expr const &)=default
Default copy constructor.
expr(Tag, Us &&...us)
Construct an expression node with a given tag and child nodes.
childs_t childs
Child nodes of the current expression node.
auto operator()(Args &&...args) const
Function call operator.
Helper struct to simplify calls to nda::clef::eval.
Definition function.hpp:52
T obj
Object to be evaluated.
Definition function.hpp:54
__inline__ decltype(auto) operator()(Args &&...args) const
Function call operator.
Definition function.hpp:68
__inline__ decltype(auto) operator()(F &&f, Args &&...args) const
Perform a function call operation.
Definition operation.hpp:95
__inline__ A operator()(C const &c, A const &a, B const &b) const
Perform a ternary (if-else) operation.
__inline__ decltype(auto) operator()(F &&f, Args &&...args) const
Perform a subscript operation.
__inline__ L operator()(L &&l) const
Perform a terminal operation.
Definition operation.hpp:77
A pair consisting of a placeholder and its assigned value.
T rhs
Value assigned to the placeholder (can be an lvalue reference).
static constexpr int p
Integer label of the placeholder.
A placeholder is an empty struct, labelled by an int.
static constexpr int index
Integer label.
auto operator[](T &&t) const
Subscript operator.
pair< N, RHS > operator=(RHS &&rhs) const
Assign a value to the placeholder.
auto operator()(Args &&...args) const
Function call operator.
Tag for binary operator expressions.
Tag for function call expressions.
Tag for conditional expressions.
Tag for subscript expressions.
Tag to indicate a terminal node in the expression tree.
Tag for unary operator expressions.
Accessor type of the nda::default_accessor.
Definition accessors.hpp:42
static __inline__ T * offset(pointer p, std::ptrdiff_t i) noexcept
Offset the pointer by a certain number of elements.
Definition accessors.hpp:71
static __inline__ reference access(pointer p, std::ptrdiff_t i) noexcept
Access a specific element of the data.
Definition accessors.hpp:59
Default accessor for various array and view types.
Definition accessors.hpp:36
Mimics Python's ... syntax.
Definition range.hpp:49
A lazy function call expression on arrays/views.
Definition map.hpp:90
Lazy unary expression for nda::Array types.
Lazy binary expression for nda::ArrayOrScalar types.
Memory policy using an nda::mem::handle_heap.
Definition policies.hpp:44
Stores information about the memory layout and the stride order of an array/view.
Definition traits.hpp:295
Wraps an arbitrary type to have a specified alignment.
Definition handle.hpp:54
T & get() noexcept
Get reference to the wrapped object.
Definition handle.hpp:59
T const & get() const noexcept
Get const reference to the wrapped object.
Definition handle.hpp:62
T x
Wrapped object of type T.
Definition handle.hpp:56
Memory block consisting of a pointer and its size.
char * ptr
Pointer to the memory block.
size_t s
Size of the memory block in bytes.
Tag used in constructors to indicate that the memory should not be initialized.
Definition handle.hpp:66
A non-owning handle for a memory block on the heap.
Definition handle.hpp:858
handle_borrowed(T *ptr) noexcept
Construct a borrowed handle from a pointer to the data.
Definition handle.hpp:892
handle_heap< T0 > const * parent() const
Get a pointer to the parent handle.
Definition handle.hpp:934
handle_borrowed(H const &h, long offset=0) noexcept
Construct a borrowed handle from a another handle.
Definition handle.hpp:904
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
Definition handle.hpp:874
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:914
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:928
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:922
handle_borrowed(handle_borrowed const &)=default
Default copy constructor.
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:940
A handle for a memory block on the heap.
Definition handle.hpp:99
long size() const noexcept
Get the size of the handle.
Definition handle.hpp:347
~handle_heap() noexcept
Destructor for the handle.
Definition handle.hpp:165
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:221
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:323
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:176
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:273
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:341
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:292
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:252
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:261
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:329
handle_heap(handle_heap const &h)
Copy constructor makes a deep copy of the data from another handle.
Definition handle.hpp:206
T & operator[](long i) noexcept
Subscript operator to access the data.
Definition handle.hpp:315
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
Definition handle.hpp:149
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:187
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:155
handle_heap(H const &h)
Construct a handle by making a deep copy of the data from another handle.
Definition handle.hpp:233
A handle for a memory block on the heap with shared ownership.
Definition handle.hpp:754
handle_shared(handle_heap< T, A > const &h) noexcept
Construct a shared handle from an nda::mem::handle_heap.
Definition handle.hpp:798
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:810
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
Definition handle.hpp:775
long refcount() const noexcept
Get the reference count of the shared object.
Definition handle.hpp:836
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:824
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:818
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:788
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:842
long size() const noexcept
Get the size of the handle.
Definition handle.hpp:848
A handle for a memory block on the heap or stack depending on the size of the data.
Definition handle.hpp:492
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated.
Definition handle.hpp:524
handle_sso()
Default constructor.
Definition handle.hpp:527
long size() const noexcept
Get the size of the handle.
Definition handle.hpp:744
~handle_sso() noexcept
Destructor for the handle.
Definition handle.hpp:535
T & operator[](long i) noexcept
Subscript operator to access the data.
Definition handle.hpp:707
bool is_null() const noexcept
Check if the handle is in a null state.
Definition handle.hpp:727
handle_sso & operator=(handle_sso const &h) noexcept
Copy assignment operator first cleans up the current handle and then makes a deep copy of the data fr...
Definition handle.hpp:598
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:563
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:680
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:583
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:738
bool on_heap() const
Check if the data is/should be stored on the heap.
Definition handle.hpp:721
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:636
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:656
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:542
handle_sso(H const &h)
Construct a handle by making a deep copy of the data from another owning handle.
Definition handle.hpp:620
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:715
A handle for a memory block on the stack.
Definition handle.hpp:359
static constexpr auto address_space
nda::mem::AddressSpace in which the memory is allocated (always on Host).
Definition handle.hpp:372
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:437
T & operator[](long i) noexcept
Subscript operator to access the data.
Definition handle.hpp:449
T * data() const noexcept
Get a pointer to the stored data.
Definition handle.hpp:469
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:416
~handle_stack() noexcept
Destructor for the handle.
Definition handle.hpp:378
handle_stack(handle_stack const &h) noexcept
Copy constructor simply calls the copy assignment operator.
Definition handle.hpp:410
handle_stack(long, do_not_initialize_t)
Construct a handle and do not initialize the data.
Definition handle.hpp:422
handle_stack(handle_stack &&h) noexcept
Move constructor simply calls the copy assignment operator.
Definition handle.hpp:393
handle_stack & operator=(handle_stack &&h) noexcept
Move assignment operator simply calls the copy assignment operator.
Definition handle.hpp:400
handle_stack(long, init_zero_t)
Construct a handle and initialize the data to zero (only for scalar and complex types).
Definition handle.hpp:425
static constexpr long size() noexcept
Get the size of the handle.
Definition handle.hpp:475
static constexpr bool is_null() noexcept
Check if the handle is in a null state.
Definition handle.hpp:463
T const & operator[](long i) const noexcept
Subscript operator to access the data.
Definition handle.hpp:457
Tag used in constructors to indicate that the memory should be initialized to zero.
Definition handle.hpp:72
Accessor type of the nda::no_alias_accessor.
Definition accessors.hpp:82
static __inline__ reference access(pointer p, std::ptrdiff_t i) noexcept
Access a specific element of the data.
Definition accessors.hpp:99
static __inline__ T * offset(pointer p, std::ptrdiff_t i) noexcept
Offset the pointer by a certain number of elements.
Accessor for array and view types with no aliasing.
Definition accessors.hpp:76
Memory policy using an nda::mem::handle_shared.
Definition policies.hpp:94
Memory policy using an nda::mem::handle_sso.
Definition policies.hpp:70
Memory policy using an nda::mem::handle_stack.
Definition policies.hpp:84