Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 09:14:32

0001 /// \file ROOT/RRangeCast.hxx
0002 /// \ingroup Base StdExt
0003 /// \author Jonas Rembser <jonas.rembser@cern.ch>
0004 /// \date 2021-08-04
0005 
0006 /*************************************************************************
0007  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
0008  * All rights reserved.                                                  *
0009  *                                                                       *
0010  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0011  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0012  *************************************************************************/
0013 
0014 #ifndef ROOT_RRangeCast
0015 #define ROOT_RRangeCast
0016 
0017 #include "ROOT/RSpan.hxx"
0018 
0019 #include <cassert>
0020 #include <iterator>
0021 #include <type_traits>
0022 #include <utility>
0023 
0024 namespace ROOT {
0025 namespace Internal {
0026 
0027 template <typename T>
0028 struct RBaseType {
0029    using type = typename std::remove_pointer<typename std::decay<T>::type>::type;
0030 };
0031 
0032 // For SFINAE-based checks for the existence of the `begin` and `end` methods.
0033 template <typename T>
0034 constexpr auto hasBeginEnd(int) -> decltype(std::begin(std::declval<T>()), std::end(std::declval<T>()), true)
0035 {
0036    return true;
0037 }
0038 
0039 template <typename>
0040 constexpr bool hasBeginEnd(...)
0041 {
0042    return false;
0043 }
0044 
0045 template <typename T, typename WrappedIterator_t, bool isDynamic>
0046 class TypedIter {
0047 
0048 public:
0049    TypedIter(WrappedIterator_t const &iter) : fIter{iter} {}
0050 
0051    TypedIter &operator++()
0052    {
0053       ++fIter;
0054       return *this;
0055    }
0056    TypedIter operator++(int)
0057    {
0058       TypedIter tmp(*this);
0059       operator++();
0060       return tmp;
0061    }
0062    bool operator==(const TypedIter &rhs) const { return fIter == rhs.fIter; }
0063    bool operator!=(const TypedIter &rhs) const { return fIter != rhs.fIter; }
0064 
0065    void swap(TypedIter &other) { fIter.swap(other.fIter); }
0066 
0067    // We want to know at compile time whether dynamic_cast or static_cast is
0068    // used. First of all to avoid overhead, but also to avoid a compiler error
0069    // when using dynamic_cast on a non-polymorphic class.
0070    T operator*()
0071    {
0072       if constexpr (isDynamic) {
0073          return dynamic_cast<T>(*fIter);
0074       } else {
0075          if constexpr (std::is_polymorphic<RBaseType<T>>::value) {
0076             assert(dynamic_cast<T>(*fIter));
0077          }
0078          return static_cast<T>(*fIter);
0079       }
0080    }
0081 
0082 private:
0083    WrappedIterator_t fIter;
0084 };
0085 
0086 } // namespace Internal
0087 
0088 /// Wraps any collection that can be used in range-based loops and applies
0089 /// `static_cast<T>` or `dynamic_cast<T>` to each element.
0090 /// \tparam T The new type to convert to.
0091 /// \tparam isDynamic If `true`, `dynamic_cast` is used, otherwise `static_cast` is used.
0092 /// \tparam Range_t The type of the input range, which should be usually a reference type to avoid copying.
0093 template <typename T, bool isDynamic, typename Range_t>
0094 class RRangeCast {
0095 
0096 public:
0097    RRangeCast(Range_t &&inputRange) : fInputRange{inputRange}
0098    {
0099       static_assert(ROOT::Internal::hasBeginEnd<Range_t>(0),
0100                     "Type with no `begin` or `end` method passed to `RRangeCast`");
0101    }
0102 
0103    using const_iterator = Internal::TypedIter<T, decltype(std::cbegin(std::declval<Range_t>())), isDynamic>;
0104    const_iterator begin() const { return std::cbegin(fInputRange); }
0105    const_iterator end() const { return std::cend(fInputRange); }
0106 
0107    using iterator = Internal::TypedIter<T, decltype(std::begin(std::declval<Range_t>())), isDynamic>;
0108    iterator begin() { return std::begin(fInputRange); }
0109    iterator end() { return std::end(fInputRange); }
0110 
0111 private:
0112    Range_t fInputRange;
0113 };
0114 
0115 /// Takes any collection that can be used in range-based loops and applies
0116 /// static_cast<T> to each element. This function can be used for example to
0117 /// cast all objects in a RooAbsCollection when iterating over them.
0118 /// Example:
0119 /// ~~~{.cpp}
0120 /// class ClassA {
0121 /// public:
0122 ///    virtual ~ClassA() {}
0123 /// };
0124 /// class ClassB : public ClassA {
0125 /// };
0126 ///
0127 /// B b1, b2, b3;
0128 /// std::vector<A const*> vec{&b1, &b2, &b3};
0129 ///
0130 /// for(auto *b : ROOT::RangeStaticCast<B const*>(vec)) {
0131 ///    // do something with b
0132 /// }
0133 /// ~~~
0134 /// Make sure to not use `auto const&` in the range-based loop, as this will
0135 /// cause a range-loop-bind-reference warning with the clang compiler.
0136 template <typename T, typename Range_t>
0137 RRangeCast<T, false, Range_t> RangeStaticCast(Range_t &&coll)
0138 {
0139    return std::forward<Range_t>(coll);
0140 }
0141 // Overload for C-style arrays. It's not possible to make an overload of the
0142 // RRangeCast constructor itself, because when the C-style array is forwarded
0143 // it might decay depending on the compiler version.
0144 template <typename T, typename U, std::size_t N>
0145 RRangeCast<T, false, std::span<U>> RangeStaticCast(U (&arr)[N])
0146 {
0147    return std::span<U>(arr, arr + N);
0148 }
0149 
0150 /// Takes any collection that can be used in range-based loops and applies
0151 /// dynamic_cast<T> to each element. This function can be used for example to
0152 /// cast all objects in a RooAbsCollection when iterating over them.
0153 /// Example:
0154 /// ~~~{.cpp}
0155 ///
0156 /// class ClassA {
0157 /// public:
0158 ///    virtual ~ClassA() {}
0159 /// };
0160 /// class ClassB : public ClassA {
0161 /// };
0162 ///
0163 /// A a1, a2;
0164 /// B b1, b2, b3;
0165 /// std::vector<A const*> vec{&b1, &a1, &b2, &a2, &b3};
0166 ///
0167 /// for(auto *b : ROOT::RangeDynCast<B const*>(vec)) {
0168 ///    if(b) {
0169 ///       // do something with b
0170 ///    }
0171 /// }
0172 /// ~~~
0173 /// Make sure to not use `auto const&` in the range-based loop, as this will
0174 /// cause a range-loop-bind-reference warning with the clang compiler.
0175 template <typename T, typename Range_t>
0176 RRangeCast<T, true, Range_t> RangeDynCast(Range_t &&coll)
0177 {
0178    return std::forward<Range_t>(coll);
0179 }
0180 // Overload for C-style arrays. It's not possible to make an overload of the
0181 // RRangeCast constructor itself, because when the C-style array is forwarded
0182 // it might decay depending on the compiler version.
0183 template <typename T, typename U, std::size_t N>
0184 RRangeCast<T, true, std::span<U>> RangeDynCast(U (&arr)[N])
0185 {
0186    return std::span<U>(arr, arr + N);
0187 }
0188 
0189 } // namespace ROOT
0190 
0191 #endif