All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
span.h
Go to the documentation of this file.
1 /**
2  * @file larcorealg/CoreUtils/span.h
3  * @brief An object with a begin and end iterator.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date January 29, 2019
6  *
7  * This library is header only.
8  */
9 
10 #ifndef LARCOREALG_COREUTILS_SPAN_H
11 #define LARCOREALG_COREUTILS_SPAN_H
12 
13 // Boost libraries
14 #include "boost/iterator/transform_iterator.hpp"
15 
16 // C/C++ standard library
17 #include <iterator> // std::begin(), std::end()
18 #include <utility> // std::as_const()
19 #include <type_traits> // std::decay_t<>, std::declval(), std::invoke_result_t<>
20 
21 
22 namespace util {
23 
24 
25  /// Non-templated base class for `span`.
26  struct span_base {
27 
28  /// Returns the begin iterator of the specified container.
29  template <typename Cont>
30  static decltype(auto) get_begin(Cont& cont)
31  { using std::begin; return begin(cont); }
32 
33  /// Returns the end iterator of the specified container.
34  template <typename Cont>
35  static decltype(auto) get_end(Cont& cont)
36  { using std::end; return end(cont); }
37 
38  /// Type of begin iterator of `Cont` type.
39  template <typename Cont>
40  using get_begin_iterator
41  = std::decay_t<decltype(get_begin(std::declval<Cont>()))>;
42 
43  /// Type of end iterator of `Cont` type.
44  template <typename Cont>
45  using get_end_iterator
46  = std::decay_t<decltype(get_end(std::declval<Cont>()))>;
47 
48 
49  /// Returns the constant begin iterator of the specified container.
50  template <typename Cont>
51  static decltype(auto) get_cbegin(Cont& cont)
52  { using std::cbegin; return cbegin(cont); }
53 
54  /// Returns the constant end iterator of the specified container.
55  template <typename Cont>
56  static decltype(auto) get_cend(Cont& cont)
57  { using std::cend; return cend(cont); }
58 
59  /// Type of constant begin iterator of `Cont` type.
60  template <typename Cont>
62  = std::decay_t<decltype(get_cbegin(std::declval<Cont>()))>;
63 
64  /// Type of constant end iterator of `Cont` type.
65  template <typename Cont>
66  using get_cend_iterator
67  = std::decay_t<decltype(get_cend(std::declval<Cont>()))>;
68 
69  }; // struct span_base
70 
71 
72  /**
73  * @brief Simple class with a begin and an end.
74  * @tparam BITER type of begin iterator
75  * @tparam EITER type of end iterator (default: as `BITER`)
76  *
77  * This class is a glorified pair of iterators which can be used in a
78  * range-for loop.
79  * All input iterators are accepted.
80  *
81  * It is probably going to be redundant with the advent of C++20 and its span
82  * and/or range libraries (if the latter is ever going to happen).
83  *
84  * Example:
85  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
86  * using Data_t = std::vector<int>;
87  *
88  * int sum(util::span<Data_t::iterator> r) {
89  * decltype(r)::value_type s = 0;
90  * for (auto v: r) s += v;
91  * return s;
92  * } // sum
93  *
94  * void analyse() {
95  *
96  * Data_t v(10U);
97  * std::iota(v.begin(), v.end(), 1); // { 1, 2, 3, 4 ,5 ,6, 7, 8, 9, 10 }
98  *
99  * auto span5 = util::span(v.begin(), v.begin() + 5);
100  * std::cout << "Sum of 5 numbers: " << sum(span5) << std::endl;
101  *
102  * auto span8 = util::span(v.begin(), v.begin() + 8);
103  * std::cout << "Sum of 8 numbers: " << sum(span8) << std::endl;
104  *
105  * auto full_span = util::make_span(v);
106  * std::cout << "Sum of all numbers: " << sum(full_span) << std::endl;
107  *
108  * } // analyse()
109  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
110  * The call to `analyse()` will produce output like:
111  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112  * Sum of 5 numbers: 15
113  * Sum of 8 numbers: 36
114  * Sum of all numbers: 55
115  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116  * The convenience of this class, not evident from the example, is the
117  * beginning and end of the span can be passed around as a single object,
118  * with the added bonus of a (very reduced) collection interface.
119  *
120  * @note The constantness of the access is completely determined by the type
121  * of the iterators. A `const span` object does _not_ guarantee
122  * unmutable access to the iterated data.
123  */
124  template <typename BIter, typename EIter = BIter>
125  struct span: public span_base, private std::pair<BIter, EIter> {
126 
127  using begin_iterator = BIter; ///< Type of begin iterator.
128  using end_iterator = EIter; ///< Type of end iterator.
129 
130  /// Type of this class.
132 
133  /// Type of iterator pair.
134  using pair_t = std::pair<begin_iterator, end_iterator>;
135 
136  /// Type of values pointed by the iterators.
137  using value_type = typename begin_iterator::value_type;
138 
139  /// Type of reference pointed by the iterators.
140  using reference = typename begin_iterator::reference;
141 
142  /// Constructor: specifies the begin and end iterator.
144 
145  /// Constructor: specifies the begin and end iterator and an adapter.
146  template <typename SrcIterB, typename SrcIterE, typename Adaptor>
147  span(SrcIterB&& b, SrcIterE&& e, Adaptor&& adaptor)
148  : span
149  (adaptor(std::forward<SrcIterB>(b)), adaptor(std::forward<SrcIterE>(e)))
150  {}
151 
152  /// Constructor: copies from another span (possibly with different types).
153  template <typename OBIter, typename OEIter>
154  span(span<OBIter, OEIter> const& from): span(from.begin(), from.end()) {}
155 
156  // C++ boilerplate
157  span(span_t const&) = default;
158  span(span_t&&) = default;
159  span_t& operator=(span_t const&) = default;
160  span_t& operator=(span_t&&) = default;
161 
162 
163  /// Returns a copy of the begin iterator.
164  begin_iterator begin() const { return pair_t::first; }
165 
166  /// Returns a copy of the end iterator.
167  end_iterator end() const { return pair_t::second; }
168 
169  /// Returns the size between begin and end, converted to `std::size_t`.
170  std::size_t size() const { return std::distance(begin(), end()); }
171 
172  /// Returns whether the span is empty (that is, no steps between them).
173  bool empty() const { return begin() == end(); }
174 
175  }; // span
176 
177  // deduction guide for adapted span
178  template <typename IterB, typename IterE, typename Adaptor>
179  span(IterB&& b, IterE&& e, Adaptor&& adaptor)
180  -> span<
181 #if 0 // this is C++17...
182  std::invoke_result_t<Adaptor, IterB>,
183  std::invoke_result_t<Adaptor, IterE>
184 #else // ... and this is what Clang 5.0 undestands
185  decltype(adaptor(std::forward<IterB>(b))),
186  decltype(adaptor(std::forward<IterE>(e)))
187 #endif // 0
188  >;
189 
190 
191  // --- BEGIN -- Span helper functions ----------------------------------------
192  /// @name Span helper functions
193  /// @{
194 
195  /// Creates a span from specified iterators (can use constructor instead).
196  template <typename BIter, typename EIter>
197  auto make_span(BIter begin, EIter end) { return util::span(begin, end); }
198 
199  /// Creates a span from a container type.
200  template <typename Cont>
201  auto make_span(Cont& cont)
202  { return span{ span_base::get_begin(cont), span_base::get_end(cont) }; }
203 
204  /// Creates a span with constant iterator access from a container type.
205  template <typename Cont>
206  auto make_const_span(Cont& cont)
207  {
208  return span{ span_base::get_cbegin(cont), span_base::get_cend(cont) };
209  }
210 
211  /// @}
212  // --- END -- Span helper functions ------------------------------------------
213 
214 
215 
216  // --- BEGIN -- Adapted span helper functions --------------------------------
217  /// @name Adapted span helper functions
218  /// @{
219 
220  /// Creates a span from specified iterators via an adaptor.
221  /// @see `make_adapted_span(Cont&, Adaptor&&)`
222  template <typename BIter, typename EIter, typename Adaptor>
223  auto make_adapted_span(BIter begin, EIter end, Adaptor&& adaptor)
224  { return util::span(adaptor(begin), adaptor(end)); }
225 
226  /**
227  * @brief Creates a span from specified collection via an adaptor.
228  * @param cont collection to be iterated through
229  * @param adapter iterator transformation to be applied on `cont`
230  * @return a `util::span` object iterating via an adapter to `cont`
231  * @see `make_adapted_span(BIter, EIter, Adaptor&&)`,
232  * `make_adapted_const_span(Cont, Adaptor&&)`
233  *
234  * This interface is just a little help on using _iterator_ adapters.
235  * Note that `adapter` transforms the iterators of `cont`, not its values.
236  * The adapter needs to be written aside and it's in general not trivial.
237  * An example of iterating through a collection of objects (actually, just
238  * `float` for simplicity) stored as unique pointers in a collection:
239  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
240  * float accumulate(std::vector<std::unique_ptr<float>> const& v) {
241  *
242  * using src_iterator = std::vector<std::unique_ptr<float>>::const_iterator;
243  *
244  * float sum = 0.0F;
245  * for (float v: util::make_adapted_span(v, boost::make_indirect_iterator<src_iterator>))
246  * sum += v;
247  *
248  * return sum;
249  * } // accumulate()
250  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
251  * This example shows the usage of `util::make_adapted_span()`. In the
252  * specific example, it would have been more explicit to use the constant
253  * counterpart, `util::make_adapted_const_span()`.
254  * The adaptor helper `boost::make_indirect_iterator()` is provided in
255  * `boost/iterator/indirect_iterator.hpp`.
256  */
257  template <typename Cont, typename Adaptor>
258  auto make_adapted_span(Cont& cont, Adaptor&& adaptor)
259  {
260  return make_adapted_span(
262  std::forward<Adaptor>(adaptor)
263  );
264  }
265 
266  /// Creates constant iteration span from specified collection via an adaptor.
267  // @see `make_adapted_span(Cont, Adaptor&&)`
268  template <typename Cont, typename Adaptor>
269  auto make_adapted_const_span(Cont& cont, Adaptor&& adaptor)
270  {
271  return make_adapted_span(
273  std::forward<Adaptor>(adaptor)
274  );
275  }
276 
277  /// @}
278  // --- END -- Adapted span helper functions ----------------------------------
279 
280 
281 
282  // --- BEGIN -- Transformed span helper functions ----------------------------
283  /**
284  * @name Transformed span helper functions
285  *
286  *
287  *
288  */
289  /// @{
290 
291  /// Creates a span from specified iterators via an adaptor.
292  /// @see `make_transformed_span(Cont&, Op&&)`
293  template <typename BIter, typename EIter, typename Op>
294  auto make_transformed_span(BIter begin, EIter end, Op&& op)
295  {
296  auto adaptor
297  = [&op](auto iter){ return boost::make_transform_iterator(iter, op); };
298  return util::make_adapted_span(begin, end, adaptor);
299  }
300 
301 
302  /**
303  * @brief Creates a span from specified collection via an adaptor.
304  * @param cont collection to be iterated through
305  * @param adapter iterator transformation to be applied on `cont`
306  * @return a `util::span` object iterating via an adapter to `cont`
307  * @see `make_transformed_span(BIter, EIter, Op&&)`,
308  * `make_transformed_const_span(Cont, Op&&)`,
309  * `make_adapted_span()`,
310  *
311  * This function transforms as directed by the unary operation `op` the result
312  * of each iteration cycle, so that instead of `cont[i]`, a `op(cont[i])`
313  * is assigned to the iteration control variable.
314  * An example of iterating through a collection of objects (actually, just
315  * `float` for simplicity) stored as unique pointers in a collection:
316  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
317  * float accumulate(std::vector<std::unique_ptr<float>> const& v) {
318  *
319  * float sum = 0.0F;
320  * for (float v: util::make_transformed_span(v, [](auto& ptr){ return *ptr; }))
321  * sum += v;
322  *
323  * return sum;
324  * } // accumulate()
325  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
326  * This example shows the usage of `util::make_transformed_span()`. In the
327  * specific example, it would have been more explicit to use the constant
328  * counterpart, `util::make_transformed_const_span()`.
329  * Note that in the example the dereference result is _copied_ into `v`.
330  * For have it by reference, the operation `op` must be properly written:
331  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
332  * void scale(std::vector<std::unique_ptr<float>>& v, float factor) {
333  *
334  * for (float& v: util::make_transformed_span(v, [](auto& ptr) -> float& { return *ptr; }))
335  * v *= factor;
336  *
337  * } // scale()
338  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
339  */
340  template <typename Cont, typename Op>
341  auto make_transformed_span(Cont& cont, Op&& op)
342  {
343  return make_transformed_span(
345  std::forward<Op>(op)
346  );
347  }
348 
349  /// Creates constant iteration span from specified collection via a
350  /// transformation `op`.
351  // @see `make_transformed_span(Cont, Op&&)`
352  template <typename Cont, typename Op>
353  auto make_transformed_const_span(Cont& cont, Op&& op)
354  { return make_transformed_span(std::as_const(cont), std::forward<Op>(op)); }
355 
356  /// @}
357  // --- END -- Adapted span helper functions ----------------------------------
358 
359 
360 } // namespace util
361 
362 
363 #endif // LARCOREALG_COREUTILS_SPAN_H
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
bool empty() const
Returns whether the span is empty (that is, no steps between them).
Definition: span.h:173
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:87
span< begin_iterator, end_iterator > span_t
Type of this class.
Definition: span.h:131
span(begin_iterator b, end_iterator e)
Constructor: specifies the begin and end iterator.
Definition: span.h:143
span(SrcIterB &&b, SrcIterE &&e, Adaptor &&adaptor)
Constructor: specifies the begin and end iterator and an adapter.
Definition: span.h:147
static decltype(auto) get_begin(Cont &cont)
Returns the begin iterator of the specified container.
Definition: span.h:30
auto make_span(BIter begin, EIter end)
Creates a span from specified iterators (can use constructor instead).
Definition: span.h:197
std::decay_t< decltype(get_end(std::declval< Cont >()))> get_end_iterator
Type of end iterator of Cont type.
Definition: span.h:46
typename begin_iterator::value_type value_type
Type of values pointed by the iterators.
Definition: span.h:137
auto cbegin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:567
end_iterator end() const
Returns a copy of the end iterator.
Definition: span.h:167
Simple class with a begin and an end.
Definition: span.h:125
auto make_adapted_span(BIter begin, EIter end, Adaptor &&adaptor)
Definition: span.h:223
Iter end_iterator
Type of end iterator.
Definition: span.h:128
span(span< OBIter, OEIter > const &from)
Constructor: copies from another span (possibly with different types).
Definition: span.h:154
auto cend(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:579
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
static decltype(auto) get_cbegin(Cont &cont)
Returns the constant begin iterator of the specified container.
Definition: span.h:51
static decltype(auto) get_cend(Cont &cont)
Returns the constant end iterator of the specified container.
Definition: span.h:56
Iter begin_iterator
Type of begin iterator.
Definition: span.h:127
span_t & operator=(span_t const &)=default
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
auto make_transformed_const_span(Cont &cont, Op &&op)
Definition: span.h:353
std::decay_t< decltype(get_cbegin(std::declval< Cont >()))> get_cbegin_iterator
Type of constant begin iterator of Cont type.
Definition: span.h:62
auto make_transformed_span(BIter begin, EIter end, Op &&op)
Definition: span.h:294
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
static decltype(auto) get_end(Cont &cont)
Returns the end iterator of the specified container.
Definition: span.h:35
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
std::size_t size() const
Returns the size between begin and end, converted to std::size_t.
Definition: span.h:170
typename begin_iterator::reference reference
Type of reference pointed by the iterators.
Definition: span.h:140
begin_iterator begin() const
Returns a copy of the begin iterator.
Definition: span.h:164
do i e
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
Definition: StdUtils.h:82
std::pair< begin_iterator, end_iterator > pair_t
Type of iterator pair.
Definition: span.h:134
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
Non-templated base class for span.
Definition: span.h:26
std::decay_t< decltype(get_begin(std::declval< Cont >()))> get_begin_iterator
Type of begin iterator of Cont type.
Definition: span.h:41
std::decay_t< decltype(get_cend(std::declval< Cont >()))> get_cend_iterator
Type of constant end iterator of Cont type.
Definition: span.h:67
auto make_const_span(Cont &cont)
Creates a span with constant iterator access from a container type.
Definition: span.h:206
auto make_adapted_const_span(Cont &cont, Adaptor &&adaptor)
Creates constant iteration span from specified collection via an adaptor.
Definition: span.h:269