TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
basic_array_view.hpp
Go to the documentation of this file.
1// Copyright (c) 2019-2023 Simons Foundation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0.txt
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Authors: Miguel Morales, Olivier Parcollet, Nils Wentzell
16
17/**
18 * @file
19 * @brief Provides the generic class for views.
20 */
21
22#pragma once
23
24#include "./basic_functions.hpp"
25#include "./clef.hpp"
26#include "./concepts.hpp"
27#include "./declarations.hpp"
28#include "./exceptions.hpp"
29#include "./iterators.hpp"
30#include "./layout/for_each.hpp"
31#include "./layout/idx_map.hpp"
32#include "./layout/permutation.hpp"
33#include "./layout/range.hpp"
34#include "./macros.hpp"
35#include "./mem/address_space.hpp"
36#include "./mem/memcpy.hpp"
37#include "./mem/policies.hpp"
38#include "./traits.hpp"
39
40#include <itertools/itertools.hpp>
41
42#include <algorithm>
43#include <array>
44#include <cstring>
45#include <memory>
46#include <ranges>
47#include <type_traits>
48#include <utility>
49
50#ifdef NDA_ENFORCE_BOUNDCHECK
51#include <exception>
52#include <iostream>
53#endif // NDA_ENFORCE_BOUNDCHECK
54
55namespace std {
56
57 /**
58 * @brief std::swap is deleted for nda::basic_array_view.
59 * @warning The std::swap is WRONG for an nda::basic_array_view because of its copy/move semantics. Use nda::swap
60 * instead (the correct one, found by ADL).
61 */
62 template <typename V1, int R1, typename LP1, char A1, typename AP1, typename OP1, typename V2, int R2, typename LP2, char A2, typename AP2,
63 typename OP2>
64 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;
65
66} // namespace std
67
68namespace nda {
69
70 /**
71 * @ingroup arrays_views
72 * @brief A generic view of a multi-dimensional array.
73 *
74 * @details Together with nda::basic_array, this class forms the backbone of the nda library. It is templated with
75 * the following parameters:
76 *
77 * - `ValueType`: This is the type of the elements in the view. Depending on how the view was constructed and on the
78 * underlying array, this can be a const or non-const type.
79 * - `Rank`: Integer specifying the number of dimensions of the view. This is a compile-time constant.
80 * - `LayoutPolicy`: The layout policy specifies how the view accesses its elements. It provides a mapping from
81 * multi-dimensional to linear indices and vice versa (see @ref layout_pols).
82 * - `Algebra`: The algebra specifies how the view behaves when it is used in an expression. Possible values are 'A'
83 * (array), 'M' (matrix) and 'V' (vector) (see nda::get_algebra).
84 * - `AccessorPolicy`: The accessor policy specifies how the view accesses the data pointer. This can be useful for
85 * optimizations.
86 * - `OwningPolicy`: The owning policy specifies the ownership of the data pointer and who is responsible for
87 * handling the memory resources (see @ref mem_handles).
88 *
89 * In contrast to regular arrays (see nda::basic_array), views do not own the data they point to. They are a fast and
90 * efficient way to access and manipulate already existing data:
91 *
92 * @code{.cpp}
93 * // create a regular 3x3 array of ones
94 * auto arr = nda::ones<int>(3, 3);
95 * std::cout << arr << std::endl;
96 *
97 * // zero out the first column
98 * arr(nda::range::all, 0) = 0;
99 * std::cout << arr << std::endl;
100 * @endcode
101 *
102 * Output:
103 *
104 * @code{bash}
105 *
106 * [[1,1,1]
107 * [1,1,1]
108 * [1,1,1]]
109 *
110 * [[0,1,1]
111 * [0,1,1]
112 * [0,1,1]]
113 * @endcode
114 *
115 * Views are usually created by taking a slice of a regular nda::basic_array or another view. In the example above,
116 * `arr(nda::range::all, 0)` creates a view of the first column of the regular array `arr`, which is then set to zero.
117 * A view of the full array can be created with `arr()`.
118 *
119 * @tparam ValueType Type stored in the array.
120 * @tparam Rank Number of dimensions of the view.
121 * @tparam LayoutPolicy Policy determining the memory layout.
122 * @tparam Algebra Algebra of the view.
123 * @tparam AccessorPolicy Policy determining how the data pointer is accessed.
124 * @tparam OwningPolicy Policy determining the ownership of the data.
125 */
126 template <typename ValueType, int Rank, typename LayoutPolicy, char Algebra, typename AccessorPolicy, typename OwningPolicy>
128 // Compile-time checks.
129 static_assert((Algebra != 'N'), "Internal error in nda::basic_array_view: Algebra 'N' not supported");
130 static_assert((Algebra != 'M') or (Rank == 2), "Internal error in nda::basic_array_view: Algebra 'M' requires a rank 2 view");
131 static_assert((Algebra != 'V') or (Rank == 1), "Internal error in nda::basic_array_view: Algebra 'V' requires a rank 1 view");
132
133 public:
134 /// Type of the values in the view (might be const).
135 using value_type = ValueType;
136
137 /// Type of the memory layout policy (see @ref layout_pols).
138 using layout_policy_t = LayoutPolicy;
139
140 /// Type of the memory layout (an nda::idx_map).
141 using layout_t = typename LayoutPolicy::template mapping<Rank>;
142
143 /// Type of the accessor policy (see e.g. nda::default_accessor).
144 using accessor_policy_t = AccessorPolicy;
145
146 /// Type of the owning policy (see @ref mem_pols).
147 using owning_policy_t = OwningPolicy;
148
149 /// Type of the memory handle (see @ref mem_handles).
150 using storage_t = typename OwningPolicy::template handle<ValueType>;
151
152 /// The associated regular (nda::basic_array) type.
153 using regular_type = basic_array<std::remove_const_t<ValueType>, Rank, C_layout, Algebra, heap<mem::get_addr_space<storage_t>>>;
154
155 /// Number of dimensions of the view.
156 static constexpr int rank = Rank;
157
158 private:
159 // Type of the view itself.
160 using self_t = basic_array_view;
161
162 // Constexpr variable that is true if the view is a view (always for basic_array_view).
163 static constexpr bool is_view = true;
164
165 // Constexpr variable that is true if the value_type is const.
166 static constexpr bool is_const = std::is_const_v<ValueType>;
167
168 // Memory layout of the view, i.e. the nda::idx_map.
169 layout_t lay;
170
171 // Memory handle of the view.
172 storage_t sto;
173
174 // Declare any nda::basic_array as a friend.
175 template <typename T, int R, typename L, char A, typename CP>
176 friend class basic_array;
177
178 // Declare any other nda::basic_array_view as a friend.
179 template <typename T, int R, typename L, char A, typename AP, typename OP>
180 friend class basic_array_view;
181
182 // Check the layout compatibility of this view with another layout.
183 template <typename L>
184 static constexpr bool requires_runtime_check = not layout_property_compatible(L::template mapping<Rank>::layout_prop, layout_t::layout_prop);
185
186 public:
187 // FIXME : TRIQS PORTING
188 // private constructor for the previous friend
189 /**
190 * @brief Construct a view from a given layout and memory handle.
191 *
192 * @warning This should not be used directly. Use one of the other constructors instead.
193 *
194 * @param idxm Layout of the view.
195 * @param st Memory handle of the view.
196 */
197 basic_array_view(layout_t const &idxm, storage_t st) : lay(idxm), sto(std::move(st)) {}
198
199 public:
200 // backward : FIXME : temporary to be removed
201 /// @deprecated Convert the current view to a view with an 'A' (array) algebra.
202 [[deprecated]] auto as_array_view() { return basic_array_view<ValueType, Rank, LayoutPolicy, 'A', AccessorPolicy, OwningPolicy>{*this}; };
203
204 /// @deprecated Convert the current view to a view with an 'A' (array) algebra.
205 [[deprecated]] auto as_array_view() const {
206 return basic_array_view<const ValueType, Rank, LayoutPolicy, 'A', AccessorPolicy, OwningPolicy>{*this};
207 };
208
209 /// Default constructor constructs an empty view with a default constructed memory handle and layout.
210 basic_array_view() = default;
211
212 /// Default move constructor moves the memory handle and layout.
214
215 /// Default copy constructor copies the memory handle and layout.
217
218 /**
219 * @brief Generic constructor from any nda::MemoryArray type.
220 *
221 * @details It simply copies the memory layout and initializes the memory handle with the handle of the given
222 * nda::MemoryArray object.
223 *
224 * @tparam A nda::MemoryArray type of the same rank as the view.
225 * @param a nda::MemoryArray object.
226 */
227 template <MemoryArrayOfRank<Rank> A>
228 requires((get_layout_info<A>.stride_order == layout_t::stride_order_encoded)
229 and (std::is_same_v<std::remove_const_t<ValueType>, get_value_t<A>>)
230 and (std::is_const_v<ValueType> or !std::is_const_v<typename std::decay_t<A>::value_type>))
231 explicit(requires_runtime_check<typename std::decay_t<A>::layout_policy_t>)
232 basic_array_view(A &&a) noexcept // NOLINT (should we forward the reference?)
233 : lay(a.indexmap()), sto(a.storage()) {}
234
235 /**
236 * @brief Construct a view from a bare pointer to some contiguous data and a shape.
237 *
238 * @note We do not have any control over the specified dimensions. The caller has to ensure their correctness and
239 * their compatibility with the given data pointer.
240 *
241 * @param shape Shape of the view.
242 * @param p Pointer to the data.
243 */
244 basic_array_view(std::array<long, Rank> const &shape, ValueType *p) noexcept : basic_array_view(layout_t{shape}, p) {}
245
246 /**
247 * @brief Construct a view from a bare pointer to some contiguous data and a memory layout.
248 *
249 * @note We do not have any control over the given layout. The caller has to ensure its correctness and its
250 * compatibility with the given data pointer.
251 *
252 * @param idxm Layout of the view.
253 * @param p Pointer to the data.
254 */
255 basic_array_view(layout_t const &idxm, ValueType *p) noexcept : lay(idxm), sto{p} {}
256
257 /**
258 * @brief Construct a 1-dimensional view of a std::array.
259 *
260 * @tparam N Size of the std::array.
261 * @param a Reference to a std::array object.
262 */
263 template <size_t N>
264 requires(Rank == 1)
265 explicit basic_array_view(std::array<ValueType, N> &a) noexcept : basic_array_view{{long(N)}, a.data()} {}
266
267 /**
268 * @brief Construct a 1-dimensional view of a std::array.
269 *
270 * @tparam N Size of the std::array.
271 * @param a Const reference to a std::array object.
272 */
273 template <size_t N>
274 requires(Rank == 1 and std::is_const_v<ValueType>)
275 explicit basic_array_view(std::array<std::remove_const_t<ValueType>, N> const &a) noexcept : basic_array_view{{long(N)}, a.data()} {}
276
277 /**
278 * @brief Construct a 1-dimensional view of a general contiguous range.
279 *
280 * @tparam R Type of the range.
281 * @param rg Range object.
282 */
283 template <std::ranges::contiguous_range R>
284 requires(Rank == 1 and not MemoryArray<R>
285 and (std::is_same_v<std::ranges::range_value_t<R>, ValueType> or std::is_same_v<const std::ranges::range_value_t<R>, ValueType>))
286 explicit basic_array_view(R &rg) noexcept : basic_array_view{{long(std::ranges::size(rg))}, std::to_address(std::begin(rg))} {}
287
288 /**
289 * @brief Copy assignment operator makes a deep copy of the contents of the view.
290 *
291 * @details The dimension of the right hand side must be large enough or the behaviour is undefined. If
292 * `NDA_ENFORCE_BOUNDCHECK` is defined, bounds checking is enabled.
293 *
294 * @param rhs Right hand side of the assignment operation.
295 */
297 assign_from_ndarray(rhs);
298 return *this;
299 }
300
301 /**
302 * @brief Assignment operator makes a deep copy of the contents of an nda::ArrayOfRank object.
303 *
304 * @details The dimension of the right hand side must be large enough or the behaviour is undefined. If
305 * `NDA_ENFORCE_BOUNDCHECK` is defined, bounds checking is enabled.
306 *
307 * @tparam RHS nda::ArrayOfRank type with the same rank as the view.
308 * @param rhs Right hand side of the assignment operation.
309 */
310 template <ArrayOfRank<Rank> RHS>
311 basic_array_view &operator=(RHS const &rhs) noexcept {
312 static_assert(!is_const, "Cannot assign to an nda::basic_array_view with const value_type");
313 assign_from_ndarray(rhs);
314 return *this;
315 }
316
317 /**
318 * @brief Assignment operator assigns a scalar to the view.
319 *
320 * @details The behavior depends on the algebra of the view:
321 * - 'A' (array) and 'V' (vector): The scalar is assigned to all elements of the view.
322 * - 'M' (matrix): The scalar is assigned to the diagonal elements of the shorter dimension.
323 *
324 * @tparam RHS Type of the scalar.
325 * @param rhs Right hand side of the assignment operation.
326 */
327 template <typename RHS>
328 basic_array_view &operator=(RHS const &rhs) noexcept
329 requires(is_scalar_for_v<RHS, basic_array_view>)
330 {
331 static_assert(!is_const, "Cannot assign to an nda::basic_array_view with const value_type");
332 assign_from_scalar(rhs);
333 return *this;
334 }
335
336 /**
337 * @brief Assignment operator uses an nda::ArrayInitializer to assign to the view.
338 *
339 * @details The shape of the view is expected to be the same as the shape of the initializer.
340 *
341 * @tparam Initializer nda::ArrayInitializer type.
342 * @param initializer Initializer object.
343 */
344 template <ArrayInitializer<basic_array_view> Initializer>
345 basic_array_view &operator=(Initializer const &initializer) noexcept {
346 EXPECTS(shape() == initializer.shape());
347 initializer.invoke(*this);
348 return *this;
349 }
350
351 /**
352 * @brief Rebind the current view to another view.
353 *
354 * @details It simply copies the layout and memory handle of the other view.
355 *
356 * @tparam T Value type of the other view.
357 * @tparam R Rank of the other view.
358 * @tparam LP Layout policy of the other view.
359 * @tparam A Algebra of the other view.
360 * @tparam AP Accessor policy of the other view.
361 * @tparam OP Owning policy of the other view.
362 *
363 * @param v Other view.
364 */
365 template <typename T, int R, typename LP, char A, typename AP, typename OP>
366 void rebind(basic_array_view<T, R, LP, A, AP, OP> v) noexcept {
367 static_assert(R == Rank, "Cannot rebind a view to another view of a different rank");
368 static_assert(std::is_same_v<std::remove_const_t<T>, std::remove_const_t<ValueType>>,
369 "Cannot rebind a view to another view with a different value_type (except for const)");
370 static constexpr bool same_type = std::is_same_v<T, ValueType>;
371 static_assert(same_type or is_const, "Cannot rebind a view with non-const value_type to another view with const value_type");
372 if constexpr (same_type) {
373 // FIXME Error message in layout error !
374 lay = v.lay;
375 sto = v.sto;
376 } else if constexpr (is_const) {
377 // the last if is always trivially true but in case of an error in the static_assert above,
378 // it improves the error message by not compiling the = afterwards
379 lay = layout_t{v.indexmap()};
380 sto = storage_t{v.storage()};
381 }
382 }
383
384 /**
385 * @brief Swap two views by swapping their memory handles and layouts.
386 *
387 * @details This does not modify the data the views point to.
388 *
389 * @param a First view.
390 * @param b Second view.
391 */
392 friend void swap(basic_array_view &a, basic_array_view &b) noexcept {
393 std::swap(a.lay, b.lay);
394 std::swap(a.sto, b.sto);
395 }
396
397 /**
398 * @brief Swap two views by swapping their data.
399 *
400 * @details This modifies the data the views point to.
401 *
402 * @param a First view.
403 * @param b Second view.
404 */
405 friend void deep_swap(basic_array_view a, basic_array_view b) noexcept {
406 auto tmp = make_regular(a);
407 a = b;
408 b = tmp;
409 }
410
411// include common functionality of arrays and views
412// Copyright (c) 2019-2024 Simons Foundation
413//
414// Licensed under the Apache License, Version 2.0 (the "License");
415// you may not use this file except in compliance with the License.
416// You may obtain a copy of the License at
417//
418// http://www.apache.org/licenses/LICENSE-2.0.txt
419//
420// Unless required by applicable law or agreed to in writing, software
421// distributed under the License is distributed on an "AS IS" BASIS,
422// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
423// See the License for the specific language governing permissions and
424// limitations under the License.
425//
426// Authors: Thomas Hahn, Miguel Morales, Olivier Parcollet, Nils Wentzell
427
428/**
429 * @brief Get the memory layout of the view/array.
430 * @return nda::idx_map specifying the layout of the view/array.
431 */
432[[nodiscard]] constexpr auto const &indexmap() const noexcept { return lay; }
433
434/**
435 * @brief Get the data storage of the view/array.
436 * @return A const reference to the memory handle of the view/array.
437 */
438[[nodiscard]] storage_t const &storage() const & noexcept { return sto; }
439
440/**
441 * @brief Get the data storage of the view/array.
442 * @return A reference to the memory handle of the view/array.
443 */
444[[nodiscard]] storage_t &storage() & noexcept { return sto; }
445
446/**
447 * @brief Get the data storage of the view/array.
448 * @return A copy of the memory handle of the view/array.
449 */
450[[nodiscard]] storage_t storage() && noexcept { return std::move(sto); }
451
452/**
453 * @brief Get the stride order of the memory layout of the view/array (see nda::idx_map for more details on how we
454 * define stride orders).
455 *
456 * @return `std::array<int, Rank>` object specifying the stride order.
457 */
458[[nodiscard]] constexpr auto stride_order() const noexcept { return lay.stride_order; }
459
460/**
461 * @brief Get a pointer to the actual data (in general this is not the beginning of the memory block for a view).
462 * @return Const pointer to the first element of the view/array.
463 */
464[[nodiscard]] ValueType const *data() const noexcept { return sto.data(); }
465
466/**
467 * @brief Get a pointer to the actual data (in general this is not the beginning of thr memory block for a view).
468 * @return Pointer to the first element of the view/array.
469 */
470[[nodiscard]] ValueType *data() noexcept { return sto.data(); }
471
472/**
473 * @brief Get the shape of the view/array.
474 * @return `std::array<long, Rank>` object specifying the shape of the view/array.
475 */
476[[nodiscard]] auto const &shape() const noexcept { return lay.lengths(); }
477
478/**
479 * @brief Get the strides of the view/array (see nda::idx_map for more details on how we define strides).
480 * @return `std::array<long, Rank>` object specifying the strides of the view/array.
481 */
482[[nodiscard]] auto const &strides() const noexcept { return lay.strides(); }
483
484/**
485 * @brief Get the total size of the view/array.
486 * @return Number of elements contained in the view/array.
487 */
488[[nodiscard]] long size() const noexcept { return lay.size(); }
489
490/**
491 * @brief Is the memory layout of the view/array contiguous?
492 * @return True if the nda::idx_map is contiguous, false otherwise.
493 */
494[[nodiscard]] long is_contiguous() const noexcept { return lay.is_contiguous(); }
495
496/**
497 * @brief Is the view/array empty?
498 * @return True if the view/array does not contain any elements.
499 */
500[[nodiscard]] bool empty() const { return sto.is_null(); }
501
502/// @deprecated Use empty() instead.
503[[nodiscard]] bool is_empty() const noexcept { return sto.is_null(); }
504
505/**
506 * @brief Get the extent of the i<sup>th</sup> dimension.
507 * @return Number of elements along the i<sup>th</sup> dimension.
508 */
509[[nodiscard]] long extent(int i) const noexcept {
510#ifdef NDA_ENFORCE_BOUNDCHECK
511 if (i < 0 || i >= rank) {
512 std::cerr << "Error in extent: Dimension " << i << " is incompatible with array of rank " << rank << std::endl;
513 std::terminate();
514 }
515#endif
516 return lay.lengths()[i];
517}
518
519/// @deprecated Use `extent(i)` or `shape()[i]` instead.
520[[nodiscard]] long shape(int i) const noexcept { return extent(i); }
521
522/**
523 * @brief Get a range that generates all valid index tuples.
524 * @return An `itertools::multiplied` range that can be used to iterate over all valid index tuples.
525 */
526[[nodiscard]] auto indices() const noexcept { return itertools::product_range(shape()); }
527
528/**
529 * @brief Is the stride order of the view/array in C-order?
530 * @return True if the stride order of the nda::idx_map is C-order, false otherwise.
531 */
532static constexpr bool is_stride_order_C() noexcept { return layout_t::is_stride_order_C(); }
533
534/**
535 * @brief Is the stride order of the view/array in Fortran-order?
536 * @return True if the stride order of the nda::idx_map is Fortran-order, false otherwise.
537 */
538static constexpr bool is_stride_order_Fortran() noexcept { return layout_t::is_stride_order_Fortran(); }
539
540/**
541 * @brief Access the element of the view/array at the given nda::_linear_index_t.
542 *
543 * @details The linear index specifies the position of the element in the view/array and not the position of the
544 * element w.r.t. to the data pointer (i.e. any possible strides should not be taken into account).
545 *
546 * @param idx nda::_linear_index_t object.
547 * @return Const reference to the element at the given linear index.
548 */
549decltype(auto) operator()(_linear_index_t idx) const noexcept {
550 if constexpr (layout_t::layout_prop == layout_prop_e::strided_1d)
551 return sto[idx.value * lay.min_stride()];
552 else if constexpr (layout_t::layout_prop == layout_prop_e::contiguous)
553 return sto[idx.value];
554 else
555 static_assert(always_false<layout_t>, "Internal error in array/view: Calling this type with a _linear_index_t is not allowed");
556}
557
558/// Non-const overload of @ref nda::basic_array_view::operator()(_linear_index_t) const.
559decltype(auto) operator()(_linear_index_t idx) noexcept {
560 if constexpr (layout_t::layout_prop == layout_prop_e::strided_1d)
561 return sto[idx.value * lay.min_stride()];
562 else if constexpr (layout_t::layout_prop == layout_prop_e::contiguous)
563 return sto[idx.value];
564 else
565 static_assert(always_false<layout_t>, "Internal error in array/view: Calling this type with a _linear_index_t is not allowed");
566}
567
568private:
569// Constexpr variable that is true if bounds checking is disabled.
570#ifdef NDA_ENFORCE_BOUNDCHECK
571static constexpr bool has_no_boundcheck = false;
572#else
573static constexpr bool has_no_boundcheck = true;
574#endif
575
576public:
577/**
578 * @brief Implementation of the function call operator.
579 *
580 * @details This function is an implementation detail an should be private. Since the Green's function library in
581 * TRIQS uses this function, it is kept public (for now).
582 *
583 * @tparam ResultAlgebra Algebra of the resulting view/array.
584 * @tparam SelfIsRvalue True if the view/array is an rvalue.
585 * @tparam Self Type of the calling view/array.
586 * @tparam T Types of the arguments.
587 *
588 * @param self Calling view.
589 * @param idxs Multi-dimensional index consisting of `long`, `nda::range`, `nda::range::all_t`, nda::ellipsis or lazy
590 * arguments.
591 * @return Result of the function call depending on the given arguments and type of the view/array.
592 */
593template <char ResultAlgebra, bool SelfIsRvalue, typename Self, typename... Ts>
594FORCEINLINE static decltype(auto) call(Self &&self, Ts const &...idxs) noexcept(has_no_boundcheck) {
595 // resulting value type
596 using r_v_t = std::conditional_t<std::is_const_v<std::remove_reference_t<Self>>, ValueType const, ValueType>;
597
598 // behavior depends on the given arguments
599 if constexpr (clef::is_any_lazy<Ts...>) {
600 // if there are lazy arguments, e.g. as in A(i_) << i_, a lazy expression is returned
601 return clef::make_expr_call(std::forward<Self>(self), idxs...);
602 } else if constexpr (sizeof...(Ts) == 0) {
603 // if no arguments are given, a full view is returned
604 return basic_array_view<r_v_t, Rank, LayoutPolicy, Algebra, AccessorPolicy, OwningPolicy>{self.lay, self.sto};
605 } else {
606 // otherwise we check the arguments and either access a single element or make a slice
607 static_assert(((layout_t::template argument_is_allowed_for_call_or_slice<Ts> + ...) > 0),
608 "Error in array/view: Slice arguments must be convertible to range, ellipsis, or long (or string if the layout permits it)");
609
610 // number of arguments convertible to long
611 static constexpr int n_args_long = (layout_t::template argument_is_allowed_for_call<Ts> + ...);
612
613 if constexpr (n_args_long == rank) {
614 // access a single element
615 long offset = self.lay(idxs...);
616 if constexpr (is_view or not SelfIsRvalue) {
617 // if the calling object is a view or an lvalue, we return a reference
618 return AccessorPolicy::template accessor<ValueType>::access(self.sto.data(), offset);
619 } else {
620 // otherwise, we return a copy of the value
621 return ValueType{self.sto[offset]};
622 }
623 } else {
624 // access a slice of the view/array
625 auto const [offset, idxm] = self.lay.slice(idxs...);
626 static constexpr auto res_rank = decltype(idxm)::rank();
627 // resulting algebra
628 static constexpr char newAlgebra = (ResultAlgebra == 'M' and (res_rank == 1) ? 'V' : ResultAlgebra);
629 // resulting layout policy
630 using r_layout_p = typename detail::layout_to_policy<std::decay_t<decltype(idxm)>>::type;
631 return basic_array_view<ValueType, res_rank, r_layout_p, newAlgebra, AccessorPolicy, OwningPolicy>{std::move(idxm), {self.sto, offset}};
632 }
633 }
634}
635
636public:
637/**
638 * @brief Function call operator to access the view/array.
639 *
640 * @details Depending on the type of the calling object and the given arguments, this function call does the following:
641 * - If any of the arguments is lazy, an nda::clef::expr with the nda::clef::tags::function tag is returned.
642 * - If no arguments are given, a full view of the calling object is returned:
643 * - If the calling object itself or its value type is const, a view with a const value type is returned.
644 * - Otherwise, a view with a non-const value type is returned.
645 * - If the number of arguments is equal to the rank of the calling object and all arguments are convertible to `long`,
646 * a single element is accessed:
647 * - If the calling object is a view or an lvalue, a (const) reference to the element is returned.
648 * - Otherwise, a copy of the element is returned.
649 * - Otherwise a slice of the calling object is returned with the same value type and accessor and owning policies as
650 * the calling object. The algebra of the slice is the same as well, except if a 1-dimensional slice of a matrix is
651 * taken. In this case, the algebra is changed to 'V'.
652 *
653 * @tparam Ts Types of the function arguments.
654 * @param idxs Multi-dimensional index consisting of `long`, `nda::range`, `nda::range::all_t`, nda::ellipsis or lazy
655 * arguments.
656 * @return Result of the function call depending on the given arguments and type of the view/array.
657 */
658template <typename... Ts>
659FORCEINLINE decltype(auto) operator()(Ts const &...idxs) const & noexcept(has_no_boundcheck) {
660 static_assert((rank == -1) or (sizeof...(Ts) == rank) or (sizeof...(Ts) == 0) or (ellipsis_is_present<Ts...> and (sizeof...(Ts) <= rank + 1)),
661 "Error in array/view: Incorrect number of parameters in call operator");
662 return call<Algebra, false>(*this, idxs...);
663}
664
665/// Non-const overload of `nda::basic_array_view::operator()(Ts const &...) const &`.
666template <typename... Ts>
667FORCEINLINE decltype(auto) operator()(Ts const &...idxs) & noexcept(has_no_boundcheck) {
668 static_assert((rank == -1) or (sizeof...(Ts) == rank) or (sizeof...(Ts) == 0) or (ellipsis_is_present<Ts...> and (sizeof...(Ts) <= rank + 1)),
669 "Error in array/view: Incorrect number of parameters in call operator");
670 return call<Algebra, false>(*this, idxs...);
671}
672
673/// Rvalue overload of `nda::basic_array_view::operator()(Ts const &...) const &`.
674template <typename... Ts>
675FORCEINLINE decltype(auto) operator()(Ts const &...idxs) && noexcept(has_no_boundcheck) {
676 static_assert((rank == -1) or (sizeof...(Ts) == rank) or (sizeof...(Ts) == 0) or (ellipsis_is_present<Ts...> and (sizeof...(Ts) <= rank + 1)),
677 "Error in array/view: Incorrect number of parameters in call operator");
678 return call<Algebra, true>(*this, idxs...);
679}
680
681/**
682 * @brief Subscript operator to access the 1-dimensional view/array.
683 *
684 * @details Depending on the type of the calling object and the given argument, this subscript operation does the
685 * following:
686 * - If the argument is lazy, an nda::clef::expr with the nda::clef::tags::function tag is returned.
687 * - If the argument is convertible to `long`, a single element is accessed:
688 * - If the calling object is a view or an lvalue, a (const) reference to the element is returned.
689 * - Otherwise, a copy of the element is returned.
690 * - Otherwise a slice of the calling object is returned with the same value type, algebra and accessor and owning
691 * policies as the calling object.
692 *
693 * @tparam T Type of the argument.
694 * @param idx 1-dimensional index that is either a `long`, `nda::range`, `nda::range::all_t`, nda::ellipsis or a lazy
695 * argument.
696 * @return Result of the subscript operation depending on the given argument and type of the view/array.
697 */
698template <typename T>
699decltype(auto) operator[](T const &idx) const & noexcept(has_no_boundcheck) {
700 static_assert((rank == 1), "Error in array/view: Subscript operator is only available for rank 1 views/arrays in C++17/20");
701 return call<Algebra, false>(*this, idx);
702}
703
704/// Non-const overload of `nda::basic_array_view::operator[](T const &) const &`.
705template <typename T>
706decltype(auto) operator[](T const &x) & noexcept(has_no_boundcheck) {
707 static_assert((rank == 1), "Error in array/view: Subscript operator is only available for rank 1 views/arrays in C++17/20");
708 return call<Algebra, false>(*this, x);
709}
710
711/// Rvalue overload of `nda::basic_array_view::operator[](T const &) const &`.
712template <typename T>
713decltype(auto) operator[](T const &x) && noexcept(has_no_boundcheck) {
714 static_assert((rank == 1), "Error in array/view: Subscript operator is only available for rank 1 views/arrays in C++17/20");
715 return call<Algebra, true>(*this, x);
716}
717
718/// Rank of the nda::array_iterator for the view/array.
719static constexpr int iterator_rank = (has_strided_1d(layout_t::layout_prop) ? 1 : Rank);
720
721/// Const iterator type of the view/array.
722using const_iterator = array_iterator<iterator_rank, ValueType const, typename AccessorPolicy::template accessor<ValueType>::pointer>;
723
724/// Iterator type of the view/array.
725using iterator = array_iterator<iterator_rank, ValueType, typename AccessorPolicy::template accessor<ValueType>::pointer>;
726
727private:
728// Make an iterator for the view/array depending on its type.
729template <typename Iterator>
730[[nodiscard]] auto make_iterator(bool at_end) const noexcept {
731 if constexpr (iterator_rank == Rank) {
732 // multi-dimensional iterator
733 if constexpr (layout_t::is_stride_order_C()) {
734 // C-order case (array_iterator already traverses the data in C-order)
735 return Iterator{indexmap().lengths(), indexmap().strides(), sto.data(), at_end};
736 } else {
737 // general case (we need to permute the shape and the strides according to the stride order of the layout)
738 return Iterator{nda::permutations::apply(layout_t::stride_order, indexmap().lengths()),
739 nda::permutations::apply(layout_t::stride_order, indexmap().strides()), sto.data(), at_end};
740 }
741 } else {
742 // 1-dimensional iterator
743 return Iterator{std::array<long, 1>{size()}, std::array<long, 1>{indexmap().min_stride()}, sto.data(), at_end};
744 }
745}
746
747public:
748/// Get a const iterator to the beginning of the view/array.
749[[nodiscard]] const_iterator begin() const noexcept { return make_iterator<const_iterator>(false); }
750
751/// Get a const iterator to the beginning of the view/array.
752[[nodiscard]] const_iterator cbegin() const noexcept { return make_iterator<const_iterator>(false); }
753
754/// Get an iterator to the beginning of the view/array.
755iterator begin() noexcept { return make_iterator<iterator>(false); }
756
757/// Get a const iterator to the end of the view/array.
758[[nodiscard]] const_iterator end() const noexcept { return make_iterator<const_iterator>(true); }
759
760/// Get a const iterator to the end of the view/array.
761[[nodiscard]] const_iterator cend() const noexcept { return make_iterator<const_iterator>(true); }
762
763/// Get an iterator to the end of the view/array.
764iterator end() noexcept { return make_iterator<iterator>(true); }
765
766/**
767 * @brief Addition assignment operator.
768 *
769 * @details It first performs the (lazy) addition with the right hand side operand and then assigns the result to the
770 * left hand side view/array.
771 *
772 * See nda::operator+(L &&, R &&) and nda::operator+(A &&, S &&) for more details.
773 *
774 * @tparam RHS nda::Scalar or nda::Array type.
775 * @param rhs Right hand side operand of the addition assignment operation.
776 * @return Reference to this object.
777 */
778template <typename RHS>
779auto &operator+=(RHS const &rhs) noexcept {
780 static_assert(not is_const, "Error in array/view: Can not assign to a const view");
781 return operator=(*this + rhs);
782}
783
784/**
785 * @brief Subtraction assignment operator.
786 *
787 * @details It first performs the (lazy) subtraction with the right hand side operand and then assigns the result to
788 * the left hand side view/array.
789 *
790 * See nda::operator-(L &&, R &&) and nda::operator-(A &&, S &&) for more details.
791 *
792 * @tparam RHS nda::Scalar or nda::Array type.
793 * @param rhs Right hand side operand of the subtraction assignment operation.
794 * @return Reference to this object.
795 */
796template <typename RHS>
797auto &operator-=(RHS const &rhs) noexcept {
798 static_assert(not is_const, "Error in array/view: Can not assign to a const view");
799 return operator=(*this - rhs);
800}
801
802/**
803 * @brief Multiplication assignment operator.
804 *
805 * @details It first performs the (lazy) multiplication with the right hand side operand and then assigns the result
806 * to the left hand side view/array.
807 *
808 * See nda::operator*(L &&, R &&) and nda::operator*(A &&, S &&) for more details.
809 *
810 * @tparam RHS nda::Scalar or nda::Array type.
811 * @param rhs Right hand side operand of the multiplication assignment operation.
812 * @return Reference to this object.
813 */
814template <typename RHS>
815auto &operator*=(RHS const &rhs) noexcept {
816 static_assert(not is_const, "Error in array/view: Can not assign to a const view");
817 return operator=((*this) * rhs);
818}
819
820/**
821 * @brief Division assignment operator.
822 *
823 * @details It first performs the (lazy) division with the right hand side operand and then assigns the result to the
824 * left hand side view/array.
825 *
826 * See nda::operator/(L &&, R &&) and nda::operator/(A &&, S &&) for more details.
827 *
828 * @tparam RHS nda::Scalar or nda::Array type.
829 * @param rhs Right hand side operand of the division assignment operation.
830 * @return Reference to this object.
831 */
832template <typename RHS>
833auto &operator/=(RHS const &rhs) noexcept {
834 static_assert(not is_const, "Error in array/view: Can not assign to a const view");
835 return operator=(*this / rhs);
836}
837
838/**
839 * @brief Assignment operator makes a deep copy of a general contiguous range and assigns it to the 1-dimensional
840 * view/array.
841 *
842 * @tparam R Range type.
843 * @param rhs Right hand side range object.
844 * @return Reference to this object.
845 */
846template <std::ranges::contiguous_range R>
847auto &operator=(R const &rhs) noexcept
848 requires(Rank == 1 and not MemoryArray<R>)
849{
850 *this = basic_array_view{rhs};
851 return *this;
852}
853
854private:
855// Implementation of the assignment from an n-dimensional array type.
856template <typename RHS>
857void assign_from_ndarray(RHS const &rhs) { // FIXME noexcept {
858#ifdef NDA_ENFORCE_BOUNDCHECK
859 if (this->shape() != rhs.shape())
860 NDA_RUNTIME_ERROR << "Error in assign_from_ndarray: Size mismatch:"
861 << "\n LHS.shape() = " << this->shape() << "\n RHS.shape() = " << rhs.shape();
862#endif
863 // compile-time check if assignment is possible
864 static_assert(std::is_assignable_v<value_type &, get_value_t<RHS>>, "Error in assign_from_ndarray: Incompatible value types");
865
866 // are both operands nda::MemoryArray types?
867 static constexpr bool both_in_memory = MemoryArray<self_t> and MemoryArray<RHS>;
868
869 // do both operands have the same stride order?
870 static constexpr bool same_stride_order = get_layout_info<self_t>.stride_order == get_layout_info<RHS>.stride_order;
871
872 // prefer optimized options if possible
873 if constexpr (both_in_memory and same_stride_order) {
874 if (rhs.empty()) return;
875 // are both operands strided in 1d?
876 static constexpr bool both_1d_strided = has_layout_strided_1d<self_t> and has_layout_strided_1d<RHS>;
877 if constexpr (mem::on_host<self_t, RHS> and both_1d_strided) {
878 // vectorizable copy on host
879 for (long i = 0; i < size(); ++i) (*this)(_linear_index_t{i}) = rhs(_linear_index_t{i});
880 return;
881 } else if constexpr (!mem::on_host<self_t, RHS> and have_same_value_type_v<self_t, RHS>) {
882 // check for block-layout and use mem::memcpy2D if possible
883 auto bl_layout_dst = get_block_layout(*this);
884 auto bl_layout_src = get_block_layout(rhs);
885 if (bl_layout_dst && bl_layout_src) {
886 auto [n_bl_dst, bl_size_dst, bl_str_dst] = *bl_layout_dst;
887 auto [n_bl_src, bl_size_src, bl_str_src] = *bl_layout_src;
888 // check that the total memory size is the same
889 if (n_bl_dst * bl_size_dst != n_bl_src * bl_size_src) NDA_RUNTIME_ERROR << "Error in assign_from_ndarray: Incompatible block sizes";
890 // if either destination or source consists of a single block, we can chunk it up to make the layouts compatible
891 if (n_bl_dst == 1 && n_bl_src > 1) {
892 n_bl_dst = n_bl_src;
893 bl_size_dst /= n_bl_src;
894 bl_str_dst = bl_size_dst;
895 }
896 if (n_bl_src == 1 && n_bl_dst > 1) {
897 n_bl_src = n_bl_dst;
898 bl_size_src /= n_bl_dst;
899 bl_str_src = bl_size_src;
900 }
901 // copy only if block-layouts are compatible, otherwise continue to fallback
902 if (n_bl_dst == n_bl_src && bl_size_dst == bl_size_src) {
903 mem::memcpy2D<mem::get_addr_space<self_t>, mem::get_addr_space<RHS>>((void *)data(), bl_str_dst * sizeof(value_type), (void *)rhs.data(),
904 bl_str_src * sizeof(value_type), bl_size_src * sizeof(value_type),
905 n_bl_src);
906 return;
907 }
908 }
909 }
910 }
911 // otherwise fallback to elementwise assignment
912 if constexpr (mem::on_device<self_t> || mem::on_device<RHS>) {
913 NDA_RUNTIME_ERROR << "Error in assign_from_ndarray: Fallback to elementwise assignment not implemented for arrays/views on the GPU";
914 }
915 nda::for_each(shape(), [this, &rhs](auto const &...args) { (*this)(args...) = rhs(args...); });
916}
917
918// Implementation to fill a view/array with a constant scalar value.
919template <typename Scalar>
920void fill_with_scalar(Scalar const &scalar) noexcept {
921 // we make a special implementation if the array is strided in 1d or contiguous
922 if constexpr (has_layout_strided_1d<self_t>) {
923 const long L = size();
924 auto *__restrict const p = data(); // no alias possible here!
925 if constexpr (has_contiguous_layout<self_t>) {
926 for (long i = 0; i < L; ++i) p[i] = scalar;
927 } else {
928 const long stri = indexmap().min_stride();
929 const long Lstri = L * stri;
930 for (long i = 0; i < Lstri; i += stri) p[i] = scalar;
931 }
932 } else {
933 // no compile-time memory layout guarantees
934 for (auto &x : *this) x = scalar;
935 }
936}
937
938// Implementation of the assignment from a scalar value.
939template <typename Scalar>
940void assign_from_scalar(Scalar const &scalar) noexcept {
941 static_assert(!is_const, "Error in assign_from_ndarray: Cannot assign to a const view");
942 if constexpr (Algebra != 'M') {
943 // element-wise assignment for non-matrix algebras
944 fill_with_scalar(scalar);
945 } else {
946 // a scalar has to be interpreted as a unit matrix for matrix algebras (the scalar in the shortest diagonal)
947 // FIXME : A priori faster to put 0 everywhere and then change the diag to avoid the if.
948 // FIXME : Benchmark and confirm.
949 if constexpr (is_scalar_or_convertible_v<Scalar>)
950 fill_with_scalar(0);
951 else
952 fill_with_scalar(Scalar{0 * scalar}); // FIXME : improve this
953 const long imax = std::min(extent(0), extent(1));
954 for (long i = 0; i < imax; ++i) operator()(i, i) = scalar;
955 }
956}
957 };
958
959 // Class template argument deduction guides.
960 template <MemoryArray A>
961 basic_array_view(A &&a)
962 -> basic_array_view<std::conditional_t<std::is_const_v<std::remove_reference_t<A>>, const typename std::decay_t<A>::value_type,
963 typename std::decay_t<A>::value_type>,
964 get_rank<A>, typename std::decay_t<A>::layout_policy_t, get_algebra<A>, default_accessor, borrowed<mem::get_addr_space<A>>>;
965
966 template <typename V, size_t R>
967 basic_array_view(std::array<V, R> &a)
968 -> basic_array_view<V, 1, nda::basic_layout<nda::static_extents(R), nda::C_stride_order<1>, nda::layout_prop_e::contiguous>, 'V',
970
971 template <typename V, size_t R>
972 basic_array_view(std::array<V, R> const &a)
973 -> basic_array_view<const V, 1, nda::basic_layout<nda::static_extents(R), nda::C_stride_order<1>, nda::layout_prop_e::contiguous>, 'V',
975
976 template <std::ranges::contiguous_range R>
977 basic_array_view(R &r) -> basic_array_view<std::conditional_t<std::is_const_v<R>, const typename R::value_type, typename R::value_type>, 1,
979
980} // namespace nda
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.
#define CUSOLVER_CHECK(X, info,...)
#define NDA_RUNTIME_ERROR
constexpr uint64_t static_extents(int i0, Is... is)
Encode the given shape into a single integer using the nda::encode function.
layout_prop_e
Compile-time guarantees of the memory layout of an array/view.
Definition traits.hpp:222
static constexpr do_not_initialize_t do_not_initialize
Instance of nda::mem::do_not_initialize_t.
Definition handle.hpp:69
static constexpr init_zero_t init_zero
Instance of nda::mem::init_zero_t.
Definition handle.hpp:75
constexpr uint64_t encode(std::array< int, N > const &a)
Encode a std::array<int, N> in a uint64_t.
#define EXPECTS(X)
Definition macros.hpp:59
#define FORCEINLINE
Definition macros.hpp:41
#define EXPECTS_WITH_MESSAGE(X,...)
Definition macros.hpp:75
#define AS_STRING(...)
Definition macros.hpp:31
Contiguous layout policy with C-order (row-major order).
Definition policies.hpp:47
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
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
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