Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:12

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 <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 = typename std::iter_value_t<iterator_t>;
0152 
0153   using raw_value_type = std::remove_reference_t<decltype(Callable::apply(
0154       std::declval<internal_value_type>()))>;
0155 
0156  public:
0157   /// The underlying value type that is returned by the iterator.
0158   /// If @c force_const is set to true, the iterator will only return
0159   /// const-qualified references
0160   using value_type =
0161       std::conditional_t<force_const, std::add_const_t<raw_value_type>,
0162                          raw_value_type>;
0163 
0164   using difference_type = typename std::iter_difference_t<iterator_t>;
0165   using pointer = std::remove_reference_t<value_type>*;
0166   using reference = value_type&;
0167   using iterator_category = std::forward_iterator_tag;
0168 
0169   /// Construct an iterator from an underlying iterator
0170   explicit TransformRangeIterator(iterator_t iterator) : m_iterator(iterator) {}
0171 
0172   TransformRangeIterator() = default;
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   /// Advance the iterator
0190   /// @return Reference to the iterator
0191   TransformRangeIterator operator++(int) {
0192     auto tmp = *this;
0193     ++m_iterator;
0194     return tmp;
0195   }
0196 
0197   /// Compare two iterators for equality
0198   /// @param other The other iterator to compare to
0199   bool operator==(const TransformRangeIterator& other) const {
0200     return m_iterator == other.m_iterator;
0201   }
0202 
0203  private:
0204   iterator_t m_iterator;
0205 };
0206 
0207 /// Callable that dereferences a value
0208 struct Dereference {
0209   template <typename input_t>
0210   constexpr static decltype(auto) apply(input_t&& value) {
0211     return *value;
0212   }
0213 };
0214 
0215 /// Callable that const-dereferences a value
0216 struct ConstDereference {
0217   template <typename input_t>
0218   constexpr static decltype(auto) apply(input_t&& value) {
0219     return std::as_const(*value);
0220   }
0221 };
0222 
0223 /// Callable that calls the @c get method of a value
0224 struct DotGet {
0225   template <typename input_t>
0226   constexpr static decltype(auto) apply(input_t&& value) {
0227     return value.get();
0228   }
0229 };
0230 
0231 }  // namespace Acts::detail
0232 
0233 /// @cond
0234 template <typename Callable, typename container_t>
0235 constexpr bool std::ranges::enable_borrowed_range<
0236     Acts::detail::TransformRange<Callable, container_t>> = true;
0237 /// @endcond