ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
vector.hpp
1// This file is part of the ACTS project.
2//
3// Copyright (C) 2016 CERN for the benefit of the ACTS project
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8#pragma once
9
10// @TODO: Remove this when Vc fixes their false positives.
11#if defined(__GNUC__) && !defined(__clang__)
12#pragma GCC diagnostic warning "-Wdeprecated-declarations"
13#endif
14
15// Project include(s)
16#include "detray/algebra/common/array_operators.hpp"
17#include "detray/algebra/concepts.hpp"
18#include "detray/definitions/detail/qualifiers.hpp"
19
20// System include(s).
21#include <array>
22#include <cstddef>
23#include <initializer_list>
24#include <type_traits>
25#include <utility>
26
27namespace detray::algebra {
28
29namespace storage {
30
31namespace detail {
35DETRAY_HOST_DEVICE
36consteval std::size_t nearest_power_of_two(std::size_t min_value,
37 std::size_t current_value) {
38 // Computes the nearest power of two relative to `min_value` starting from
39 // the power of two `current_value`
40 return min_value <= current_value
41 ? current_value
42 : nearest_power_of_two(min_value, current_value * 2u);
43}
44
45} // namespace detail
46
49template <std::size_t N, concepts::scalar scalar_t,
50 template <typename, std::size_t> class array_t>
51class DETRAY_ALIGN(
52 alignof(array_t<scalar_t, detail::nearest_power_of_two(N, 2u)>)) vector {
53 public:
55 DETRAY_HOST_DEVICE
56 static consteval std::size_t simd_size() {
57 return concepts::value<scalar_t> ? detail::nearest_power_of_two(N, 2u) : N;
58 }
59
61 using scalar_type = scalar_t;
63 using array_type = array_t<scalar_t, simd_size()>;
64
66 DETRAY_HOST_DEVICE
67 constexpr vector() {
69 zero_fill(std::make_index_sequence<simd_size()>{});
70 }
71 }
72
76
79 template <typename... Scalars>
80 requires(concepts::simd_scalar<scalar_t> && (sizeof...(Scalars) == N) &&
82 std::convertible_to<Scalars, scalar_t>) &&
83 ...))
84 // Element-wise construction, not a conversion: the requires-clause pins the
85 // argument count to N.
86 // NOLINTNEXTLINE(google-explicit-constructor)
87 DETRAY_HOST_DEVICE constexpr vector(Scalars &&...scals)
88 : m_data{std::forward<Scalars>(scals)...} {}
89
96 template <typename... Values>
97 requires(!concepts::simd_scalar<scalar_t> && (sizeof...(Values) > 1) &&
99 std::convertible_to<Values, scalar_t>) &&
100 ...))
101 // NOLINTNEXTLINE(google-explicit-constructor)
102 DETRAY_HOST_DEVICE constexpr vector(Values &&...vals) {
103 static_assert(sizeof...(Values) <= N);
104
105 // Fill up last entries, if necessary (explicitly for now)
106 if constexpr ((simd_size() - N) == 1) {
107 m_data = {std::forward<Values>(vals)..., 0.f};
108 } else if constexpr ((simd_size() - N) == 2) {
109 m_data = {std::forward<Values>(vals)..., 0.f, 0.f};
110 } else if constexpr (sizeof...(Values) < simd_size()) {
111 // @TODO: Does this actually work, yet?
112 zero_fill(std::make_index_sequence<simd_size() - sizeof...(Values)>{});
113 } else {
114 m_data = {std::forward<Values>(vals)...};
115 }
116 }
117
119
126 DETRAY_HOST_DEVICE
127 // NOLINTNEXTLINE(google-explicit-constructor)
128 constexpr vector(array_type &&vals) : m_data{std::move(vals)} {}
129
131 DETRAY_HOST_DEVICE
132 // NOLINTNEXTLINE(google-explicit-constructor)
133 constexpr vector(const array_type &vals) : m_data{vals} {}
135
140 template <std::size_t M>
143 DETRAY_HOST_DEVICE constexpr const vector &operator=(
144 const vector<M, scalar_t, array_t> &lhs) {
145 m_data = lhs;
146 return *this;
147 }
148
152 DETRAY_HOST_DEVICE
153 // NOLINTNEXTLINE(google-explicit-constructor)
154 constexpr operator array_type &() { return m_data; }
157 DETRAY_HOST_DEVICE
158 // NOLINTNEXTLINE(google-explicit-constructor)
159 constexpr operator const array_type &() const { return m_data; }
161
164 DETRAY_HOST_DEVICE
165 constexpr const auto &get() const { return m_data; }
166
171 DETRAY_HOST_DEVICE
172 constexpr decltype(auto) operator[](std::size_t i) { return m_data[i]; }
175 DETRAY_HOST_DEVICE
176 constexpr decltype(auto) operator[](std::size_t i) const { return m_data[i]; }
178
183 DETRAY_HOST_DEVICE
184 constexpr decltype(auto) operator*=(scalar_type factor) noexcept {
185 return m_data *= factor;
186 }
187
191 template <concepts::scalar S = scalar_t>
192 requires(!concepts::simd_scalar<S>)
193 DETRAY_HOST_DEVICE constexpr friend bool operator==(
194 const vector &lhs, const vector &rhs) noexcept {
195 const auto comp = lhs.compare(rhs);
196 bool is_full = true;
197
198 DETRAY_UNROLL_N(N)
199 for (unsigned int i{0u}; i < N; ++i) {
200 is_full = is_full && comp[i];
201 }
202
203 return is_full;
204 }
205
207 template <concepts::scalar S = scalar_t>
209 DETRAY_HOST_DEVICE constexpr friend bool operator==(
210 const vector &lhs, const vector &rhs) noexcept {
211 const auto comp = lhs.compare(rhs);
212 bool is_full = true;
213
214 DETRAY_UNROLL_N(N)
215 for (unsigned int i{0u}; i < N; ++i) {
216 // Ducktyping the Vc::Vector::MaskType
217 is_full = is_full && comp[i].isFull();
218 }
219
220 return is_full;
221 }
222
223
227 template <typename other_t>
228 DETRAY_HOST_DEVICE constexpr bool operator!=(
229 const other_t &rhs) const noexcept {
230 return ((*this == rhs) == false);
231 }
232
236 template <typename other_t>
237 DETRAY_HOST_DEVICE constexpr auto compare(const other_t &rhs) const noexcept {
238 using result_t = decltype(m_data[0] == rhs[0]);
239
240 std::array<result_t, N> comp;
241
242 DETRAY_UNROLL_N(N)
243 for (unsigned int i{0u}; i < N; ++i) {
244 comp[i] = (m_data[i] == rhs[i]);
245 }
246
247 return comp;
248 }
249
251 array_t<scalar_t, simd_size()> m_data;
252
253 private:
255 template <std::size_t... Is>
256 DETRAY_HOST_DEVICE constexpr void zero_fill(
257 std::index_sequence<Is...> /*unused*/) noexcept {
258 ((m_data[simd_size() - sizeof...(Is) + Is] = static_cast<scalar_t>(0)),
259 ...);
260 }
261};
262
264#define DECLARE_VECTOR_OPERATORS(OP) \
265 template <std::size_t N, concepts::scalar scalar_t, concepts::value value_t, \
266 template <typename, std::size_t> class array_t> \
267 DETRAY_HOST_DEVICE constexpr decltype(auto) operator OP( \
268 const vector<N, scalar_t, array_t> &lhs, value_t rhs) noexcept { \
269 return lhs.m_data OP static_cast<scalar_t>(rhs); \
270 } \
271 template <std::size_t N, concepts::scalar scalar_t, concepts::value value_t, \
272 template <typename, std::size_t> class array_t> \
273 DETRAY_HOST_DEVICE constexpr decltype(auto) operator OP( \
274 value_t lhs, const vector<N, scalar_t, array_t> &rhs) noexcept { \
275 return static_cast<scalar_t>(lhs) OP rhs.m_data; \
276 } \
277 template <std::size_t N, concepts::scalar scalar_t, \
278 template <typename, std::size_t> class array_t> \
279 DETRAY_HOST_DEVICE constexpr decltype(auto) operator OP( \
280 const vector<N, scalar_t, array_t> &lhs, \
281 const vector<N, scalar_t, array_t> &rhs) noexcept { \
282 return lhs.m_data OP rhs.m_data; \
283 } \
284 template <std::size_t N, concepts::scalar scalar_t, \
285 template <typename, std::size_t> class array_t, typename other_t> \
286 requires(concepts::vector<other_t> || concepts::simd_scalar<other_t>) \
287 DETRAY_HOST_DEVICE constexpr decltype(auto) operator OP( \
288 const vector<N, scalar_t, array_t> &lhs, const other_t &rhs) noexcept { \
289 return lhs.m_data OP rhs; \
290 } \
291 template <std::size_t N, concepts::scalar scalar_t, \
292 template <typename, std::size_t> class array_t, typename other_t> \
293 requires(concepts::vector<other_t> || concepts::simd_scalar<other_t>) \
294 DETRAY_HOST_DEVICE constexpr decltype(auto) operator OP( \
295 const other_t &lhs, const vector<N, scalar_t, array_t> &rhs) noexcept { \
296 return lhs OP rhs.m_data; \
297 }
298
299// Implement all arithmetic operations on top of @c vector.
300// clang-format off
301DECLARE_VECTOR_OPERATORS(+)
302DECLARE_VECTOR_OPERATORS(-)
303DECLARE_VECTOR_OPERATORS(*)
304DECLARE_VECTOR_OPERATORS(/)
305// clang-format on
306
307// Clean up.
308#undef DECLARE_VECTOR_OPERATORS
309
310} // namespace storage
311
312namespace detail {
313
314template <typename T>
315struct is_storage_vector : public std::false_type {};
316
317template <std::size_t N, concepts::scalar scalar_t,
318 template <typename, std::size_t> class array_t>
319struct is_storage_vector<algebra::storage::vector<N, scalar_t, array_t>>
320 : public std::true_type {};
321
322template <typename T>
323inline constexpr bool is_storage_vector_v = is_storage_vector<T>::value;
324
325} // namespace detail
326
327} // namespace detray::algebra
Vector wrapper for AoS vs interleaved SoA data.
Definition vector.hpp:52
constexpr const auto & get() const
Return the underlying storage array.
Definition vector.hpp:165
static consteval std::size_t simd_size()
Definition vector.hpp:56
constexpr vector()
Default constructor sets all entries to zero.
Definition vector.hpp:67
constexpr auto compare(const other_t &rhs) const noexcept
Elementwise comparison.
Definition vector.hpp:237
array_t< scalar_t, simd_size()> array_type
Definition vector.hpp:63
array_t< scalar_t, simd_size()> m_data
Definition vector.hpp:251
constexpr vector(const array_type &vals)
Definition vector.hpp:133
constexpr vector(array_type &&vals)
Construct from existing array storage vals.
Definition vector.hpp:128
constexpr bool operator!=(const other_t &rhs) const noexcept
Inequality operator.
Definition vector.hpp:228
Scalar concept: Elements of vectors/matrices (can be simd vectors).
Definition concepts.hpp:40
Check if a scalar is simd.
Definition concepts.hpp:50
Definition concepts.hpp:32