counter.h
Go to the documentation of this file.
1 /**
2  * @file larcorealg/CoreUtils/counter.h
3  * @brief Test of `util::counter` and support utilities.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date April 14, 2019
6  *
7  * This is a header-only library.
8  */
9 
10 #ifndef LARCOREALG_COREUTILS_COUNTER_H
11 #define LARCOREALG_COREUTILS_COUNTER_H
12 
13 
14 // LArSoft libraries
16 
17 // C/C++ libraries
18 #include <utility> // std::move()
19 #include <cstddef> // std::size_t
20 
21 
22 namespace util {
23 
24  // -- BEGIN -- Counted iterations --------------------------------------------
25  /// @name Counted iterations
26  /// @{
27 
28  /**
29  * @brief An iterator dereferencing to a counter value.
30  * @tparam T the type of counter returned on dereferenciation
31  * @see `util::counter()`
32  *
33  * This iterator returns on dereferencing the net count of how many times it
34  * has been incremented.
35  * So for example:
36  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
37  * std::vector<int> data;
38  * for (util::count_iterator it;; ++it) {
39  * if (*it >= 10) break;
40  * data.push_back(*it); // implicit conversion `std::size_t` to `int`
41  * }
42  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
43  * this infinite loop will push the value `0` into `data` on the first
44  * iteration, `1` on the second and so forth, until at the eleventh iteration,
45  * just before it can push `10`, the loop is forcibly broken leaving 10
46  * elements in `data`.
47  *
48  * The iterator can be made to start from an index `n` different than `0`, in
49  * which case it behaves like it had already been incremented `n` times.
50  * End iterators can be build in that way too; see also `util::counter()`.
51  *
52  */
53  template <typename T = std::size_t>
55 
56  public:
57 
58  // --- BEGIN -- Traits and data types --------------------------------------
59  /// @name Traits and data types
60  /// @{
61 
62  using iterator_type = count_iterator<T>; ///< Type of this iterator.
63 
64  using difference_type = std::ptrdiff_t;
65  using value_type = T; ///< Type of index returned by this iterator.
66  using reference = T const&; ///< Type returned by dereference operator.
67  using pointer = T*;
68  using iterator_category = std::bidirectional_iterator_tag;
69 
70  /// @}
71  // --- END -- Traits and data types ----------------------------------------
72 
73 
74  // --- BEGIN Constructors --------------------------------------------------
75  /// @name Construction
76  /// @{
77 
78  /**
79  * @brief Initializes the iterator.
80  *
81  * The initial loop count is the default-constructed value of the counter
82  * type, which is usually some variation on the concept of `0`.
83  */
84  count_iterator() = default;
85 
86  /**
87  * @brief Initializes the iterator with the specified loop count.
88  * @param count the initial loop count
89  */
91 
92  /// @}
93  // --- END Constructors ----------------------------------------------------
94 
95 
96  // --- BEGIN -- Data access ------------------------------------------------
97  /// @name Data access
98  /// @{
99 
100  /// Returns the current loop count.
101  reference operator* () const { return fCount; }
102 
103  /// @}
104  // --- END -- Data access --------------------------------------------------
105 
106 
107  // --- BEGIN -- Modification -----------------------------------------------
108  /// @name Modification
109  /// @{
110 
111  /// Increments the loop count of this iterator, which is then returned.
112  iterator_type& operator++ () { ++fCount; return *this; }
113 
114  /// Increments the loop count of this iterator, returning a copy with the
115  /// value before the increment.
117  { iterator_type const old = *this; operator++(); return old; }
118 
119  /// Decrements the loop count of this iterator, which is then returned.
120  iterator_type& operator-- () { --fCount; return *this; }
121 
122  /// Decrements the loop count of this iterator, returning a copy with the
123  /// value before the decrement.
125  { iterator_type const old = *this; operator--(); return old; }
126 
127  /// @}
128  // --- END -- Modification -------------------------------------------------
129 
130 
131  // --- BEGIN -- Comparisons ------------------------------------------------
132  /// @name Comparisons
133  /// @{
134 
135  /// Iterators are equal if their loop counts compare equal.
136  template <typename U>
138  { return fCount == other.fCount; }
139 
140  /// Iterators are equal if their loop counts compare different.
141  template <typename U>
143  { return fCount != other.fCount; }
144 
145  /// @}
146  // --- END -- Comparisons --------------------------------------------------
147 
148 
149  private:
150 
151  value_type fCount {}; ///< Internal counter.
152 
153  }; // class count_iterator<>
154 
155 
156  /**
157  * @brief Returns an object to iterate values from `begin` to `end` in a
158  * range-for loop.
159  * @tparam T type of counter value
160  * @return a control object for range-for loop
161  * @see `util::count_iterator`
162  *
163  * An example of usage:
164  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
165  * std::vector<std::size_t> data;
166  * for (auto i: util::counter(4, 8)) {
167  * data.push_back(i);
168  * }
169  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170  * will insert in `data` the numbers from `4` to `7`, just like:
171  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
172  * for (std::size_t i = 4; i < 8; ++i) {
173  * data.push_back(i);
174  * }
175  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
176  * would.
177  */
178  template <typename T>
179  auto counter(T begin, T end);
180 
181  /// Version of `util::counter()` starting at default-constructed `T`
182  /// (usually some form of `0`).
183  template <typename T>
184  auto counter(T end) { return counter(T{}, end); }
185 
186  /**
187  * @brief Version of `util::counter()` starting at `begin` and never ending.
188  * @tparam T type of counter value
189  * @param begin the count to start from (default-constructed, usually some
190  * form of `0`, by default)
191  * @return a control object for range-for loop
192  *
193  * An example of usage:
194  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
195  * std::vector<unsigned char> data;
196  * for (auto ch: util::infinite_counter<unsigned char>()) {
197  * if (data.size() >= 512U) break;
198  * data.push_back(ch);
199  * }
200  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
201  * This loop runs through the full range of a character (8 bits, supposedly)
202  * twice before being broken.
203  *
204  */
205  template <typename T = std::size_t>
206  auto infinite_counter(T begin = T{});
207 
208 
209  /// @}
210  // -- END -- Counted iterations ----------------------------------------------
211 
212 
213 } // namespace util
214 
215 
216 //==============================================================================
217 //=== template implementation
218 //==============================================================================
219 //------------------------------------------------------------------------------
220 //--- util::counter()
221 //------------------------------------------------------------------------------
222 namespace util::details {
223 
224  /**
225  * @brief Class used as end iterator (sentinel) for an infinite loop.
226  * @tparam T the nominal count type
227  *
228  * This "iterator" offers a very limited interface, not at all like a real
229  * iterator.
230  * In fact, it can only be compared to other `count_iterator` objects on the
231  * same counter type.
232  */
233  template <typename T>
237 
238  public:
239 
240  // mock-up of stuff required by `util::span`
241  using value_type = T;
242  using reference = T const&;
243  using pointer = T const*;
244  using difference_type = std::ptrdiff_t;
245  using iterator_category = std::forward_iterator_tag; // this is a lie
246 
247 
248  /// Never admit this iterator is equal to anything else (except the same).
249  bool operator== (this_iterator_t const&) const { return true; }
250 
251  /// Never admit this iterator is equal to anything else (except the same).
252  bool operator!= (this_iterator_t const&) const { return false; }
253 
254  }; // class infinite_endcount_iterator
255 
256  /// Never admit a `infinite_endcount_iterator` to be equal to anything else.
257  template <typename T>
258  bool operator!=
260  { return true; }
261 
262  template <typename T>
263  bool operator!=
265  { return true; }
266 
267  template <typename T>
268  bool operator==
270  { return false; }
271 
272  template <typename T>
273  bool operator==
275  { return false; }
276 
277 
278  //----------------------------------------------------------------------------
279 
280 } // namespace util::details
281 
282 
283 //------------------------------------------------------------------------------
284 template <typename T>
286  { return util::span(count_iterator(begin), count_iterator(end)); }
287 
288 
289 //------------------------------------------------------------------------------
290 template <typename T>
292 {
293  return util::span
295 } // util::infinite_counter()
296 
297 
298 //------------------------------------------------------------------------------
299 
300 
301 #endif // LARCOREALG_COREUTILS_COUNTER_H
T value_type
Type of index returned by this iterator.
Definition: counter.h:65
span(IterB &&b, IterE &&e, Adaptor &&adaptor) -> span< decltype(adaptor(std::forward< IterB >(b))), decltype(adaptor(std::forward< IterE >(e))) >
Namespace for general, non-LArSoft-specific utilities.
An object with a begin and end iterator.
An iterator dereferencing to a counter value.
Definition: counter.h:54
auto infinite_counter(T begin=T{})
Version of util::counter() starting at begin and never ending.
Definition: counter.h:291
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
std::ptrdiff_t difference_type
Definition: counter.h:64
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
Definition: counter.h:285
Class used as end iterator (sentinel) for an infinite loop.
Definition: counter.h:234
T const & reference
Type returned by dereference operator.
Definition: counter.h:66
count_iterator(value_type count)
Initializes the iterator with the specified loop count.
Definition: counter.h:90
reference operator*() const
Returns the current loop count.
Definition: counter.h:101
value_type fCount
Internal counter.
Definition: counter.h:151
iterator_type & operator++()
Increments the loop count of this iterator, which is then returned.
Definition: counter.h:112
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
iterator_type & operator--()
Decrements the loop count of this iterator, which is then returned.
Definition: counter.h:120
std::forward_iterator_tag iterator_category
Definition: counter.h:245
bool operator!=(count_iterator< U > const &other) const
Iterators are equal if their loop counts compare different.
Definition: counter.h:142
count_iterator()=default
Initializes the iterator.
bool operator==(count_iterator< U > const &other) const
Iterators are equal if their loop counts compare equal.
Definition: counter.h:137
std::bidirectional_iterator_tag iterator_category
Definition: counter.h:68