Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RRangeCast.hxx
Go to the documentation of this file.
1/// \file ROOT/RRangeCast.hxx
2/// \author Jonas Rembser <jonas.rembser@cern.ch>
3/// \date 2021-08-04
4
5/*************************************************************************
6 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#ifndef ROOT_RRangeCast
14#define ROOT_RRangeCast
15
16#include "ROOT/RSpan.hxx"
17
18#include <cassert>
19#include <iterator>
20#include <type_traits>
21#include <utility>
22
23namespace ROOT {
24namespace Internal {
25
26template <typename T>
27struct RBaseType {
28 using type = typename std::remove_pointer<typename std::decay<T>::type>::type;
29};
30
31// For SFINAE-based checks for the existence of the `begin` and `end` methods.
32template <typename T>
33constexpr auto hasBeginEnd(int) -> decltype(std::begin(std::declval<T>()), std::end(std::declval<T>()), true)
34{
35 return true;
36}
37
38template <typename>
39constexpr bool hasBeginEnd(...)
40{
41 return false;
42}
43
44template <typename T, typename WrappedIterator_t, bool isDynamic>
45class TypedIter {
46
47public:
48 TypedIter(WrappedIterator_t const &iter) : fIter{iter} {}
49
51 {
52 ++fIter;
53 return *this;
54 }
56 {
57 TypedIter tmp(*this);
58 operator++();
59 return tmp;
60 }
61 bool operator==(const TypedIter &rhs) const { return fIter == rhs.fIter; }
62 bool operator!=(const TypedIter &rhs) const { return fIter != rhs.fIter; }
63
64 void swap(TypedIter &other) { fIter.swap(other.fIter); }
65
66 // We want to know at compile time whether dynamic_cast or static_cast is
67 // used. First of all to avoid overhead, but also to avoid a compiler error
68 // when using dynamic_cast on a non-polymorphic class.
70 {
71 if constexpr (isDynamic) {
72 return dynamic_cast<T>(*fIter);
73 } else {
74 if constexpr (std::is_polymorphic<RBaseType<T>>::value) {
75 assert(dynamic_cast<T>(*fIter));
76 }
77 return static_cast<T>(*fIter);
78 }
79 }
80
81private:
82 WrappedIterator_t fIter;
83};
84
85} // namespace Internal
86
87/// Wraps any collection that can be used in range-based loops and applies
88/// `static_cast<T>` or `dynamic_cast<T>` to each element.
89/// \tparam T The new type to convert to.
90/// \tparam isDynamic If `true`, `dynamic_cast` is used, otherwise `static_cast` is used.
91/// \tparam Range_t The type of the input range, which should be usually a reference type to avoid copying.
92template <typename T, bool isDynamic, typename Range_t>
94
95public:
96 RRangeCast(Range_t &&inputRange) : fInputRange{inputRange}
97 {
99 "Type with no `begin` or `end` method passed to `RRangeCast`");
100 }
101
103 const_iterator begin() const { return std::cbegin(fInputRange); }
104 const_iterator end() const { return std::cend(fInputRange); }
105
107 iterator begin() { return std::begin(fInputRange); }
108 iterator end() { return std::end(fInputRange); }
109
110private:
111 Range_t fInputRange;
112};
113
114/// Takes any collection that can be used in range-based loops and applies
115/// static_cast<T> to each element. This function can be used for example to
116/// cast all objects in a RooAbsCollection when iterating over them.
117/// Example:
118/// ~~~{.cpp}
119/// class ClassA {
120/// public:
121/// virtual ~ClassA() {}
122/// };
123/// class ClassB : public ClassA {
124/// };
125///
126/// B b1, b2, b3;
127/// std::vector<A const*> vec{&b1, &b2, &b3};
128///
129/// for(auto *b : ROOT::RangeStaticCast<B const*>(vec)) {
130/// // do something with b
131/// }
132/// ~~~
133/// Make sure to not use `auto const&` in the range-based loop, as this will
134/// cause a range-loop-bind-reference warning with the clang compiler.
135template <typename T, typename Range_t>
137{
138 return std::forward<Range_t>(coll);
139}
140// Overload for C-style arrays. It's not possible to make an overload of the
141// RRangeCast constructor itself, because when the C-style array is forwarded
142// it might decay depending on the compiler version.
143template <typename T, typename U, std::size_t N>
145{
146 return std::span<U>(arr, arr + N);
147}
148
149/// Takes any collection that can be used in range-based loops and applies
150/// dynamic_cast<T> to each element. This function can be used for example to
151/// cast all objects in a RooAbsCollection when iterating over them.
152/// Example:
153/// ~~~{.cpp}
154///
155/// class ClassA {
156/// public:
157/// virtual ~ClassA() {}
158/// };
159/// class ClassB : public ClassA {
160/// };
161///
162/// A a1, a2;
163/// B b1, b2, b3;
164/// std::vector<A const*> vec{&b1, &a1, &b2, &a2, &b3};
165///
166/// for(auto *b : ROOT::RangeDynCast<B const*>(vec)) {
167/// if(b) {
168/// // do something with b
169/// }
170/// }
171/// ~~~
172/// Make sure to not use `auto const&` in the range-based loop, as this will
173/// cause a range-loop-bind-reference warning with the clang compiler.
174template <typename T, typename Range_t>
176{
177 return std::forward<Range_t>(coll);
178}
179// Overload for C-style arrays. It's not possible to make an overload of the
180// RRangeCast constructor itself, because when the C-style array is forwarded
181// it might decay depending on the compiler version.
182template <typename T, typename U, std::size_t N>
184{
185 return std::span<U>(arr, arr + N);
186}
187
188} // namespace ROOT
189
190#endif
#define N
bool operator!=(const TypedIter &rhs) const
TypedIter(WrappedIterator_t const &iter)
bool operator==(const TypedIter &rhs) const
TypedIter operator++(int)
WrappedIterator_t fIter
void swap(TypedIter &other)
Wraps any collection that can be used in range-based loops and applies static_cast<T> or dynamic_cast...
Internal::TypedIter< T, decltype(std::begin(std::declval< Range_t >())), isDynamic > iterator
Internal::TypedIter< T, decltype(std::cbegin(std::declval< Range_t >())), isDynamic > const_iterator
const_iterator begin() const
const_iterator end() const
RRangeCast(Range_t &&inputRange)
constexpr auto hasBeginEnd(int) -> decltype(std::begin(std::declval< T >()), std::end(std::declval< T >()), true)
RRangeCast< T, false, Range_t > RangeStaticCast(Range_t &&coll)
Takes any collection that can be used in range-based loops and applies static_cast<T> to each element...
RRangeCast< T, true, Range_t > RangeDynCast(Range_t &&coll)
Takes any collection that can be used in range-based loops and applies dynamic_cast<T> to each elemen...
typename std::remove_pointer< typename std::decay< T >::type >::type type