Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-09 07:49:52

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 #include <concepts>
0012 #include <iterator>
0013 #include <ranges>
0014 #include <type_traits>
0015 #include <utility>
0016 
0017 namespace Acts::detail {
0018 
0019 template <typename Callable, typename iterator_t, bool force_const>
0020 struct TransformRangeIterator;
0021 
0022 /// This type implements a transforming range over a container.
0023 /// It functions like a view, where all element access is passed through
0024 /// a user-defined callable, that can process values, like dereferencing them
0025 /// or calling a specific method.
0026 ///
0027 /// @note The range and associated iterator maintain const-ness of the input,
0028 ///       i.e. if a const-qualified container is passed, the range and iterators
0029 ///       will not return any mutable references, even if they are mutable
0030 ///       themselves
0031 /// @note The range and iterator assume the the callables return references
0032 ///
0033 /// @tparam Callable The callable to apply to each element.
0034 /// @tparam container_t The container to wrap.
0035 template <typename Callable, typename container_t>
0036 struct TransformRange : public std::ranges::view_interface<
0037                             TransformRange<Callable, container_t>> {
0038  private:
0039   using internal_value_type = typename container_t::value_type;
0040 
0041   static_assert(std::is_reference_v<decltype(Callable::apply(
0042                     std::declval<internal_value_type>()))>,
0043                 "The callable must return a reference type");
0044 
0045   using raw_value_type = std::remove_reference_t<decltype(Callable::apply(
0046       std::declval<internal_value_type>()))>;
0047 
0048  public:
0049   /// The underlying value type that is returned by the range.
0050   /// If the input container has const-qualification, the range does
0051   /// not expose mutable values
0052   using value_type =
0053       std::conditional_t<std::is_const_v<container_t>,
0054                          std::add_const_t<raw_value_type>, raw_value_type>;
0055 
0056   using reference = value_type&;
0057   using const_reference = const value_type&;
0058 
0059   using iterator = TransformRangeIterator<
0060       Callable,
0061       std::conditional_t<std::is_const_v<container_t>,
0062                          typename container_t::const_iterator,
0063                          typename container_t::iterator>,
0064       std::is_const_v<container_t>>;
0065   using const_iterator =
0066       TransformRangeIterator<Callable, typename container_t::const_iterator,
0067                              true>;
0068 
0069   /// Construct a transforming range from a container. The first argument is
0070   /// only used for type-deduction
0071   /// @param container The container to wrap
0072   TransformRange(Callable&& /*callable*/, container_t& container)
0073       : m_container(&container) {}
0074 
0075   /// Construct a transforming range from a construct
0076   /// @param container The container to wrap
0077   explicit TransformRange(container_t& container) : m_container(&container) {}
0078 
0079   /// Access the i-th element of the underlying container, applying the
0080   /// callable
0081   /// @param i The index of the element to access
0082   /// @return Reference to the transformed i-th element
0083   reference operator[](std::size_t i) {
0084     return Callable::apply((*m_container)[i]);
0085   }
0086 
0087   /// Access the i-th element of the underlying container, applying the
0088   /// callable
0089   /// @param i The index of the element to access
0090   /// @return Const-reference to the transformed i-th element
0091   const_reference operator[](std::size_t i) const {
0092     return std::as_const(Callable::apply((*m_container)[i]));
0093   }
0094 
0095   /// Access the i-th element of the underlying container, applying the
0096   /// callable
0097   /// @param i The index of the element to access
0098   /// @return Reference to the transformed i-th element
0099   reference at(std::size_t i) { return Callable::apply(m_container->at(i)); }
0100 
0101   /// Access the i-th element of the underlying container, applying the
0102   /// callable
0103   /// @param i The index of the element to access
0104   /// @return Const-reference to the transformed i-th element
0105   const_reference at(std::size_t i) const {
0106     return std::as_const(Callable::apply(m_container->at(i)));
0107   }
0108 
0109   /// Return an iterator to the beginning of the underlying container
0110   /// @return Iterator to the beginning of the range
0111   iterator begin() { return iterator{m_container->begin()}; }
0112 
0113   /// Return an iterator past the end of the underlying container
0114   /// @return Iterator past the end of the range
0115   iterator end() { return iterator{m_container->end()}; }
0116 
0117   /// Return a const-iterator to the beginning of the underlying container
0118   /// @return Const-iterator to the beginning of the range
0119   const_iterator begin() const { return const_iterator{m_container->begin()}; }
0120 
0121   /// Return a const-iterator past the end of the underlying container
0122   /// @return Const-iterator past the end of the range
0123   const_iterator cbegin() const { return begin(); }
0124 
0125   /// Return a const-iterator to the beginning of the underlying container
0126   /// @return Const-iterator to the beginning of the range
0127   const_iterator end() const { return const_iterator{m_container->end()}; }
0128 
0129   /// Return a const-iterator past the end of the underlying container
0130   /// @return Const-iterator past the end of the range
0131   const_iterator cend() const { return end(); }
0132 
0133   /// Return the size of the underlying container
0134   /// @return The size of the underlying container
0135   std::size_t size() const { return m_container->size(); }
0136 
0137   /// Check if the underlying container is empty
0138   /// @return True if the underlying container is empty
0139   bool empty() const { return m_container->empty(); }
0140 
0141  private:
0142   container_t* m_container;
0143 };
0144 
0145 /// This type is associated with @c TransformRange and implements the iterator
0146 /// for the range. It applies the callable to the value that is dereferences.
0147 /// It also maintains const-ness, if instructed, by returning const references
0148 /// only.
0149 /// @tparam Callable The callable to apply to the value
0150 /// @tparam iterator_t The iterator type of the underlying container
0151 template <typename Callable, typename iterator_t, bool force_const>
0152 struct TransformRangeIterator {
0153  private:
0154   using internal_value_type = typename std::iter_value_t<iterator_t>;
0155 
0156   using raw_value_type = std::remove_reference_t<decltype(Callable::apply(
0157       std::declval<internal_value_type>()))>;
0158 
0159  public:
0160   /// The underlying value type that is returned by the iterator.
0161   /// If @c force_const is set to true, the iterator will only return
0162   /// const-qualified references
0163   using value_type =
0164       std::conditional_t<force_const, std::add_const_t<raw_value_type>,
0165                          raw_value_type>;
0166 
0167   using difference_type = typename std::iter_difference_t<iterator_t>;
0168   using pointer = std::remove_reference_t<value_type>*;
0169   using reference = value_type&;
0170   using iterator_category = std::forward_iterator_tag;
0171 
0172   /// Construct an iterator from an underlying iterator
0173   explicit TransformRangeIterator(iterator_t iterator) : m_iterator(iterator) {}
0174 
0175   TransformRangeIterator() = default;
0176 
0177   /// Return a reference to the value that is transformed by the callable
0178   /// @return Reference to the transformed value
0179   reference operator*() { return Callable::apply(*m_iterator); }
0180 
0181   /// Return a const-reference to the value that is transformed by the callable
0182   /// @return Const-reference to the transformed value
0183   reference operator*() const { return Callable::apply(*m_iterator); }
0184 
0185   /// Advance the iterator
0186   /// @return Reference to the iterator
0187   TransformRangeIterator& operator++() {
0188     ++m_iterator;
0189     return *this;
0190   }
0191 
0192   /// Advance the iterator
0193   /// @return Reference to the iterator
0194   TransformRangeIterator operator++(int) {
0195     auto tmp = *this;
0196     ++m_iterator;
0197     return tmp;
0198   }
0199 
0200   /// Equality operator between arbitrary iterators whose internal iterators are
0201   /// comparable. Needed for C++20 range interface
0202   template <typename I, bool F>
0203   bool operator==(const TransformRangeIterator<Callable, I, F>& other) const
0204     requires(std::equality_comparable_with<iterator_t, I>)
0205   {
0206     return m_iterator == other.m_iterator;
0207   }
0208 
0209   template <typename C, typename I, bool F>
0210   friend struct TransformRangeIterator;
0211 
0212  private:
0213   iterator_t m_iterator;
0214 };
0215 
0216 /// Callable that dereferences a value
0217 struct Dereference {
0218   template <typename input_t>
0219   constexpr static decltype(auto) apply(input_t&& value) {
0220     return *value;
0221   }
0222 };
0223 
0224 /// Callable that const-dereferences a value
0225 struct ConstDereference {
0226   template <typename input_t>
0227   constexpr static decltype(auto) apply(input_t&& value) {
0228     return std::as_const(*value);
0229   }
0230 };
0231 
0232 /// Callable that calls the @c get method of a value
0233 struct DotGet {
0234   template <typename input_t>
0235   constexpr static decltype(auto) apply(input_t&& value) {
0236     return value.get();
0237   }
0238 };
0239 
0240 }  // namespace Acts::detail
0241 
0242 /// @cond
0243 template <typename Callable, typename container_t>
0244 constexpr bool std::ranges::enable_borrowed_range<
0245     Acts::detail::TransformRange<Callable, container_t>> = true;
0246 /// @endcond