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