Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-27 07:24:04

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 // Project include(s)
0012 #include "detray/definitions/containers.hpp"
0013 #include "detray/definitions/detail/qualifiers.hpp"
0014 #include "detray/utils/ranges/empty.hpp"
0015 #include "detray/utils/ranges/ranges.hpp"
0016 #include "detray/utils/type_traits.hpp"
0017 
0018 // System include(s)
0019 #include <type_traits>
0020 
0021 namespace detray::ranges {
0022 
0023 namespace detail {
0024 
0025 template <detray::ranges::range T>
0026 struct join_iterator;
0027 
0028 }
0029 
0030 /// @brief Range adaptor that joins different ranges of the same type (static)
0031 ///
0032 /// @see https://en.cppreference.com/w/cpp/ranges/join_view
0033 ///
0034 /// @tparam range_t a range of the ranges that should be joined.
0035 ///
0036 /// @note Static implementation: The number of ranges needs to be know at
0037 /// compile time
0038 /// @note Does not take ownership of the ranges it operates on. Their lifetime
0039 /// needs to be guaranteed throughout iteration or between iterations with the
0040 /// same join instance.
0041 template <detray::ranges::range range_t>
0042 struct join_view : public detray::ranges::view_interface<join_view<range_t>> {
0043   /// Iterator over the range of ranges
0044   using outer_iterator_t = detray::ranges::iterator_t<range_t>;
0045   // Type of a single range
0046   using outer_value_t =
0047       std::conditional_t<std::is_const_v<range_t>,
0048                          const detray::ranges::range_value_t<range_t>,
0049                          detray::ranges::range_value_t<range_t>>;
0050   // Iterator over a single range
0051   using inner_iterator_t = detray::ranges::iterator_t<outer_value_t>;
0052 
0053   using iterator_t = detray::ranges::detail::join_iterator<range_t>;
0054   using value_t = std::iter_value_t<iterator_t>;
0055 
0056   /// Default constructor
0057   constexpr join_view() = default;
0058 
0059   /// Construct from a range of @param ranges.
0060   template <detray::ranges::range R>
0061     requires(!std::same_as<R, join_view>)
0062   DETRAY_HOST_DEVICE constexpr explicit join_view(R &&ranges)
0063       : m_begin{detray::ranges::begin(ranges)},
0064         m_end{detray::ranges::end(ranges)} {}
0065 
0066   /// @return start position of range - const
0067   DETRAY_HOST_DEVICE
0068   constexpr auto begin() const -> iterator_t { return {m_begin, m_end}; }
0069 
0070   /// @return sentinel of the range.
0071   DETRAY_HOST_DEVICE
0072   constexpr auto end() const -> iterator_t { return {m_end, m_end}; }
0073 
0074   /// @returns a pointer to the beginning of the data of the first underlying
0075   /// range - const
0076   DETRAY_HOST_DEVICE
0077   constexpr auto data() const -> const value_t * { return &(*(*m_begin)); }
0078 
0079   /// @returns a pointer to the beginning of the data of the first underlying
0080   /// range - non-const
0081   DETRAY_HOST_DEVICE
0082   constexpr auto data() -> value_t * { return &(*(*m_begin)); }
0083 
0084   /// @returns sum of the number elements of all ranges in the join
0085   DETRAY_HOST_DEVICE
0086   constexpr auto size() const noexcept -> std::size_t {
0087     std::size_t size{0u};
0088     for (outer_iterator_t itr = m_begin; itr != m_end; ++itr) {
0089       // subrange
0090       const auto begin = detray::ranges::begin(*itr);
0091       const auto end = detray::ranges::end(*itr);
0092       size += static_cast<std::size_t>(detray::ranges::distance(begin, end));
0093     }
0094     return size;
0095   }
0096 
0097   /// Start and end position of the subranges
0098   outer_iterator_t m_begin{};
0099   outer_iterator_t m_end{};
0100 };
0101 
0102 namespace views {
0103 
0104 /// @brief interface type to construct a @c join_view with CTAD
0105 template <detray::ranges::range range_t>
0106 struct join : public ranges::join_view<range_t> {
0107   using base_type = detray::ranges::join_view<range_t>;
0108 
0109   constexpr join() = default;
0110 
0111   template <detray::ranges::range deduced_range_t>
0112     requires(!std::same_as<deduced_range_t, join>)
0113   DETRAY_HOST_DEVICE constexpr explicit join(deduced_range_t &&ranges)
0114       : base_type(std::forward<deduced_range_t>(ranges)) {}
0115 
0116   /// Call operator for range composition
0117   template <detray::ranges::range deduced_range_t>
0118   DETRAY_HOST_DEVICE constexpr auto operator()(deduced_range_t &&ranges) {
0119     return detray::ranges::join_view<deduced_range_t>(
0120         std::forward<deduced_range_t>(ranges));
0121   }
0122 
0123   /// Copy assignment operator
0124   DETRAY_HOST_DEVICE
0125   join &operator=(const join &other) {
0126     base_type::operator=(other);
0127     return *this;
0128   }
0129 };
0130 
0131 // deduction guides
0132 DETRAY_HOST_DEVICE join() -> join<detray::ranges::views::empty<dvector<int>>>;
0133 
0134 template <detray::ranges::range R>
0135 DETRAY_HOST_DEVICE join(R &&ranges) -> join<std::remove_reference_t<R>>;
0136 
0137 }  // namespace views
0138 
0139 namespace detail {
0140 
0141 /// @brief Sequentially iterate through multiple ranges of the same type.
0142 ///
0143 /// Once the sentinel of one range is reached, set the current iterator to the
0144 /// next ranges 'begin' (or 'end' if decrementing)
0145 ///
0146 /// @tparam range_t a range that contains the ranges to be joined.
0147 template <detray::ranges::range range_t>
0148 struct join_iterator {
0149   using outer_iterator_t =
0150       std::conditional_t<std::is_const_v<range_t>,
0151                          detray::ranges::const_iterator_t<range_t>,
0152                          detray::ranges::iterator_t<range_t>>;
0153   using outer_value_t = decltype(*std::declval<outer_iterator_t>());
0154   using inner_iterator_t = std::conditional_t<
0155       std::is_same_v<outer_iterator_t,
0156                      detray::ranges::const_iterator_t<range_t>>,
0157       detray::ranges::const_iterator_t<outer_value_t>,
0158       detray::ranges::iterator_t<outer_value_t>>;
0159 
0160   using iterator_t = inner_iterator_t;
0161   using difference_type = std::iter_difference_t<iterator_t>;
0162   using value_type = std::iter_value_t<iterator_t>;
0163   using pointer = typename std::iterator_traits<iterator_t>::pointer;
0164   using reference = std::iter_reference_t<iterator_t>;
0165   using iterator_category =
0166       typename std::iterator_traits<iterator_t>::iterator_category;
0167 
0168   /// Default constructor required by LegacyIterator trait
0169   constexpr join_iterator() = default;
0170 
0171   /// Construct from range of ranges ( @param begin and @param  end )
0172   DETRAY_HOST_DEVICE
0173   constexpr join_iterator(outer_iterator_t begin, outer_iterator_t end)
0174       : m_outer_begin(begin), m_outer_end(end), m_outer_itr(begin) {
0175     if (m_outer_itr != m_outer_end) {
0176       m_inner_itr = (*m_outer_itr).begin();
0177     } else {
0178       m_inner_itr = {};
0179     }
0180     next_inner();
0181   }
0182 
0183   /// Increment current iterator and check for switch between ranges.
0184   /// @{
0185   DETRAY_HOST_DEVICE auto operator++() -> join_iterator & {
0186     ++m_inner_itr;
0187     next_inner();
0188 
0189     return *this;
0190   }
0191 
0192   DETRAY_HOST_DEVICE constexpr auto operator++(int) -> join_iterator {
0193     auto tmp(*this);
0194     ++(*this);
0195     return tmp;
0196   }
0197   /// @}
0198 
0199   /// Decrement current iterator and check for switch between ranges.
0200   /// @{
0201   DETRAY_HOST_DEVICE constexpr auto operator--() -> join_iterator &
0202     requires std::bidirectional_iterator<inner_iterator_t> &&
0203              std::bidirectional_iterator<outer_iterator_t>
0204   {
0205     // If we are calling this at the end of the join iteration, go back into
0206     // the valid range
0207     if (m_outer_itr == m_outer_end) {
0208       --m_outer_itr;
0209     }
0210 
0211     previous_inner();
0212     --m_inner_itr;
0213 
0214     return *this;
0215   }
0216 
0217   DETRAY_HOST_DEVICE constexpr auto operator--(int) -> join_iterator
0218     requires std::bidirectional_iterator<inner_iterator_t> &&
0219              std::bidirectional_iterator<outer_iterator_t>
0220   {
0221     auto tmp(*this);
0222     --(*this);
0223     return tmp;
0224   }
0225   /// @}
0226 
0227   /// @returns the single value that the iterator points to - const
0228   DETRAY_HOST_DEVICE
0229   constexpr decltype(auto) operator*() const { return *m_inner_itr; }
0230 
0231   /// @returns advance this iterator state by @param j.
0232   DETRAY_HOST_DEVICE constexpr auto operator+=(const difference_type j)
0233       -> join_iterator &
0234     requires std::random_access_iterator<inner_iterator_t> &&
0235              std::random_access_iterator<outer_iterator_t>
0236   {
0237     // walk through join to catch the switch between intermediate ranges
0238     if (difference_type i{j}; i >= difference_type{0}) {
0239       while (i--) {
0240         ++(*this);
0241       }
0242     } else {
0243       while (i++) {
0244         --(*this);
0245       }
0246     }
0247     return *this;
0248   }
0249 
0250   /// @returns advance this iterator state by @param j.
0251   DETRAY_HOST_DEVICE constexpr auto operator-=(const difference_type j)
0252       -> join_iterator &
0253     requires std::random_access_iterator<inner_iterator_t> &&
0254              std::random_access_iterator<outer_iterator_t>
0255   {
0256     m_inner_itr += (-j);
0257     return *this;
0258   }
0259 
0260   /// @returns the value at a given position - const
0261   DETRAY_HOST_DEVICE constexpr decltype(auto) operator[](
0262       const difference_type i) const
0263     requires std::random_access_iterator<inner_iterator_t> &&
0264              std::random_access_iterator<outer_iterator_t>
0265   {
0266     difference_type offset{i -
0267                            (m_inner_itr - detray::ranges::begin(*m_outer_itr))};
0268     return *(*this + offset);
0269   }
0270 
0271  private:
0272   /// @returns true if it points to the same value.
0273   DETRAY_HOST_DEVICE friend constexpr bool operator==(
0274       const join_iterator &lhs, const join_iterator &rhs) {
0275     return (lhs.m_inner_itr == rhs.m_inner_itr);
0276   }
0277 
0278   /// @returns false if it points to the same value (usually the global
0279   /// sentinel of the join).
0280   DETRAY_HOST_DEVICE friend constexpr bool operator!=(
0281       const join_iterator &lhs, const join_iterator &rhs) {
0282     return (lhs.m_outer_itr != rhs.m_outer_itr);
0283   }
0284 
0285   /// @returns relation according to comparison operators
0286   DETRAY_HOST_DEVICE friend constexpr auto operator<=>(const join_iterator &lhs,
0287                                                        const join_iterator &rhs)
0288     requires detray::ranges::random_access_iterator<inner_iterator_t> &&
0289              std::random_access_iterator<outer_iterator_t>
0290   {
0291 #if defined(__apple_build_version__)
0292     const auto l_o_itr{lhs.m_outer_itr};
0293     const auto l_i_itr{lhs.m_inner_itr};
0294     const auto r_o_itr{rhs.m_outer_itr};
0295     const auto r_i_itr{rhs.m_inner_itr};
0296     if (l_o_itr == r_o_itr) {
0297       if (l_i_itr < r_i_itr || (l_i_itr == r_i_itr && l_i_itr < r_i_itr)) {
0298         return std::strong_ordering::less;
0299       }
0300       if (l_i_itr > r_i_itr || (l_i_itr == r_i_itr && l_i_itr > r_i_itr)) {
0301         return std::strong_ordering::greater;
0302       }
0303       return std::strong_ordering::equivalent;
0304     } else {
0305       if (l_o_itr < r_o_itr || (l_o_itr == r_o_itr && l_o_itr < r_o_itr)) {
0306         return std::strong_ordering::less;
0307       }
0308       if (l_o_itr > r_o_itr || (l_o_itr == r_o_itr && l_o_itr > r_o_itr)) {
0309         return std::strong_ordering::greater;
0310       }
0311       return std::strong_ordering::equivalent;
0312     }
0313 #else
0314     if (lhs.m_outer_itr == rhs.m_outer_itr) {
0315       return lhs.m_inner_itr <=> rhs.m_inner_itr;
0316     } else {
0317       return lhs.m_outer_itr <=> rhs.m_outer_itr;
0318     }
0319 #endif
0320   }
0321 
0322   /// @returns an iterator advanced by @param j through the join.
0323   DETRAY_HOST_DEVICE friend constexpr auto operator+(const join_iterator &itr,
0324                                                      const difference_type j)
0325       -> join_iterator
0326     requires std::random_access_iterator<inner_iterator_t> &&
0327              std::random_access_iterator<outer_iterator_t>
0328   {
0329     join_iterator<range_t> tmp(itr);
0330     // walk through join to catch the switch between intermediate ranges
0331     if (difference_type i{j}; i >= difference_type{0}) {
0332       while (i--) {
0333         ++tmp;
0334       }
0335     } else {
0336       while (i++) {
0337         --tmp;
0338       }
0339     }
0340     return tmp;
0341   }
0342   /// @returns an iterator advanced by @param j through the join.
0343   DETRAY_HOST_DEVICE friend constexpr auto operator+(const difference_type j,
0344                                                      const join_iterator &itr)
0345       -> join_iterator
0346     requires std::random_access_iterator<inner_iterator_t> &&
0347              std::random_access_iterator<outer_iterator_t>
0348   {
0349     return itr + j;
0350   }
0351 
0352   /// @returns an iterator advanced by @param j through the join.
0353   DETRAY_HOST_DEVICE friend constexpr auto operator-(const join_iterator &itr,
0354                                                      const difference_type j)
0355       -> join_iterator
0356     requires std::random_access_iterator<inner_iterator_t> &&
0357              std::random_access_iterator<outer_iterator_t>
0358   {
0359     return itr + (-j);
0360   }
0361 
0362   /// @returns the positional difference between two iterators
0363   DETRAY_HOST_DEVICE friend constexpr auto operator-(const join_iterator &left,
0364                                                      const join_iterator &right)
0365       -> difference_type
0366     requires std::random_access_iterator<inner_iterator_t> &&
0367              std::random_access_iterator<outer_iterator_t>
0368   {
0369     const join_iterator lhs{left};
0370     const join_iterator rhs{right};
0371     outer_iterator_t tmp_outer_itr;
0372 
0373     if (tmp_outer_itr == rhs.m_outer_itr) {
0374       return lhs.m_inner_itr - rhs.m_inner_itr;
0375     }
0376     if ((tmp_outer_itr - rhs.m_outer_itr) < 0) {
0377       // Negative distance
0378       difference_type diff{lhs.m_inner_itr -
0379                            detray::ranges::end(*lhs.m_outer_itr)};
0380       for (tmp_outer_itr + 1; tmp_outer_itr != rhs.m_outer_itr;
0381            ++tmp_outer_itr) {
0382         diff += detray::ranges::end(*tmp_outer_itr) -
0383                 detray::ranges::begin(*tmp_outer_itr);
0384       }
0385       diff += rhs.m_inner_itr - detray::ranges::end(*rhs.m_outer_itr);
0386       return diff;
0387     } else {
0388       // Positive distance
0389       difference_type diff{lhs.m_inner_itr -
0390                            detray::ranges::begin(*tmp_outer_itr)};
0391       for (tmp_outer_itr - 1; tmp_outer_itr != rhs.m_outer_itr;
0392            --tmp_outer_itr) {
0393         diff += detray::ranges::end(*tmp_outer_itr) -
0394                 detray::ranges::begin(*tmp_outer_itr);
0395       }
0396       diff += rhs.m_inner_itr - detray::ranges::begin(*rhs.m_outer_itr);
0397       return diff;
0398     }
0399   }
0400 
0401   /// Find the first inner range that is not empty
0402   constexpr void next_inner() {
0403     if (m_outer_itr == m_outer_end) {
0404       return;
0405     }
0406     while (m_inner_itr == detray::ranges::end(*m_outer_itr)) {
0407       ++m_outer_itr;
0408       if (m_outer_itr != m_outer_end) {
0409         m_inner_itr = (*m_outer_itr).begin();
0410       } else {
0411         break;
0412       }
0413     }
0414   }
0415 
0416   /// Find the last inner range that is not empty
0417   constexpr void previous_inner() {
0418     // Get the start of the current inner range
0419     inner_iterator_t inner_begin = detray::ranges::begin(*m_outer_itr);
0420 
0421     // Iterator has reached last valid position in this range
0422     // during the previous decrement. Now go to the end of the
0423     // previous range
0424     while (m_inner_itr == inner_begin) {
0425       // No more inner ranges to try
0426       if (m_outer_itr == m_outer_begin) {
0427         m_inner_itr = detray::ranges::end(*m_outer_begin);
0428         return;
0429       }
0430 
0431       --m_outer_itr;
0432 
0433       inner_begin = detray::ranges::begin(*m_outer_itr);
0434       m_inner_itr = detray::ranges::end(*m_outer_itr);
0435     }
0436   }
0437 
0438   /// Global range collection begin and end (outer iterators)
0439   outer_iterator_t m_outer_begin{};
0440   outer_iterator_t m_outer_end{};
0441   /// Current range
0442   outer_iterator_t m_outer_itr{};
0443   /// Current iterators over the inner ranges
0444   inner_iterator_t m_inner_itr{};
0445 };
0446 
0447 }  // namespace detail
0448 
0449 }  // namespace detray::ranges