alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
Vec.hpp
Go to the documentation of this file.
1/* Copyright 2024 René Widera
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5#pragma once
6
7#include "alpaka/cast.hpp"
10#include "alpaka/trait.hpp"
11#include "unused.hpp"
12
13#include <array>
14#include <concepts>
15#include <cstdint>
16#include <iosfwd>
17#include <ranges>
18#include <sstream>
19#include <string>
20#include <type_traits>
21#include <utility>
22
23namespace alpaka
24{
25 namespace trait
26 {
27 template<typename T>
28 struct IsVector : std::false_type
29 {
30 };
31
32 template<typename T>
33 struct IsCVector : std::false_type
34 {
35 };
36 } // namespace trait
37
38 template<typename T>
40
41 template<typename T>
43
44 namespace concepts
45 {
46
47 /** Concept to check if a type is a vector
48 *
49 * @tparam T Type to check
50 * @tparam T_ValueType enforce a value type of the vector, if not provided the value type is not checked
51 * @tparam T_dim enforce a dimensionality of the vector, if not provided the value is not checked
52 */
53 template<typename T, typename T_ValueType = alpaka::NotRequired, uint32_t T_dim = alpaka::notRequiredDim>
55 && (std::same_as<T_ValueType, trait::GetValueType_t<std::decay_t<T>>>
56 || std::same_as<T_ValueType, alpaka::NotRequired>)
57 && ((T_dim == alpaka::notRequiredDim) || (T::dim() == T_dim));
58
59 /** Concept to check if a type is a vector or scalar variable
60 *
61 * @tparam T Type to check
62 * @tparam T_ValueType enforce a value type of T, if not provided the value type is not checked
63 */
64 template<typename T, typename T_ValueType = alpaka::NotRequired>
65 concept VectorOrScalar = (isVector_v<T> || std::integral<T> || std::floating_point<T>)
66 && (std::same_as<T_ValueType, trait::GetValueType_t<std::decay_t<T>>>
67 || std::same_as<T_ValueType, alpaka::NotRequired>);
68
69 /** Concept to check if a type is a CVector
70 *
71 * @details
72 * Checks whether the given type is a CVector. For more information, refer to the implementation alpaka::CVec.
73 */
74 template<typename T, typename T_ValueType = alpaka::NotRequired>
76 && (std::same_as<T_ValueType, trait::GetValueType_t<std::decay_t<T>>>
77 || std::same_as<T_ValueType, alpaka::NotRequired>);
78
79 /** Concept to check if a type is a vector or a specific other type
80 *
81 * @tparam T Type to check
82 * @tparam T_RequiredComponent enforce that T is a vector or a specific other type
83 */
84 template<typename T, typename T_RequiredComponent>
85 concept TypeOrVector = (isVector_v<T> || std::is_same_v<T, T_RequiredComponent>);
86
87 template<typename T, typename T_RequiredComponent>
88 concept VectorOrConvertibleType = (isVector_v<T> || std::is_convertible_v<T, T_RequiredComponent>);
89 } // namespace concepts
90
91 /** Array storge for vector data
92 *
93 * This class is a workaround and is simply wrapping std::array. It is required because the dim in std::array
94 * in the template signature is size_t. This produces template deduction issues for math::Vec if we sue
95 * array as default storage without this wrapper.
96 */
97 template<typename T_Type, uint32_t T_dim>
98 struct ArrayStorage : protected std::array<T_Type, T_dim>
99 {
100 using type = T_Type;
101 using BaseType = std::array<T_Type, T_dim>;
102 using BaseType::operator[];
103
104 // constructor is required because exposing the array constructors does not work
105 template<typename... T_Args>
106 constexpr ArrayStorage(T_Args&&... args) : BaseType{std::forward<T_Args>(args)...}
107 {
108 }
109
110 constexpr ArrayStorage(std::array<T_Type, T_dim> const& data) : BaseType{data}
111 {
112 }
113 };
114
115 namespace detail
116 {
117 template<typename T, T... T_values>
118 struct CVec
119 {
120 using type = T;
121
122 static consteval uint32_t dim()
123 {
124 return sizeof...(T_values);
125 }
126
127 constexpr T operator[](std::integral auto const idx) const
128 {
129 // default initializes with first value
130 T result = std::get<0>(std::forward_as_tuple(T_values...));
131
132 if constexpr(dim() > 1u)
133 {
134 [[maybe_unused]] bool _ = std::apply(
135 [idx, &result](auto&&, auto&&... values) constexpr
136 {
137 using IdxType = ALPAKA_TYPEOF(idx);
138 IdxType i{1u};
139 return ((idx == i++ && (result = values, true)) || ...);
140 },
141 std::forward_as_tuple(T_values...));
142 }
143 return result;
144 }
145
146 template<T T_value>
147 static constexpr auto fill()
148 {
149 using IotaSeq = std::make_integer_sequence<T, dim()>;
150 return integerSequenceToCVec(IotaSeq{}, [](auto&&) constexpr { return T_value; });
151 }
152
153 private:
154 template<T... T_indices>
155 static constexpr auto integerSequenceToCVec(
156 std::integer_sequence<T, T_indices...>,
157 auto const op = std::identity{})
158 {
159 return CVec<T, op(T_indices)...>{};
160 }
161 };
162
163 template<typename T>
164 struct TemplateSignatureStorage : std::false_type
165 {
166 };
167
168 template<typename T_Type, T_Type... T_values>
169 struct TemplateSignatureStorage<CVec<T_Type, T_values...>> : std::true_type
170 {
171 };
172
173 template<typename T>
175 } // namespace detail
176
177 template<typename T_Type, uint32_t T_dim, typename T_Storage = alpaka::ArrayStorage<T_Type, T_dim>>
178 struct Vec : private T_Storage
179 {
180 using Storage = T_Storage;
181 using type = T_Type;
183
184 using index_type = uint32_t;
185 using size_type = uint32_t;
186 using rank_type = uint32_t;
187
188 // universal vec used as fallback if T_Storage is holding the state in the template signature
190
191 /*Vecs without elements are not allowed*/
192 static_assert(T_dim > 0u);
193
194 constexpr Vec() = default;
195
196 /** Initialize via a generator expression
197 *
198 * The generator must return the value for the corresponding index of the component which is passed to the
199 * generator.
200 */
201 template<
202 typename F,
203 std::enable_if_t<std::is_invocable_v<F, std::integral_constant<uint32_t, 0u>>, uint32_t> = 0u>
204 constexpr explicit Vec(F&& generator)
205 : Vec(std::forward<F>(generator), std::make_integer_sequence<uint32_t, T_dim>{})
206 {
207 }
208
209 private:
210 template<typename F, uint32_t... Is>
211 constexpr explicit Vec(F&& generator, std::integer_sequence<uint32_t, Is...>)
212 : Storage{generator(std::integral_constant<uint32_t, Is>{})...}
213 {
214 }
215
216 public:
217 /** Constructor for N-dimensional vector
218 *
219 * @attention This constructor allows implicit casts.
220 *
221 * @param args value of each dimension, x,y,z,...
222 *
223 * A constexpr vector should be initialized with {} instead of () because at least
224 * CUDA 11.6 has problems in cases where a compile time evaluation is required.
225 * @code{.cpp}
226 * constexpr auto vec1 = Vec{ 1 };
227 * constexpr auto vec2 = Vec{ 1, 2 };
228 * //or explicit
229 * constexpr auto vec3 = Vec<int, 3u>{ 1, 2, 3 };
230 * constexpr auto vec4 = Vec<int, 3u>{ {1, 2, 3} };
231 * @endcode
232 */
233 template<typename... T_Args>
234 requires(std::is_convertible_v<T_Args, T_Type> && ...)
235 constexpr Vec(T_Args const&... args) : Storage(static_cast<T_Type>(args)...)
236 {
237 }
238
239 constexpr Vec(Vec const& other) = default;
240
241 constexpr Vec(T_Storage const& other) : T_Storage{other}
242 {
243 }
244
245 /** constructor allows changing the storage policy
246 */
247 template<typename T_OtherStorage>
249 : Vec([&](uint32_t const i) constexpr { return other[i]; })
250 {
251 }
252
253 /** Allow static_cast / explicit cast to member type for 1D vector */
254 template<uint32_t T_deferDim = T_dim, typename = typename std::enable_if<T_deferDim == 1u>::type>
255 constexpr explicit operator type()
256 {
257 return (*this)[0];
258 }
259
260 static consteval uint32_t dim()
261 {
262 return T_dim;
263 }
264
265 /**
266 * Creates a Vec where all dimensions are set to the same value
267 *
268 * @param value Value which is set for all dimensions
269 * @return new Vec<...>
270 */
271 static constexpr auto fill(concepts::Convertible<T_Type> auto const& value)
272 {
273 if constexpr(requires { detail::TemplateSignatureStorage_v<T_Storage>; })
274 {
275 return UniVec([=](uint32_t const) { return static_cast<T_Type>(value); });
276 }
277 else
278 {
279 return Vec([=](uint32_t const) { return static_cast<T_Type>(value); });
280 }
281 }
282
283 template<auto T_v>
284 requires(isConvertible_v<ALPAKA_TYPEOF(T_v), T_Type>)
285 static constexpr auto fill() requires requires { T_Storage::template fill<T_v>(); }
286 {
288 }
289
290 constexpr Vec toRT() const
291
292 {
293 return *this;
294 }
295
296 constexpr Vec revert() const
297 {
298 Vec invertedVec{};
299 for(uint32_t i = 0u; i < T_dim; i++)
300 invertedVec[T_dim - 1 - i] = (*this)[i];
301
302 return invertedVec;
303 }
304
305 constexpr Vec& operator=(Vec const&) = default;
306 constexpr Vec& operator=(Vec&&) = default;
307
308 constexpr Vec operator-() const
309 {
310 return Vec([this](uint32_t const i) constexpr { return -(*this)[i]; });
311 }
312
313#define ALPAKA_VECTOR_ASSIGN_OP(op) \
314 template<typename T_OtherStorage> \
315 constexpr Vec& operator op(Vec<T_Type, T_dim, T_OtherStorage> const& rhs) \
316 { \
317 for(uint32_t i = 0u; i < T_dim; i++) \
318 { \
319 if constexpr(requires { unWrapp((*this)[i]) op rhs[i]; }) \
320 { \
321 unWrapp((*this)[i]) op rhs[i]; \
322 } \
323 else \
324 { \
325 (*this)[i] op rhs[i]; \
326 } \
327 } \
328 return *this; \
329 } \
330 constexpr Vec& operator op(concepts::LosslesslyConvertible<T_Type> auto const value) \
331 { \
332 for(uint32_t i = 0u; i < T_dim; i++) \
333 { \
334 if constexpr(requires { unWrapp((*this)[i]) op value; }) \
335 { \
336 unWrapp((*this)[i]) op value; \
337 } \
338 else \
339 { \
340 (*this)[i] op value; \
341 } \
342 } \
343 return *this; \
344 }
345
346 /** assign operator
347 * @{
348 */
354 /** @} */
355
356#undef ALPAKA_VECTOR_ASSIGN_OP
357
358 constexpr decltype(auto) operator[](std::integral auto const idx)
359 {
360 return Storage::operator[](idx);
361 }
362
363 constexpr decltype(auto) operator[](std::integral auto const idx) const
364 {
365 return Storage::operator[](idx);
366 }
367
368#define ALPAKA_NAMED_ARRAY_ACCESS(functionName, indexPos) \
369 /* An integer underflow may occur with `indexPos`, for example if `T_dim` is equal to 1 and `y()` should be \
370 declared as `(T_dim - 2u)`. Therefore the `requires` is fine, because everything which should be theoretical \
371 negative become much bigger. \
372 * than T_dim. */ \
373 constexpr decltype(auto) functionName() requires((indexPos) < T_dim) \
374 { \
375 return (*this)[indexPos]; \
376 } \
377 constexpr decltype(auto) functionName() const requires((indexPos) < T_dim) \
378 { \
379 return (*this)[indexPos]; \
380 }
381
382 /** named member access
383 *
384 * index -> name [0->w, 1->z, 2->y, 3->x]
385 * @{
386 */
388 ALPAKA_NAMED_ARRAY_ACCESS(y, T_dim - 2u)
389 ALPAKA_NAMED_ARRAY_ACCESS(z, T_dim - 3u)
390 ALPAKA_NAMED_ARRAY_ACCESS(w, T_dim - 4u)
391 /** @} */
393#undef ALPAKA_NAMED_ARRAY_ACCESS
394
395 constexpr decltype(auto) back()
396 {
397 return (*this)[T_dim - 1u];
398 }
399
400 constexpr decltype(auto) back() const
401 {
402 return (*this)[T_dim - 1u];
403 }
404
405 /** Shrink the number of elements of a vector.
406 *
407 * Highest indices kept alive.
408 *
409 * @tparam T_numElements New dimension of the vector.
410 * @return First T_numElements elements of the origin vector
411 */
412 template<uint32_t T_numElements>
413 constexpr Vec<T_Type, T_numElements> rshrink() const
414 {
415 static_assert(T_numElements <= T_dim);
417 for(uint32_t i = 0u; i < T_numElements; i++)
418 result[T_numElements - 1u - i] = (*this)[T_dim - 1u - i];
419
420 return result;
421 }
422
423 /** Shrink the vector
425 * Removes the last value.
426 */
427 constexpr Vec<T_Type, T_dim - 1u> eraseBack() const requires(T_dim > 1u)
428 {
429 constexpr auto reducedDim = T_dim - 1u;
431 for(uint32_t i = 0u; i < reducedDim; i++)
432 result[i] = (*this)[i];
433
434 return result;
435 }
436
437 /** Shrink the number of elements of a vector.
438 *
439 * @tparam T_numElements New dimension of the vector.
440 * @param startIdx Index within the origin vector which will be the last element in the result.
441 * @return T_numElements elements of the origin vector starting with the index startIdx.
442 * Indexing will wrapp around when the begin of the origin vector is reached.
443 */
444 template<uint32_t T_numElements>
445 constexpr Vec<type, T_numElements> rshrink(std::integral auto const startIdx) const
446 {
447 static_assert(T_numElements <= T_dim);
449 for(uint32_t i = 0u; i < T_numElements; i++)
450 result[T_numElements - 1u - i] = (*this)[(T_dim + startIdx - i) % T_dim];
451 return result;
452 }
453
454 /** Assign an value to the given index position
455 *
456 * @tparam T_elementIdx Index of the element from the begin which shall be replaced; range: [ 0; T_dim - 1 ]
457 * @param value value to assign to the element at the given index position
458 * @return copy of the vector with where the index positions are updated with value
459 */
460 template<uint32_t T_elementIdx = 0>
461 constexpr Vec<T_Type, T_dim> assign(T_Type const& value) const requires(T_elementIdx < T_dim)
462 {
463 auto result = *this;
464 result[T_elementIdx] = value;
465 return result;
466 }
467
468 /** Assign an value to the given index position
469 *
470 * @param selection CVec with the indices of the elements which shall be replaced; indices range must be
471 * [0; T_dim -1]
472 * @param value value to assign to the element at the given index position
473 * @return copy of the vector with where the index positions are updated with value
474 */
475 constexpr Vec<T_Type, T_dim> assign(
476 concepts::CVector auto const selection,
477 concepts::Vector<T_Type> auto const& value) const requires(ALPAKA_TYPEOF(value)::dim() <= T_dim)
478 {
479 auto result = *this;
480 result.ref(selection) = value;
481 return result;
482 }
483
484 /** Assign an value to the given index position
485 *
486 * @tparam T_elementIdx Index of the element from the back which shall be replaced; range: [ 0; T_dim - 1 ]
487 * @param value value to assign to the element at the given index position
488 * @return copy of the vector with where the index positions are updated with value
489 */
490 template<uint32_t T_elementIdx = T_dim - 1u>
491 constexpr Vec<T_Type, T_dim> rAssign(T_Type const& value) const requires(T_elementIdx < T_dim)
492 {
493 Vec<T_Type, T_dim> result = *this;
494 result[T_elementIdx] = value;
495 return result;
496 }
497
498 /** Removes a component
499 *
500 * It is not allowed to call this method on a vector with the dimensionality of one.
501 *
502 * @tparam dimToRemove index which shall be removed; range: [ 0; T_dim - 1 ]
503 * @return vector with `T_dim - 1` elements
504 */
505 template<std::integral auto dimToRemove>
506 constexpr Vec<type, T_dim - 1u> remove() const requires(T_dim >= 2u)
507 {
508 Vec<type, T_dim - 1u> result{};
509 for(int i = 0u; i < static_cast<int>(T_dim - 1u); ++i)
510 {
511 // skip component which must be deleted
512 int const sourceIdx = i >= static_cast<int>(dimToRemove) ? i + 1 : i;
513 result[i] = (*this)[sourceIdx];
514 }
515 return result;
516 }
517
518 /** Returns product of all components.
520 * @return product of components
521 */
522 constexpr type product() const
523 {
524 type result = (*this)[0];
525 for(uint32_t i = 1u; i < T_dim; i++)
526 result *= (*this)[i];
527 return result;
528 }
529
530 /** Returns sum of all components.
532 * @return sum of components
533 */
534 constexpr type sum() const
535 {
536 type result = (*this)[0];
537 for(uint32_t i = 1u; i < T_dim; i++)
538 result += (*this)[i];
539 return result;
540 }
541
542 /**
543 * == comparison operator.
544 *
545 * Compares dims of two DataSpaces.
546 *
547 * @param other Vec to compare to
548 * @return true if all components in both vectors are equal, else false
549 */
550 template<typename T_OtherStorage>
551 constexpr bool operator==(Vec<T_Type, T_dim, T_OtherStorage> const& rhs) const
552 {
553 bool result = true;
554 for(uint32_t i = 0u; i < T_dim; i++)
555 result = result && ((*this)[i] == rhs[i]);
556 return result;
557 }
558
559 /**
560 * != comparison operator.
561 *
562 * Compares dims of two DataSpaces.
563 *
564 * @param other Vec to compare to
565 * @return true if one component in both vectors are not equal, else false
566 */
567 template<typename T_OtherStorage>
568 constexpr bool operator!=(Vec<T_Type, T_dim, T_OtherStorage> const& rhs) const
569 {
570 return !((*this) == rhs);
572
573 template<typename T_OtherStorage>
574 constexpr auto min(Vec<T_Type, T_dim, T_OtherStorage> const& rhs) const
575 {
576 typename Vec::UniVec result{};
577 for(uint32_t d = 0u; d < T_dim; d++)
578 result[d] = std::min((*this)[d], rhs[d]);
579 return result;
580 }
581
582 /** create string out of the vector
583 *
584 * @param separator string to separate components of the vector
585 * @param enclosings string with dim 2 to enclose vector
586 * dim == 0 ? no enclose symbols
587 * dim == 1 ? means enclose symbol begin and end are equal
588 * dim >= 2 ? letter[0] = begin enclose symbol
589 * letter[1] = end enclose symbol
590 *
591 * example:
592 * .toString(";","|") -> |x;...;z|
593 * .toString(",","[]") -> [x,...,z]
594 */
595 std::string toString(std::string const separator = ",", std::string const enclosings = "{}") const
596 {
597 std::string locale_enclosing_begin;
598 std::string locale_enclosing_end;
599 size_t enclosing_dim = enclosings.size();
600
601 if(enclosing_dim > 0)
602 {
603 /* % avoid out of memory access */
604 locale_enclosing_begin = enclosings[0 % enclosing_dim];
605 locale_enclosing_end = enclosings[1 % enclosing_dim];
606 }
607
608 std::stringstream stream;
609 stream << locale_enclosing_begin << (*this)[0];
610
611 for(uint32_t i = 1u; i < T_dim; ++i)
612 stream << separator << (*this)[i];
613 stream << locale_enclosing_end;
614 return stream.str();
615 }
617 /** swizzle operator */
618 template<typename T, T... T_values>
619 constexpr auto operator[](Vec<T, sizeof...(T_values), detail::CVec<T, T_values...>> const v) const
620 {
621 using InType = ALPAKA_TYPEOF(v);
622 return Vec<T_Type, InType::dim()>{(*this)[T_values]...};
624
625 template<typename T, T... T_values>
626 constexpr auto ref(Vec<T, sizeof...(T_values), detail::CVec<T, T_values...>> const v)
627 {
628 using InType = ALPAKA_TYPEOF(v);
629 using ArrayType = std::array<ALPAKA_TYPEOF(std::ref((*this)[T{0}])), sizeof...(T_values)>;
630 auto array = ArrayType{std::ref((*this)[T_values])...};
631 return Vec<T_Type, InType::dim(), ALPAKA_TYPEOF(array)>{array};
633
634 template<typename T, T... T_values>
635 constexpr auto ref(Vec<T, sizeof...(T_values), detail::CVec<T, T_values...>> const v) const
636 {
637 using InType = ALPAKA_TYPEOF(v);
638 using ArrayType = std::array<ALPAKA_TYPEOF(std::ref((*this)[T{0}])), sizeof...(T_values)>;
639 auto array = ArrayType{std::ref((*this)[T_values])...};
640 return Vec<T_Type, InType::dim(), ALPAKA_TYPEOF(array)>{array};
641 }
642
643 /** reduce all elements to a single value
644 *
645 * For better numerical stability a tree reduce algorithm is used.
646 *
647 * @tparam BinaryOp binary functor executed to reduce the range
648 * The binary operation must be associative.
649 * @return the type of the result depends on the binary functor
650 */
651 [[nodiscard]] constexpr auto reduce(auto&& reduceFunc) const
652 -> decltype(reduceFunc(std::declval<type>(), std::declval<type>()))
653 {
654 return reduce_range(ALPAKA_FORWARD(reduceFunc));
655 }
656
657 private:
658 /** reduce over a range of elements
659 *
660 * @tparam BinaryOp binary functor executed to reduce the range
661 * @tparam T_start start index
662 * @tparam T_end end index (excluded)
663 * @return the type of the result depends on the binary functor
664 */
665 template<uint32_t T_start = 0u, uint32_t T_end = dim()>
666 [[nodiscard]] constexpr auto reduce_range(auto&& reduceFunc) const
667 -> decltype(reduceFunc(std::declval<type>(), std::declval<type>()))
668 {
669 // elements in the range
670 constexpr uint32_t size = T_end - T_start;
671 // single element termination
672 if constexpr(size == 1u)
673 {
674 return (*this)[T_start];
675 }
676#if ALPAKA_LANG_SYCL
677 // SYCL can not call recursive functions
678 auto result = (*this)[T_start];
679 for(uint32_t i = T_start + 1u; i < T_end; ++i)
680 {
681 result = reduceFunc(result, (*this)[i]);
682 }
683 return result;
684#else
685 // split range at midpoint
686 constexpr uint32_t mid = T_start + size / 2u;
687
688 // recursively reduce both halves and combine
689 return reduceFunc(
692#endif
693 }
694 };
695
696 template<std::size_t I, typename T_Type, uint32_t T_dim, typename T_Storage>
697 constexpr auto get(Vec<T_Type, T_dim, T_Storage> const& v)
698 {
699 return v[I];
701
702 template<std::size_t I, typename T_Type, uint32_t T_dim, typename T_Storage>
703 constexpr decltype(auto) get(Vec<T_Type, T_dim, T_Storage>& v)
704 {
705 return v[I];
707
708 template<typename Type>
709 struct Vec<Type, 0>
710 {
711 using type = Type;
712 static constexpr uint32_t T_dim = 0;
713
714 template<typename OtherType>
715 constexpr operator Vec<OtherType, 0>() const
716 {
717 return Vec<OtherType, 0>();
718 }
719
720 /**
721 * == comparison operator.
723 * Returns always true
724 */
725 constexpr bool operator==(Vec const&) const
726 {
727 return true;
728 }
729
730 /**
731 * != comparison operator.
733 * Returns always false
734 */
735 constexpr bool operator!=(Vec const&) const
736 {
737 return false;
738 }
739
740 static constexpr Vec create(Type)
741 {
742 /* this method should never be actually called,
743 * it exists only for Visual Studio to handle alpaka::Size_t< 0 >
744 */
745 static_assert(sizeof(Type) != 0 && false);
746 }
747 };
749 // type deduction guide
750 template<typename T_1, typename... T_Args>
751 ALPAKA_FN_HOST_ACC Vec(T_1, T_Args...)
752 -> Vec<T_1, uint32_t(sizeof...(T_Args) + 1u), ArrayStorage<T_1, uint32_t(sizeof...(T_Args) + 1u)>>;
753
754 template<typename Type, uint32_t T_dim, typename T_Storage>
755 std::ostream& operator<<(std::ostream& s, Vec<Type, T_dim, T_Storage> const& vec)
756 {
757 /* Usage of a temporary universal vector variable is required as workaround to silent an error with gcc 15
758 * error: 'frameSpec' may be used uninitialized [-Werror=maybe-uninitialized] when compiling with 'ubsan'
759 * enabled. It is a false positive in some cases where a CVec is used. Since this method is not performance
760 * critical this workaround should be acceptable.
761 */
763 return s << v.toString();
764 }
765
766#define ALPAKA_VECTOR_BINARY_OP(typenameOrConcept, resultScalarType, op) \
767 template<typenameOrConcept T_Type, uint32_t T_dim, typename T_Storage, typename T_OtherStorage> \
768 constexpr auto operator op( \
769 const Vec<T_Type, T_dim, T_Storage>& lhs, \
770 const Vec<T_Type, T_dim, T_OtherStorage>& rhs) \
771 { \
772 /* to avoid allocation side effects the result is always a vector \
773 * with default policies \
774 */ \
775 Vec<resultScalarType, T_dim> result{}; \
776 for(uint32_t i = 0u; i < T_dim; i++) \
777 result[i] = lhs[i] op rhs[i]; \
778 return result; \
779 } \
780 \
781 template< \
782 typenameOrConcept T_Type, \
783 concepts::LosslesslyConvertible<T_Type> T_ValueType, \
784 uint32_t T_dim, \
785 typename T_Storage> \
786 constexpr auto operator op(const Vec<T_Type, T_dim, T_Storage>& lhs, T_ValueType rhs) \
787 { \
788 /* to avoid allocation side effects the result is always a vector \
789 * with default policies \
790 */ \
791 Vec<resultScalarType, T_dim> result{}; \
792 for(uint32_t i = 0u; i < T_dim; i++) \
793 result[i] = lhs[i] op rhs; \
794 return result; \
795 } \
796 template< \
797 typenameOrConcept T_Type, \
798 concepts::LosslesslyConvertible<T_Type> T_ValueType, \
799 uint32_t T_dim, \
800 typename T_Storage> \
801 constexpr auto operator op(T_ValueType lhs, const Vec<T_Type, T_dim, T_Storage>& rhs) \
802 { \
803 /* to avoid allocation side effects the result is always a vector \
804 * with default policies \
805 */ \
806 Vec<resultScalarType, T_dim> result{}; \
807 for(uint32_t i = 0u; i < T_dim; i++) \
808 result[i] = lhs op rhs[i]; \
809 return result; \
812 /** binary operators
813 * @{
814 */
815 ALPAKA_VECTOR_BINARY_OP(typename, T_Type, +)
816 ALPAKA_VECTOR_BINARY_OP(typename, T_Type, -)
817 ALPAKA_VECTOR_BINARY_OP(typename, T_Type, *)
818 ALPAKA_VECTOR_BINARY_OP(typename, T_Type, /)
819 ALPAKA_VECTOR_BINARY_OP(typename, bool, >=)
820 ALPAKA_VECTOR_BINARY_OP(typename, bool, >)
821 ALPAKA_VECTOR_BINARY_OP(typename, bool, <=)
822 ALPAKA_VECTOR_BINARY_OP(typename, bool, <)
823 ALPAKA_VECTOR_BINARY_OP(typename, bool, &&)
824 ALPAKA_VECTOR_BINARY_OP(typename, bool, ||)
825 ALPAKA_VECTOR_BINARY_OP(std::integral, T_Type, %)
826 ALPAKA_VECTOR_BINARY_OP(std::integral, T_Type, <<)
827 ALPAKA_VECTOR_BINARY_OP(std::integral, T_Type, >>)
828 ALPAKA_VECTOR_BINARY_OP(std::integral, T_Type, &)
829 ALPAKA_VECTOR_BINARY_OP(std::integral, T_Type, |)
830 ALPAKA_VECTOR_BINARY_OP(std::integral, T_Type, ^)
831 /** @} */
832
833#undef ALPAKA_VECTOR_BINARY_OP
834
835 /** Give the linear index of an N-dimensional index within an N-dimensional index space.
836 *
837 * @tparam T_IntegralType vector data type (must be an integral type)
838 * @tparam T_dim dimension of the vector, should be >= 2
839 * @param dim N-dimensional dim of the index space (N can be one dimension less compared to idx)
840 * @param idx N-dimensional index within the index space
841 * @attention behaviour is undefined for negative index
842 * @attention if idx is outside of dim the result will be outside of the the index domain too
843 * @return linear index within the index domain
844 *
845 * @{
846 */
847 template<std::integral T_IntegralType, typename T_Storage, typename T_OtherStorage, uint32_t T_dim>
848 constexpr T_IntegralType linearize(
850 Vec<T_IntegralType, T_dim, T_OtherStorage> const& idx) requires(T_dim >= 2u)
852 T_IntegralType linearIdx{idx[0]};
853 for(uint32_t d = 1u; d < T_dim; ++d)
854 linearIdx = linearIdx * dim[d - 1u] + idx[d];
855
856 return linearIdx;
857 }
858
859 template<std::integral T_IntegralType, typename T_Storage, typename T_OtherStorage, uint32_t T_dim>
860 constexpr T_IntegralType linearize(
863 {
864 return linearize(dim.template rshrink<T_dim - 1u>(), idx);
865 }
866
867 template<std::integral T_IntegralType, typename T_Storage, typename T_OtherStorage>
868 ALPAKA_FN_HOST_ACC T_IntegralType linearize(
869 Vec<T_IntegralType, 1u, T_Storage> const&,
870 Vec<T_IntegralType, 1u, T_OtherStorage> const& idx)
871 {
872 return idx.x();
873 }
874
875 /** @} */
876
877 /** Maps a linear index to an N-dimensional index
878 *
879 * @tparam T_IntegralType vector data type (must be an integral type)
880 * @param dim N-dimensional index space
881 * @param linearIdx Linear index within dim.
882 * @attention If linearIdx is an index outside of dim the result will be outside of the index domain
883 * too.
884 * @return N-dimensional index
885 *
886 * @{
887 */
888 template<std::integral T_IntegralType, typename T_Storage, uint32_t T_dim>
891 T_IntegralType linearIdx) requires(T_dim >= 2u)
892 {
893 constexpr uint32_t reducedDim = T_dim - 1u;
895 pitchExtents.back() = extents.back();
896 for(uint32_t d = 1u; d < T_dim - 1u; ++d)
897 pitchExtents[reducedDim - 1u - d] = extents[T_dim - 1u - d] * pitchExtents[reducedDim - d];
898
900 for(uint32_t d = 0u; d < T_dim - 1u; ++d)
902 result[d] = linearIdx / pitchExtents[d];
903 linearIdx -= pitchExtents[d] * result[d];
904 }
905 result[T_dim - 1u] = linearIdx;
906 return result;
907 }
908
909 template<std::integral T_IntegralType, typename T_Storage>
910 constexpr Vec<T_IntegralType, 1u> mapToND(
911 Vec<T_IntegralType, 1u, T_Storage> const& extents,
912 T_IntegralType linearIdx)
913 {
914 alpaka::unused(extents);
915 return {linearIdx};
916 }
917
918 /** @} */
920 namespace trait
921 {
922 template<typename T_Type, uint32_t T_dim, typename T_Storage>
923 struct IsVector<Vec<T_Type, T_dim, T_Storage>> : std::true_type
924 {
925 };
926
927 template<typename T_Type, uint32_t T_dim, T_Type... T_values>
928 struct IsCVector<Vec<T_Type, T_dim, detail::CVec<T_Type, T_values...>>> : std::true_type
930 };
931 } // namespace trait
932
933 namespace trait
934 {
935 template<typename T_Type, uint32_t T_dim, typename T_Storage>
936 struct GetDim<alpaka::Vec<T_Type, T_dim, T_Storage>>
937 {
938 static constexpr uint32_t value = T_dim;
939 };
940
941 template<typename T>
942 struct GetVec;
943
944 template<std::integral T>
945 struct GetVec<T>
946 {
947 using type = Vec<T, 1u>;
948 };
949
950 template<typename T_Type, uint32_t T_dim, typename T_Storage>
951 struct GetVec<alpaka::Vec<T_Type, T_dim, T_Storage>>
952 {
954 };
955
956 template<typename T>
957 using getVec_t = typename GetVec<T>::type;
958
959 template<typename T_Type, uint32_t T_dim, typename T_Storage>
960 struct GetValueType<Vec<T_Type, T_dim, T_Storage>>
961 {
962 using type = T_Type;
963 };
964
965 } // namespace trait
966
967 template<typename T>
968 consteval auto getVec(T const& any)
970 return trait::getVec_t<T>{any};
971 }
972
973 namespace internal
974 {
975 template<typename T_To, typename T_Type, uint32_t T_dim, typename T_Storage>
976 struct PCast::Op<T_To, alpaka::Vec<T_Type, T_dim, T_Storage>>
977 {
978 constexpr auto operator()(auto&& input) const
979 requires std::convertible_to<T_Type, T_To> && (!std::same_as<T_To, T_Type>)
980 {
981 return typename alpaka::Vec<T_To, T_dim, T_Storage>::UniVec([&](uint32_t idx) constexpr
982 { return static_cast<T_To>(input[idx]); });
983 }
984
985 constexpr decltype(auto) operator()(auto&& input) const requires std::same_as<T_To, T_Type>
986 {
987 return std::forward<decltype(input)>(input);
989 };
990 } // namespace internal
991
992 /** @todo the function for integral values is defined in Utils.hpp
993 * move this to a better place, e.g. math and expose this for the user too
994 */
995 template<concepts::Vector T_Vector0, concepts::Vector T_Vector1>
996 requires(std::is_same_v<trait::GetValueType_t<T_Vector0>, trait::GetValueType_t<T_Vector1>>)
997 [[nodiscard]] ALPAKA_FN_HOST_ACC constexpr concepts::Vector auto divCeil(T_Vector0 a, T_Vector1 b)
998 {
999 return (a + b - T_Vector0::fill(1)) / b;
1000 }
1001
1002 template<concepts::Vector T_Vector0, concepts::Vector T_Vector1>
1003 requires(std::is_same_v<trait::GetValueType_t<T_Vector0>, trait::GetValueType_t<T_Vector1>>)
1004 [[nodiscard]] ALPAKA_FN_HOST_ACC constexpr concepts::Vector auto divExZero(T_Vector0 a, T_Vector1 b)
1005 {
1006 auto tmp = a / b;
1007
1009 for(uint32_t d = 0u; d < a.dim(); ++d)
1010 tmp[d] = std::max(tmp[d], ValueType{1u});
1011 return tmp;
1012 }
1013}; // namespace alpaka
1014
1015namespace std
1016{
1017 template<typename T_Type, uint32_t T_dim, typename T_Storage>
1018 struct tuple_size<alpaka::Vec<T_Type, T_dim, T_Storage>>
1019 {
1020 static constexpr std::size_t value = T_dim;
1021 };
1022
1023 template<std::size_t I, typename T_Type, uint32_t T_dim, typename T_Storage>
1024 struct tuple_element<I, alpaka::Vec<T_Type, T_dim, T_Storage>>
1025 {
1026 using type = T_Type;
1027 };
1028} // namespace std
#define ALPAKA_NAMED_ARRAY_ACCESS(functionName, laneIdx)
Definition Simd.hpp:275
#define ALPAKA_VECTOR_ASSIGN_OP(op)
assign operator
Definition Simd.hpp:232
#define ALPAKA_VECTOR_BINARY_OP(typenameOrConcept, op)
binary operators
Definition Simd.hpp:549
#define ALPAKA_VECTOR_BINARY_OP(typenameOrConcept, resultScalarType, op)
Definition Vec.hpp:763
#define ALPAKA_NAMED_ARRAY_ACCESS(functionName, indexPos)
Definition Vec.hpp:368
#define ALPAKA_VECTOR_ASSIGN_OP(op)
Definition Vec.hpp:313
#define ALPAKA_FN_HOST_ACC
All functions that can be used on an accelerator have to be attributed with ALPAKA_FN_ACC or ALPAKA_F...
Definition common.hpp:32
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Definition common.hpp:154
#define ALPAKA_FORWARD(instance)
Perfectly forward an instance as argument.
Definition common.hpp:148
Concept to check if a type is a CVector.
Definition Vec.hpp:75
Concept to check if a type is a vector or a specific other type.
Definition Vec.hpp:85
Concept to check if a type is a vector or scalar variable.
Definition Vec.hpp:65
Concept to check if a type is a vector.
Definition Vec.hpp:54
constexpr bool TemplateSignatureStorage_v
Definition Vec.hpp:174
alpaka internal implementations.
Definition generic.hpp:19
typename GetVec< T >::type getVec_t
Definition Vec.hpp:948
typename GetValueType< T >::type GetValueType_t
Definition trait.hpp:65
main alpaka namespace.
Definition alpaka.hpp:76
constexpr uint32_t notRequiredDim
Definition trait.hpp:23
ALPAKA_FN_HOST_ACC constexpr auto divCeil(Integral a, Integral b) -> Integral
Returns the ceiling of a / b, as integer.
Definition utility.hpp:34
std::ostream & operator<<(std::ostream &os, concepts::BoundaryDirection auto const &bd)
constexpr T_IntegralType linearize(Vec< T_IntegralType, T_dim - 1u, T_Storage > const &dim, Vec< T_IntegralType, T_dim, T_OtherStorage > const &idx)
Give the linear index of an N-dimensional index within an N-dimensional index space.
Definition Vec.hpp:839
Vec< T, sizeof...(T_values), detail::CVec< T, T_values... > > CVec
A vector with compile-time known values.
Definition CVec.hpp:31
ALPAKA_FN_HOST_ACC Vec(T_1, T_Args...) -> Vec< T_1, uint32_t(sizeof...(T_Args)+1u), ArrayStorage< T_1, uint32_t(sizeof...(T_Args)+1u)> >
constexpr bool isVector_v
Definition Vec.hpp:39
constexpr bool isConvertible_v
Definition trait.hpp:125
consteval auto getVec(T const &any)
Definition Vec.hpp:959
constexpr bool isCVector_v
Definition Vec.hpp:42
constexpr Vec< T_IntegralType, T_dim > mapToND(Vec< T_IntegralType, T_dim, T_Storage > const &extents, T_IntegralType linearIdx)
Maps a linear index to an N-dimensional index.
Definition Vec.hpp:880
STL namespace.
Array storge for vector data.
Definition Vec.hpp:99
constexpr ArrayStorage(std::array< T_Type, T_dim > const &data)
Definition Vec.hpp:110
constexpr ArrayStorage(T_Args &&... args)
Definition Vec.hpp:106
std::array< T_Type, T_dim > BaseType
Definition Vec.hpp:101
static constexpr uint32_t T_dim
Definition Vec.hpp:709
constexpr bool operator==(Vec const &) const
== comparison operator.
Definition Vec.hpp:722
constexpr bool operator!=(Vec const &) const
!= comparison operator.
Definition Vec.hpp:732
constexpr Vec()=default
constexpr Vec operator-() const
Definition Vec.hpp:308
constexpr Vec< type, T_dim - 1u > remove() const
Definition Vec.hpp:503
constexpr Vec(T_Storage const &other)
Definition Vec.hpp:241
static constexpr auto fill(concepts::Convertible< T_Type > auto const &value)
Creates a Vec where all dimensions are set to the same value.
Definition Vec.hpp:271
constexpr Vec(F &&generator)
Initialize via a generator expression.
Definition Vec.hpp:204
constexpr Vec(F &&generator, std::integer_sequence< uint32_t, Is... >)
Definition Vec.hpp:211
static consteval uint32_t dim()
Definition Vec.hpp:260
constexpr Vec revert() const
Definition Vec.hpp:296
constexpr bool operator==(Vec< T, T_dim, T_OtherStorage > const &rhs) const
Definition Vec.hpp:548
constexpr Vec< T, T_dim > assign(T const &value) const
Definition Vec.hpp:458
constexpr Vec toRT() const
Definition Vec.hpp:290
constexpr Vec< T, T_numElements > rshrink() const
Definition Vec.hpp:410
constexpr Vec & operator=(Vec const &)=default
std::string toString(std::string const separator=",", std::string const enclosings="{}") const
Definition Vec.hpp:592
constexpr Vec(Vec< T_Type, T_dim, T_OtherStorage > const &other)
constructor allows changing the storage policy
Definition Vec.hpp:248
static constexpr auto fill()
Definition Vec.hpp:285
constexpr bool operator!=(Vec< T, T_dim, T_OtherStorage > const &rhs) const
Definition Vec.hpp:565
constexpr auto reduce(auto &&reduceFunc) const -> decltype(reduceFunc(std::declval< type >(), std::declval< type >()))
Definition Vec.hpp:648
constexpr decltype(auto) operator[](std::integral auto const idx)
Definition Vec.hpp:358
constexpr Vec< T, T_dim > rAssign(T const &value) const
Definition Vec.hpp:488
constexpr Vec & operator=(Vec &&)=default
constexpr Vec(Vec const &other)=default
constexpr auto reduce_range(auto &&reduceFunc) const -> decltype(reduceFunc(std::declval< type >(), std::declval< type >()))
Definition Vec.hpp:663
static constexpr auto integerSequenceToCVec(std::integer_sequence< T, T_indices... >, auto const op=std::identity{})
Definition Vec.hpp:155
static consteval uint32_t dim()
Definition Vec.hpp:122
constexpr T operator[](std::integral auto const idx) const
Definition Vec.hpp:127
static constexpr auto fill()
Definition Vec.hpp:147
alpaka::Vec< T_Type, T_dim, T_Storage > type
Definition Vec.hpp:944