Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:59

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