Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:22:39

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 #if (__cplusplus < 201700L)
0033 
0034 template <typename T, bool isDynamic = true, bool isPolymorphic = std::is_polymorphic<RBaseType<T>>::value>
0035 struct RCast {
0036    template <typename U>
0037    static T cast(U &&u)
0038    {
0039       return dynamic_cast<T>(u);
0040    }
0041 };
0042 
0043 template <typename T>
0044 struct RCast<T, false, false> {
0045    template <typename U>
0046    static T cast(U &&u)
0047    {
0048       return static_cast<T>(u);
0049    }
0050 };
0051 
0052 template <typename T>
0053 struct RCast<T, false, true> {
0054    template <typename U>
0055    static T cast(U &&u)
0056    {
0057       assert(dynamic_cast<T>(u));
0058       return static_cast<T>(u);
0059    }
0060 };
0061 
0062 #endif
0063 
0064 // For SFINAE-based checks for the existence of the `begin` and `end` methods.
0065 template <typename T>
0066 constexpr auto hasBeginEnd(int) -> decltype(std::begin(std::declval<T>()), std::end(std::declval<T>()), true)
0067 {
0068    return true;
0069 }
0070 
0071 template <typename>
0072 constexpr bool hasBeginEnd(...)
0073 {
0074    return false;
0075 }
0076 
0077 template <typename T, typename WrappedIterator_t, bool isDynamic>
0078 class TypedIter {
0079 
0080 public:
0081    TypedIter(WrappedIterator_t const &iter) : fIter{iter} {}
0082 
0083    TypedIter &operator++()
0084    {
0085       ++fIter;
0086       return *this;
0087    }
0088    TypedIter operator++(int)
0089    {
0090       TypedIter tmp(*this);
0091       operator++();
0092       return tmp;
0093    }
0094    bool operator==(const TypedIter &rhs) const { return fIter == rhs.fIter; }
0095    bool operator!=(const TypedIter &rhs) const { return fIter != rhs.fIter; }
0096 
0097    void swap(TypedIter &other) { fIter.swap(other.fIter); }
0098 
0099    // We want to know at compile time whether dynamic_cast or static_cast is
0100    // used. First of all to avoid overhead, but also to avoid a compiler
0101    // error when using dynamic_cast on a non-polymorphic class. In C++17,
0102    // this can be done easily with `if constexpr`, but for the older
0103    // standards we have to use a more verbose alternative. Both ways are
0104    // explicitely implemented for different standards, so that when the
0105    // minimum C++ standard for ROOT is raised to C++17 it's easy to remember
0106    // that we can avoid much boilerplate code in this file.
0107 #if (__cplusplus < 201700L)
0108    T operator*() { return ROOT::Internal::RCast<T, isDynamic>::cast(*fIter); }
0109 #else
0110    T operator*()
0111    {
0112       if constexpr (isDynamic) {
0113          return dynamic_cast<T>(*fIter);
0114       } else {
0115          if constexpr (std::is_polymorphic<RBaseType<T>>::value) {
0116             assert(dynamic_cast<T>(*fIter));
0117          }
0118          return static_cast<T>(*fIter);
0119       }
0120    }
0121 #endif
0122 
0123 private:
0124    WrappedIterator_t fIter;
0125 };
0126 
0127 } // namespace Internal
0128 
0129 /// Wraps any collection that can be used in range-based loops and applies
0130 /// `static_cast<T>` or `dynamic_cast<T>` to each element.
0131 /// \tparam T The new type to convert to.
0132 /// \tparam isDynamic If `true`, `dynamic_cast` is used, otherwise `static_cast` is used.
0133 /// \tparam Range_t The type of the input range, which should be usually a reference type to avoid copying.
0134 template <typename T, bool isDynamic, typename Range_t>
0135 class RRangeCast {
0136 
0137 public:
0138    RRangeCast(Range_t &&inputRange) : fInputRange{inputRange}
0139    {
0140       static_assert(ROOT::Internal::hasBeginEnd<Range_t>(0),
0141                     "Type with no `begin` or `end` method passed to `RRangeCast`");
0142    }
0143 
0144    using const_iterator = Internal::TypedIter<T, decltype(std::cbegin(std::declval<Range_t>())), isDynamic>;
0145    const_iterator begin() const { return std::cbegin(fInputRange); }
0146    const_iterator end() const { return std::cend(fInputRange); }
0147 
0148    using iterator = Internal::TypedIter<T, decltype(std::begin(std::declval<Range_t>())), isDynamic>;
0149    iterator begin() { return std::begin(fInputRange); }
0150    iterator end() { return std::end(fInputRange); }
0151 
0152 private:
0153    Range_t fInputRange;
0154 };
0155 
0156 /// Takes any collection that can be used in range-based loops and applies
0157 /// static_cast<T> to each element. This function can be used for example to
0158 /// cast all objects in a RooAbsCollection when iterating over them.
0159 /// Example:
0160 /// ~~~{.cpp}
0161 /// class ClassA {
0162 /// public:
0163 ///    virtual ~ClassA() {}
0164 /// };
0165 /// class ClassB : public ClassA {
0166 /// };
0167 ///
0168 /// B b1, b2, b3;
0169 /// std::vector<A const*> vec{&b1, &b2, &b3};
0170 ///
0171 /// for(auto *b : ROOT::RangeStaticCast<B const*>(vec)) {
0172 ///    // do something with b
0173 /// }
0174 /// ~~~
0175 /// Make sure to not use `auto const&` in the range-based loop, as this will
0176 /// cause a range-loop-bind-reference warning with the clang compiler.
0177 template <typename T, typename Range_t>
0178 RRangeCast<T, false, Range_t> RangeStaticCast(Range_t &&coll)
0179 {
0180    return std::forward<Range_t>(coll);
0181 }
0182 // Overload for C-style arrays. It's not possible to make an overload of the
0183 // RRangeCast constructor itself, because when the C-style array is forwarded
0184 // it might decay depending on the compiler version.
0185 template <typename T, typename U, std::size_t N>
0186 RRangeCast<T, false, std::span<U>> RangeStaticCast(U (&arr)[N])
0187 {
0188    return std::span<U>(arr, arr + N);
0189 }
0190 
0191 /// Takes any collection that can be used in range-based loops and applies
0192 /// dynamic_cast<T> to each element. This function can be used for example to
0193 /// cast all objects in a RooAbsCollection when iterating over them.
0194 /// Example:
0195 /// ~~~{.cpp}
0196 ///
0197 /// class ClassA {
0198 /// public:
0199 ///    virtual ~ClassA() {}
0200 /// };
0201 /// class ClassB : public ClassA {
0202 /// };
0203 ///
0204 /// A a1, a2;
0205 /// B b1, b2, b3;
0206 /// std::vector<A const*> vec{&b1, &a1, &b2, &a2, &b3};
0207 ///
0208 /// for(auto *b : ROOT::RangeDynCast<B const*>(vec)) {
0209 ///    if(b) {
0210 ///       // do something with b
0211 ///    }
0212 /// }
0213 /// ~~~
0214 /// Make sure to not use `auto const&` in the range-based loop, as this will
0215 /// cause a range-loop-bind-reference warning with the clang compiler.
0216 template <typename T, typename Range_t>
0217 RRangeCast<T, true, Range_t> RangeDynCast(Range_t &&coll)
0218 {
0219    return std::forward<Range_t>(coll);
0220 }
0221 // Overload for C-style arrays. It's not possible to make an overload of the
0222 // RRangeCast constructor itself, because when the C-style array is forwarded
0223 // it might decay depending on the compiler version.
0224 template <typename T, typename U, std::size_t N>
0225 RRangeCast<T, true, std::span<U>> RangeDynCast(U (&arr)[N])
0226 {
0227    return std::span<U>(arr, arr + N);
0228 }
0229 
0230 } // namespace ROOT
0231 
0232 #endif