Back to home page

EIC code displayed by LXR

 
 

    


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

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/ranges.hpp"
0015 #include "detray/utils/type_traits.hpp"
0016 
0017 // System include(s)
0018 #include <type_traits>
0019 
0020 namespace detray::ranges {
0021 
0022 namespace detail {
0023 
0024 template <detray::ranges::range T>
0025   requires std::input_iterator<detray::detail::get_value_t<T>>
0026 struct static_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 I the number of ranges in the join.
0035 /// @tparam range_itr_t the iterator type of the ranges.
0036 ///
0037 /// @note Static implementation: The number of ranges needs to be know at
0038 /// compile time
0039 /// @note Does not take ownership of the ranges it operates on. Their lifetime
0040 /// needs to be guaranteed throughout iteration or between iterations with the
0041 /// same join instance.
0042 /// @note Is not fit for lazy evaluation.
0043 /// @todo improve performance of e.g. @c operator+ and @c operator+=
0044 template <std::size_t I, std::input_iterator range_itr_t>
0045 struct static_join_view
0046     : public detray::ranges::view_interface<static_join_view<I, range_itr_t>> {
0047   using iterator_coll_t = darray<range_itr_t, I>;
0048   using iterator_t =
0049       detray::ranges::detail::static_join_iterator<iterator_coll_t>;
0050   using value_t = std::iter_value_t<iterator_t>;
0051 
0052   /// Default constructor
0053   constexpr static_join_view() = default;
0054 
0055   /// Construct from a pack of @param ranges.
0056   template <detray::ranges::range... ranges_t>
0057     requires((sizeof...(ranges_t) > 1) ||
0058              ((!std::same_as<static_join_view, ranges_t>) && ...))
0059   DETRAY_HOST_DEVICE constexpr explicit static_join_view(ranges_t &&...ranges)
0060       : m_begins{detray::ranges::begin(std::forward<ranges_t>(ranges))...},
0061         m_ends{detray::ranges::end(std::forward<ranges_t>(ranges))...} {}
0062 
0063   /// Construct from a pack of @param ranges - const
0064   template <detray::ranges::range... ranges_t>
0065   DETRAY_HOST_DEVICE constexpr explicit static_join_view(
0066       const ranges_t &...ranges)
0067       : m_begins{detray::ranges::cbegin(ranges)...},
0068         m_ends{detray::ranges::cend(ranges)...} {}
0069 
0070   /// @return start position of range - const
0071   DETRAY_HOST_DEVICE
0072   constexpr auto begin() const -> iterator_t { return {m_begins, m_ends}; }
0073 
0074   /// @return sentinel of the range.
0075   DETRAY_HOST_DEVICE
0076   constexpr auto end() const -> iterator_t {
0077     // Build a joined itr from the last value in the iterator collection
0078     return {m_begins, m_ends, detray::detail::get<I - 1>(m_ends), I - 1};
0079   }
0080 
0081   /// @returns a pointer to the beginning of the data of the first underlying
0082   /// range - const
0083   DETRAY_HOST_DEVICE
0084   constexpr auto data() const -> const value_t * {
0085     return &(*(detray::detail::get<0>(m_begins())));
0086   }
0087 
0088   /// @returns a pointer to the beginning of the data of the first underlying
0089   /// range - non-const
0090   DETRAY_HOST_DEVICE
0091   constexpr auto data() -> value_t * {
0092     return &(*(detray::detail::get<0>(m_begins())));
0093   }
0094 
0095   /// @returns sum of the number elements of all ranges in the join
0096   DETRAY_HOST_DEVICE
0097   constexpr auto size() const noexcept -> std::size_t {
0098     std::size_t size{0};
0099     for (std::size_t i{0}; i < I; ++i) {
0100       const range_itr_t &begin = m_begins[i];
0101       const range_itr_t &end = m_ends[i];
0102       size += static_cast<std::size_t>(detray::ranges::distance(begin, end));
0103     }
0104     return size;
0105   }
0106 
0107   /// Start and end position of the subranges
0108   iterator_coll_t m_begins{};
0109   iterator_coll_t m_ends{};
0110 };
0111 
0112 namespace views {
0113 
0114 /// @brief interface type to construct a @c static_join_view with CTAD
0115 template <std::size_t I, std::input_iterator range_itr_t>
0116 struct static_join : public ranges::static_join_view<I, range_itr_t> {
0117   using base_type = ranges::static_join_view<I, range_itr_t>;
0118 
0119   constexpr static_join() = default;
0120 
0121   template <detray::ranges::range... ranges_t>
0122     requires((sizeof...(ranges_t) > 1) ||
0123              ((!std::same_as<static_join, ranges_t>) && ...))
0124   DETRAY_HOST_DEVICE constexpr explicit static_join(ranges_t &&...ranges)
0125       : base_type(std::forward<ranges_t>(ranges)...) {}
0126 };
0127 
0128 // deduction guides
0129 template <detray::ranges::range... ranges_t>
0130 DETRAY_HOST_DEVICE static_join(ranges_t &&...ranges)
0131     -> static_join<sizeof...(ranges_t),
0132                    typename detray::ranges::iterator_t<detray::detail::first_t<
0133                        std::remove_reference_t<ranges_t>...>>>;
0134 
0135 }  // namespace views
0136 
0137 namespace detail {
0138 
0139 /// @brief Sequentially iterate through multiple ranges of the same type.
0140 ///
0141 /// Once the sentinel of one range is reached, set the current iterator to the
0142 /// next ranges 'begin' (or 'end' if decrementing)
0143 ///
0144 /// @tparam iterator_coll_t type of iterator collection of ranges to be joined.
0145 ///         Can contain const iterators.
0146 ///
0147 /// @note The iterator must not be typed on the current range index, so that
0148 /// begin and sentinel type are the same.
0149 template <detray::ranges::range iterator_coll_t>
0150   requires std::input_iterator<detray::detail::get_value_t<iterator_coll_t>>
0151 struct static_join_iterator {
0152   using iterator_t = detray::detail::get_value_t<iterator_coll_t>;
0153 
0154   using difference_type = std::iter_difference_t<iterator_t>;
0155   using value_type = std::iter_value_t<iterator_t>;
0156   using pointer = typename std::iterator_traits<iterator_t>::pointer;
0157   using reference = std::iter_reference_t<iterator_t>;
0158   using iterator_category =
0159       typename std::iterator_traits<iterator_t>::iterator_category;
0160 
0161   /// Default constructor required by LegacyIterator trait
0162   constexpr static_join_iterator() = default;
0163 
0164   /// Construct from a collection of @param begin and @param  end positions
0165   DETRAY_HOST_DEVICE
0166   constexpr static_join_iterator(const iterator_coll_t &begins,
0167                                  const iterator_coll_t &ends)
0168       : m_begins(&begins), m_ends(&ends), m_iter{(*m_begins)[0]} {}
0169 
0170   /// Fully parametrized construction
0171   DETRAY_HOST_DEVICE
0172   constexpr static_join_iterator(const iterator_coll_t &begins,
0173                                  const iterator_coll_t &ends,
0174                                  iterator_t current, const std::size_t i)
0175       : m_begins(&begins), m_ends(&ends), m_iter{current}, m_idx{i} {}
0176 
0177   /// Increment current iterator and check for switch between ranges.
0178   /// @{
0179   DETRAY_HOST_DEVICE constexpr auto operator++() -> static_join_iterator & {
0180     ++m_iter;
0181     // Switch to next range in the collection
0182     if (constexpr std::size_t max_idx{
0183             sizeof(iterator_coll_t) / sizeof(iterator_t) - 1u};
0184         (m_iter == (*m_ends)[m_idx]) && (m_idx < max_idx)) {
0185       ++m_idx;
0186       m_iter = (*m_begins)[m_idx];
0187     }
0188     return *this;
0189   }
0190 
0191   DETRAY_HOST_DEVICE constexpr auto operator++(int) -> static_join_iterator {
0192     auto tmp(*this);
0193     ++(*this);
0194     return tmp;
0195   }
0196   /// @}
0197 
0198   /// Decrement current iterator and check for switch between ranges.
0199   /// @{
0200   DETRAY_HOST_DEVICE constexpr auto operator--() -> static_join_iterator &
0201     requires std::bidirectional_iterator<iterator_t>
0202   {
0203     if (m_iter != (*m_begins)[m_idx]) {
0204       // Normal case
0205       --m_iter;
0206     } else if (m_idx > 0u) {
0207       // Iterator has reached last valid position in this range during the
0208       // previous decrement. Now go to the end of the previous range
0209       --m_idx;
0210       m_iter = detray::ranges::prev((*m_ends)[m_idx]);
0211     }
0212     return *this;
0213   }
0214   /// @}
0215 
0216   DETRAY_HOST_DEVICE constexpr auto operator--(int) -> static_join_iterator
0217     requires std::bidirectional_iterator<iterator_t>
0218   {
0219     auto tmp(*this);
0220     ++(*this);
0221     return tmp;
0222   }
0223 
0224   /// @returns the single value that the iterator points to.
0225   DETRAY_HOST_DEVICE
0226   constexpr auto operator*() const -> decltype(auto) { return *m_iter; }
0227 
0228   /// @returns advance this iterator state by @param j.
0229   DETRAY_HOST_DEVICE constexpr auto operator+=(const difference_type j)
0230       -> static_join_iterator &
0231     requires std::random_access_iterator<iterator_t>
0232   {
0233     // walk through join to catch the switch between intermediate ranges
0234     if (difference_type i{j}; i >= difference_type{0}) {
0235       while (i--) {
0236         ++(*this);
0237       }
0238     } else {
0239       while (i++) {
0240         --(*this);
0241       }
0242     }
0243     return *this;
0244   }
0245 
0246   /// @returns advance this iterator state by @param j.
0247   DETRAY_HOST_DEVICE constexpr auto operator-=(const difference_type j)
0248       -> static_join_iterator &
0249     requires std::random_access_iterator<iterator_t>
0250   {
0251     m_iter += (-j);
0252     return *this;
0253   }
0254 
0255   /// @returns the value at a given position - const
0256   DETRAY_HOST_DEVICE constexpr decltype(auto) operator[](
0257       const difference_type i) const
0258     requires std::random_access_iterator<iterator_t>
0259   {
0260     difference_type offset{i - (m_iter - (*m_begins)[0])};
0261     return *(*this + offset);
0262   }
0263 
0264  private:
0265   /// @returns true if it points to the same value.
0266   DETRAY_HOST_DEVICE friend constexpr bool operator==(
0267       const static_join_iterator &lhs, const static_join_iterator &rhs) {
0268     return (lhs.m_iter == rhs.m_iter);
0269   }
0270 
0271   /// @returns decision of comparison operators
0272   DETRAY_HOST_DEVICE friend constexpr auto operator<=>(
0273       const static_join_iterator &lhs, const static_join_iterator &rhs)
0274     requires std::random_access_iterator<iterator_t>
0275   {
0276 #if defined(__apple_build_version__)
0277     const auto l{lhs.m_iter};
0278     const auto r{rhs.m_iter};
0279     if (l < r || (l == r && l < r)) {
0280       return std::strong_ordering::less;
0281     }
0282     if (l > r || (l == r && l > r)) {
0283       return std::strong_ordering::greater;
0284     }
0285     return std::strong_ordering::equivalent;
0286 #else
0287     return (lhs.m_iter <=> rhs.m_iter);
0288 #endif
0289   }
0290 
0291   /// @returns an iterator advanced by @param j through the join.
0292   DETRAY_HOST_DEVICE friend constexpr auto operator+(
0293       const static_join_iterator &itr, const difference_type j)
0294       -> static_join_iterator
0295     requires std::random_access_iterator<iterator_t>
0296   {
0297     static_join_iterator<iterator_coll_t> tmp(itr);
0298     // walk through join to catch the switch between intermediate ranges
0299     if (difference_type i{j}; i >= 0) {
0300       while (i--) {
0301         ++tmp;
0302       }
0303     } else {
0304       while (i++) {
0305         --tmp;
0306       }
0307     }
0308     return tmp;
0309   }
0310 
0311   /// @returns an iterator advanced by @param j through the join.
0312   DETRAY_HOST_DEVICE friend constexpr auto operator+(
0313       const difference_type j, const static_join_iterator &itr)
0314       -> static_join_iterator
0315     requires std::random_access_iterator<iterator_t>
0316   {
0317     return itr + j;
0318   }
0319 
0320   /// @returns an iterator advanced by @param j through the join.
0321   DETRAY_HOST_DEVICE friend constexpr auto operator-(
0322       const static_join_iterator &itr, const difference_type j)
0323       -> static_join_iterator
0324     requires std::random_access_iterator<iterator_t>
0325   {
0326     return itr + (-j);
0327   }
0328 
0329   /// @returns the positional difference between two iterators
0330   DETRAY_HOST_DEVICE friend constexpr auto operator-(
0331       const static_join_iterator &lhs, const static_join_iterator &rhs)
0332       -> difference_type
0333     requires std::random_access_iterator<iterator_t>
0334   {
0335     const static_join_iterator l{lhs};
0336     const static_join_iterator r{rhs};
0337 
0338     if (l.m_idx == r.m_idx) {
0339       return l.m_iter - r.m_iter;
0340     }
0341     if (l.m_idx < r.m_idx) {
0342       // Negative distance
0343       difference_type diff{l.m_iter - (*l.m_ends)[l.m_idx]};
0344       for (std::size_t i{l.m_idx + 1u}; i < r.m_idx; ++i) {
0345         diff += (*l.m_begins)[i] - (*l.m_ends)[i];
0346       }
0347       diff += (*r.m_begins)[l.m_idx] - r.m_iter;
0348       return diff;
0349     } else {
0350       // Positive distance
0351       difference_type diff{l.m_iter - (*l.m_begins)[l.m_idx]};
0352       for (std::size_t i{l.m_idx - 1u}; i > r.m_idx; --i) {
0353         diff += (*l.m_ends)[i] - (*l.m_begins)[i];
0354       }
0355       diff += (*r.m_ends)[r.m_idx] - r.m_iter;
0356       return diff;
0357     }
0358   }
0359 
0360   /// Global range collection of begin and end iterators
0361   const iterator_coll_t *m_begins{nullptr};
0362   const iterator_coll_t *m_ends{nullptr};
0363   /// This is the actual iterator state that will be advanced during iteration
0364   iterator_t m_iter{};
0365   /// Index of the current range in the join
0366   std::size_t m_idx{0};
0367 };
0368 
0369 }  // namespace detail
0370 
0371 }  // namespace detray::ranges