ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
join.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
9#pragma once
10
11// Project include(s)
12#include "detray/definitions/containers.hpp"
13#include "detray/definitions/detail/qualifiers.hpp"
14#include "detray/utils/ranges/empty.hpp"
15#include "detray/utils/ranges/ranges.hpp"
16#include "detray/utils/type_traits.hpp"
17
18// System include(s)
19#include <type_traits>
20
21namespace detray::ranges {
22
23namespace detail {
24
25template <detray::ranges::range T>
26struct join_iterator;
27
28}
29
41template <detray::ranges::range range_t>
42struct join_view : public detray::ranges::view_interface<join_view<range_t>> {
44 using outer_iterator_t = detray::ranges::iterator_t<range_t>;
47 std::conditional_t<std::is_const_v<range_t>,
48 const detray::ranges::range_value_t<range_t>,
49 detray::ranges::range_value_t<range_t>>;
51 using inner_iterator_t = detray::ranges::iterator_t<outer_value_t>;
52
56 using value_t = std::iter_value_t<iterator_t>;
57
59 constexpr join_view() = default;
60
63 template <detray::ranges::range R>
64 requires(!std::same_as<R, join_view>)
65 DETRAY_HOST_DEVICE constexpr explicit join_view(R &&ranges)
66 : m_begin{detray::ranges::begin(ranges)},
67 m_end{detray::ranges::end(ranges)} {}
68
70 DETRAY_HOST_DEVICE
71 constexpr auto begin() const -> iterator_t { return {m_begin, m_end}; }
72
74 DETRAY_HOST_DEVICE
75 constexpr auto end() const -> iterator_t { return {m_end, m_end}; }
76
79 DETRAY_HOST_DEVICE
80 constexpr auto data() const -> const value_t * { return &(*(*m_begin)); }
81
84 DETRAY_HOST_DEVICE
85 constexpr auto data() -> value_t * { return &(*(*m_begin)); }
86
88 DETRAY_HOST_DEVICE
89 constexpr auto size() const noexcept -> std::size_t {
90 std::size_t size{0u};
91 for (outer_iterator_t itr = m_begin; itr != m_end; ++itr) {
92 // subrange
93 const auto begin = detray::ranges::begin(*itr);
94 const auto end = detray::ranges::end(*itr);
95 size += static_cast<std::size_t>(detray::ranges::distance(begin, end));
96 }
97 return size;
98 }
99
103};
104
105namespace views {
106
108template <detray::ranges::range range_t>
109struct join : public ranges::join_view<range_t> {
112
113 constexpr join() = default;
114
117 template <detray::ranges::range deduced_range_t>
118 requires(!std::same_as<deduced_range_t, join>)
119 DETRAY_HOST_DEVICE constexpr explicit join(deduced_range_t &&ranges)
120 : base_type(std::forward<deduced_range_t>(ranges)) {}
121
125 template <detray::ranges::range deduced_range_t>
126 DETRAY_HOST_DEVICE constexpr auto operator()(deduced_range_t &&ranges) {
128 std::forward<deduced_range_t>(ranges));
129 }
130
134 DETRAY_HOST_DEVICE
135 join &operator=(const join &other) {
136 base_type::operator=(other);
137 return *this;
138 }
139};
140
141// deduction guides
142DETRAY_HOST_DEVICE_DEDUCTION_GUIDE join()
143 -> join<detray::ranges::views::empty<dvector<int>>>;
144
145template <detray::ranges::range R>
146DETRAY_HOST_DEVICE_DEDUCTION_GUIDE join(R &&ranges)
147 -> join<std::remove_reference_t<R>>;
148
149} // namespace views
150
151namespace detail {
152
159template <detray::ranges::range range_t>
163 std::conditional_t<std::is_const_v<range_t>,
164 detray::ranges::const_iterator_t<range_t>,
165 detray::ranges::iterator_t<range_t>>;
167 using outer_value_t = decltype(*std::declval<outer_iterator_t>());
169 using inner_iterator_t = std::conditional_t<
170 std::is_same_v<outer_iterator_t,
171 detray::ranges::const_iterator_t<range_t>>,
172 detray::ranges::const_iterator_t<outer_value_t>,
173 detray::ranges::iterator_t<outer_value_t>>;
174
178 using difference_type = std::iter_difference_t<iterator_t>;
180 using value_type = std::iter_value_t<iterator_t>;
182 using pointer = typename std::iterator_traits<iterator_t>::pointer;
184 using reference = std::iter_reference_t<iterator_t>;
187 typename std::iterator_traits<iterator_t>::iterator_category;
188
190 constexpr join_iterator() = default;
191
193 DETRAY_HOST_DEVICE
195 : m_outer_begin(begin), m_outer_end(end), m_outer_itr(begin) {
196 if (m_outer_itr != m_outer_end) {
197 m_inner_itr = (*m_outer_itr).begin();
198 } else {
199 m_inner_itr = {};
200 }
201 next_inner();
202 }
203
207 DETRAY_HOST_DEVICE auto operator++() -> join_iterator & {
208 ++m_inner_itr;
209 next_inner();
210
211 return *this;
212 }
213
216 DETRAY_HOST_DEVICE constexpr auto operator++(int) -> join_iterator {
217 auto tmp(*this);
218 ++(*this);
219 return tmp;
220 }
221
222
226 DETRAY_HOST_DEVICE constexpr auto operator--() -> join_iterator &
227 requires std::bidirectional_iterator<inner_iterator_t> &&
228 std::bidirectional_iterator<outer_iterator_t>
229 {
230 // If we are calling this at the end of the join iteration, go back into
231 // the valid range
232 if (m_outer_itr == m_outer_end) {
233 --m_outer_itr;
234 }
235
236 previous_inner();
237 --m_inner_itr;
238
239 return *this;
240 }
241
244 DETRAY_HOST_DEVICE constexpr auto operator--(int) -> join_iterator
245 requires std::bidirectional_iterator<inner_iterator_t> &&
246 std::bidirectional_iterator<outer_iterator_t>
247 {
248 auto tmp(*this);
249 --(*this);
250 return tmp;
251 }
252
253
255 DETRAY_HOST_DEVICE
256 constexpr decltype(auto) operator*() const { return *m_inner_itr; }
257
261 DETRAY_HOST_DEVICE constexpr auto operator+=(const difference_type j)
262 -> join_iterator &
263 requires std::random_access_iterator<inner_iterator_t> &&
264 std::random_access_iterator<outer_iterator_t>
265 {
266 // walk through join to catch the switch between intermediate ranges
267 if (difference_type i{j}; i >= difference_type{0}) {
268 while (i--) {
269 ++(*this);
270 }
271 } else {
272 while (i++) {
273 --(*this);
274 }
275 }
276 return *this;
277 }
278
282 DETRAY_HOST_DEVICE constexpr auto operator-=(const difference_type j)
283 -> join_iterator &
284 requires std::random_access_iterator<inner_iterator_t> &&
285 std::random_access_iterator<outer_iterator_t>
286 {
287 m_inner_itr += (-j);
288 return *this;
289 }
290
294 DETRAY_HOST_DEVICE constexpr decltype(auto) operator[](
295 const difference_type i) const
296 requires std::random_access_iterator<inner_iterator_t> &&
297 std::random_access_iterator<outer_iterator_t>
298 {
299 difference_type offset{i -
300 (m_inner_itr - detray::ranges::begin(*m_outer_itr))};
301 return *(*this + offset);
302 }
303
304 private:
306 DETRAY_HOST_DEVICE friend constexpr bool operator==(
307 const join_iterator &lhs, const join_iterator &rhs) {
308 return (lhs.m_inner_itr == rhs.m_inner_itr);
309 }
310
313 DETRAY_HOST_DEVICE friend constexpr bool operator!=(
314 const join_iterator &lhs, const join_iterator &rhs) {
315 return (lhs.m_outer_itr != rhs.m_outer_itr);
316 }
317
319 DETRAY_HOST_DEVICE friend constexpr auto operator<=>(const join_iterator &lhs,
320 const join_iterator &rhs)
321 requires detray::ranges::random_access_iterator<inner_iterator_t> &&
322 std::random_access_iterator<outer_iterator_t>
323 {
324#if defined(__apple_build_version__)
325 const auto l_o_itr{lhs.m_outer_itr};
326 const auto l_i_itr{lhs.m_inner_itr};
327 const auto r_o_itr{rhs.m_outer_itr};
328 const auto r_i_itr{rhs.m_inner_itr};
329 if (l_o_itr == r_o_itr) {
330 if (l_i_itr < r_i_itr || (l_i_itr == r_i_itr && l_i_itr < r_i_itr)) {
331 return std::strong_ordering::less;
332 }
333 if (l_i_itr > r_i_itr || (l_i_itr == r_i_itr && l_i_itr > r_i_itr)) {
334 return std::strong_ordering::greater;
335 }
336 return std::strong_ordering::equivalent;
337 } else {
338 if (l_o_itr < r_o_itr || (l_o_itr == r_o_itr && l_o_itr < r_o_itr)) {
339 return std::strong_ordering::less;
340 }
341 if (l_o_itr > r_o_itr || (l_o_itr == r_o_itr && l_o_itr > r_o_itr)) {
342 return std::strong_ordering::greater;
343 }
344 return std::strong_ordering::equivalent;
345 }
346#else
347 if (lhs.m_outer_itr == rhs.m_outer_itr) {
348 return lhs.m_inner_itr <=> rhs.m_inner_itr;
349 } else {
350 return lhs.m_outer_itr <=> rhs.m_outer_itr;
351 }
352#endif
353 }
354
359 DETRAY_HOST_DEVICE friend constexpr auto operator+(const join_iterator &itr,
360 const difference_type j)
362 requires std::random_access_iterator<inner_iterator_t> &&
363 std::random_access_iterator<outer_iterator_t>
364 {
365 join_iterator<range_t> tmp(itr);
366 // walk through join to catch the switch between intermediate ranges
367 if (difference_type i{j}; i >= difference_type{0}) {
368 while (i--) {
369 ++tmp;
370 }
371 } else {
372 while (i++) {
373 --tmp;
374 }
375 }
376 return tmp;
377 }
378
382 DETRAY_HOST_DEVICE friend constexpr auto operator+(const difference_type j,
383 const join_iterator &itr)
385 requires std::random_access_iterator<inner_iterator_t> &&
386 std::random_access_iterator<outer_iterator_t>
387 {
388 return itr + j;
389 }
390
395 DETRAY_HOST_DEVICE friend constexpr auto operator-(const join_iterator &itr,
396 const difference_type j)
398 requires std::random_access_iterator<inner_iterator_t> &&
399 std::random_access_iterator<outer_iterator_t>
400 {
401 return itr + (-j);
402 }
403
405 DETRAY_HOST_DEVICE friend constexpr auto operator-(const join_iterator &left,
406 const join_iterator &right)
408 requires std::random_access_iterator<inner_iterator_t> &&
409 std::random_access_iterator<outer_iterator_t>
410 {
411 const join_iterator lhs{left};
412 const join_iterator rhs{right};
413 outer_iterator_t tmp_outer_itr;
414
415 if (tmp_outer_itr == rhs.m_outer_itr) {
416 return lhs.m_inner_itr - rhs.m_inner_itr;
417 }
418 if ((tmp_outer_itr - rhs.m_outer_itr) < 0) {
419 // Negative distance
420 difference_type diff{lhs.m_inner_itr -
421 detray::ranges::end(*lhs.m_outer_itr)};
422 for (tmp_outer_itr + 1; tmp_outer_itr != rhs.m_outer_itr;
423 ++tmp_outer_itr) {
424 diff += detray::ranges::end(*tmp_outer_itr) -
425 detray::ranges::begin(*tmp_outer_itr);
426 }
427 diff += rhs.m_inner_itr - detray::ranges::end(*rhs.m_outer_itr);
428 return diff;
429 } else {
430 // Positive distance
431 difference_type diff{lhs.m_inner_itr -
432 detray::ranges::begin(*tmp_outer_itr)};
433 for (tmp_outer_itr - 1; tmp_outer_itr != rhs.m_outer_itr;
434 --tmp_outer_itr) {
435 diff += detray::ranges::end(*tmp_outer_itr) -
436 detray::ranges::begin(*tmp_outer_itr);
437 }
438 diff += rhs.m_inner_itr - detray::ranges::begin(*rhs.m_outer_itr);
439 return diff;
440 }
441 }
442
444 constexpr void next_inner() {
445 if (m_outer_itr == m_outer_end) {
446 return;
447 }
448 while (m_inner_itr == detray::ranges::end(*m_outer_itr)) {
449 ++m_outer_itr;
450 if (m_outer_itr != m_outer_end) {
451 m_inner_itr = (*m_outer_itr).begin();
452 } else {
453 break;
454 }
455 }
456 }
457
459 constexpr void previous_inner() {
460 // Get the start of the current inner range
461 inner_iterator_t inner_begin = detray::ranges::begin(*m_outer_itr);
462
463 // Iterator has reached last valid position in this range
464 // during the previous decrement. Now go to the end of the
465 // previous range
466 while (m_inner_itr == inner_begin) {
467 // No more inner ranges to try
468 if (m_outer_itr == m_outer_begin) {
469 m_inner_itr = detray::ranges::end(*m_outer_begin);
470 return;
471 }
472
473 --m_outer_itr;
474
475 inner_begin = detray::ranges::begin(*m_outer_itr);
476 m_inner_itr = detray::ranges::end(*m_outer_itr);
477 }
478 }
479
481 outer_iterator_t m_outer_begin{};
482 outer_iterator_t m_outer_end{};
484 outer_iterator_t m_outer_itr{};
486 inner_iterator_t m_inner_itr{};
487};
488
489} // namespace detail
490
491} // namespace detray::ranges
Defines a detray 'view'.
Definition ranges.hpp:190
Sequentially iterate through multiple ranges of the same type.
Definition join.hpp:160
constexpr auto operator++(int) -> join_iterator
Increment and return the iterator's previous position.
Definition join.hpp:216
inner_iterator_t iterator_t
Iterator type of the current inner range.
Definition join.hpp:176
std::iter_value_t< iterator_t > value_type
Value yielded by dereferencing the join iterator.
Definition join.hpp:180
friend constexpr bool operator!=(const join_iterator &lhs, const join_iterator &rhs)
Definition join.hpp:313
friend constexpr auto operator<=>(const join_iterator &lhs, const join_iterator &rhs)
Definition join.hpp:319
constexpr auto operator+=(const difference_type j) -> join_iterator &
Advance the joined iterator by j elements.
Definition join.hpp:261
constexpr auto operator-=(const difference_type j) -> join_iterator &
Retreat the joined iterator by j elements.
Definition join.hpp:282
friend constexpr auto operator+(const join_iterator &itr, const difference_type j) -> join_iterator
Return the iterator advanced by j elements through the joined ranges.
Definition join.hpp:359
std::conditional_t< std::is_same_v< outer_iterator_t, detray::ranges::const_iterator_t< range_t > >, detray::ranges::const_iterator_t< outer_value_t >, detray::ranges::iterator_t< outer_value_t > > inner_iterator_t
Iterator used to traverse each inner range.
Definition join.hpp:169
constexpr auto operator--(int) -> join_iterator
Decrement and return the iterator's previous position.
Definition join.hpp:244
friend constexpr auto operator-(const join_iterator &left, const join_iterator &right) -> difference_type
Definition join.hpp:405
constexpr join_iterator()=default
Default constructor required by LegacyIterator trait.
friend constexpr auto operator+(const difference_type j, const join_iterator &itr) -> join_iterator
Return the iterator advanced by j elements through the joined ranges.
Definition join.hpp:382
friend constexpr auto operator-(const join_iterator &itr, const difference_type j) -> join_iterator
Return the iterator retreated by j elements through the joined ranges.
Definition join.hpp:395
std::iter_reference_t< iterator_t > reference
Reference type yielded by the inner iterator.
Definition join.hpp:184
std::conditional_t< std::is_const_v< range_t >, detray::ranges::const_iterator_t< range_t >, detray::ranges::iterator_t< range_t > > outer_iterator_t
Iterator used to traverse the outer range of ranges.
Definition join.hpp:162
friend constexpr bool operator==(const join_iterator &lhs, const join_iterator &rhs)
Definition join.hpp:306
std::iter_difference_t< iterator_t > difference_type
Distance type of the inner iterator.
Definition join.hpp:178
constexpr join_iterator(outer_iterator_t begin, outer_iterator_t end)
Construct from range of ranges (.
Definition join.hpp:194
typename std::iterator_traits< iterator_t >::pointer pointer
Pointer type associated with the inner iterator.
Definition join.hpp:182
decltype(*std::declval< outer_iterator_t >()) outer_value_t
Reference type obtained from the outer iterator.
Definition join.hpp:167
constexpr auto operator--() -> join_iterator &
Decrement current iterator and check for switch between ranges.
Definition join.hpp:226
auto operator++() -> join_iterator &
Increment current iterator and check for switch between ranges.
Definition join.hpp:207
typename std::iterator_traits< iterator_t >::iterator_category iterator_category
Iterator category supported by the inner iterator.
Definition join.hpp:186
Range adaptor that joins different ranges of the same type (static).
Definition join.hpp:42
detray::ranges::iterator_t< outer_value_t > inner_iterator_t
Iterator over a single range.
Definition join.hpp:51
outer_iterator_t m_begin
Start and end position of the subranges.
Definition join.hpp:101
constexpr join_view()=default
Default constructor.
constexpr auto begin() const -> iterator_t
Definition join.hpp:71
constexpr auto end() const -> iterator_t
Definition join.hpp:75
std::iter_value_t< iterator_t > value_t
Element value type yielded by the joined view.
Definition join.hpp:56
constexpr join_view(R &&ranges)
Construct from a range of ranges.
Definition join.hpp:65
constexpr auto data() -> value_t *
Definition join.hpp:85
std::conditional_t< std::is_const_v< range_t >, const detray::ranges::range_value_t< range_t >, detray::ranges::range_value_t< range_t > > outer_value_t
Type of a single range.
Definition join.hpp:46
outer_iterator_t m_end
End iterator of the outer range.
Definition join.hpp:102
constexpr auto size() const noexcept -> std::size_t
Definition join.hpp:89
constexpr auto data() const -> const value_t *
Definition join.hpp:80
detray::ranges::detail::join_iterator< range_t > iterator_t
Iterator that walks across all nested ranges.
Definition join.hpp:54
detray::ranges::iterator_t< range_t > outer_iterator_t
Iterator over the range of ranges.
Definition join.hpp:44
detray::ranges::join_view< range_t > base_type
Base joined-range implementation.
Definition join.hpp:111
constexpr auto operator()(deduced_range_t &&ranges)
Call operator for range composition.
Definition join.hpp:126
join & operator=(const join &other)
Copy assignment operator.
Definition join.hpp:135
constexpr join(deduced_range_t &&ranges)
Construct the adaptor from the outer range of nested ranges.
Definition join.hpp:119