NestedIterator.h
Go to the documentation of this file.
1 /**
2  * @file NestedIterator.h
3  * @brief Iterators recursing though nested collections
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date August 22th, 2014
6  *
7  * This header is currently a draft with reduced (essential) functionality.
8  * Its ambition is to become general enough to be used transparently.
9  */
10 
11 #ifndef NESTEDITERATOR_H
12 #define NESTEDITERATOR_H
13 
14 // interface include
15 #include <type_traits> // std::true_type, std::false_type, std::conditional
16 #include <iterator> // std::forward_iterator_tag
17 
18 namespace lar {
19 
20  namespace details {
21  namespace type_traits {
22 
23  //------------------------------------------------------------------------
24  // declarations of helpers for has_const_iterator() function
25  template <typename T, bool>
27 
28  template <typename T>
29  constexpr auto has_const_iterator_helper(T* = nullptr)
30  -> decltype(typename T::const_iterator(), bool());
31 
32  // Used as fallback when SFINAE culls the template method
33  constexpr bool has_const_iterator_helper(...);
34  //------------------------------------------------------------------------
35 
36  } // namespace type_traits
37  } // namespace details
38 
39  template <typename T>
42  <T, details::type_traits::has_const_iterator_helper((T*)(nullptr))>
43  {};
44 
45 
46  /// Functor returning the object specified as argument
47  template <typename T>
48  class Identity;
49 
50 
51  template <typename T>
52  class PairSecond;
53 
54  /// Internal helper class: actual implementation of nested iterator
55  template <
56  typename ITER,
57  typename INNERCONTEXTRACT = Identity<typename ITER::value_type>
58  >
60 
61 
62  /// Deep iterator
63  /// @todo write documentation about how to use it
64 /* template <typename CITER>
65  using deep_fwd_const_iterator = std::conditional<
66  has_const_iterator<typename CITER::value_type>(),
67  deep_const_fwd_iterator_nested<CITER>,
68  CITER
69  >;
70 */
71 
72  template <
73  typename CITER,
74  typename INNERCONTEXTRACT = Identity<typename CITER::value_type>
75  >
78 
79 } // namespace lar
80 
81 
82 namespace std {
83  template <typename CITER, typename INNERCONTEXTRACT>
86 
87 } // namespace std
88 
89 
90 //------------------------------------------------------------------------------
91 
92 namespace lar {
93 
94  namespace details {
95  namespace type_traits {
96 
97  //------------------------------------------------------------------------
98  // helpers for has_const_iterator() function
99  template <typename T, bool>
100  struct has_const_iterator_struct: public std::false_type {};
101 
102  template <typename T>
103  struct has_const_iterator_struct<T, true>: public std::true_type {};
104 
105  // Culled by SFINAE if T::const_iterator does not exist
106  // or is not accessible or not default-constructable
107  template <typename T>
108  constexpr auto has_const_iterator_helper(T* /* = nullptr */)
109  -> decltype(typename T::const_iterator(), bool())
110  { return true; }
111 
112  // Used as fallback when SFINAE culls the template method
113  constexpr bool has_const_iterator_helper(...) { return false; }
114  //------------------------------------------------------------------------
115 
116  } // namespace type_traits
117  } // namespace details
118 
119  //---
120  //--- Identity declaration
121  //---
122  template <class T>
123  class Identity {
124  public:
125  typedef T argument_type;
126  typedef T result_type;
127 
128  result_type& operator() (argument_type& x) const { return x; }
129  const result_type& operator() (const argument_type& x) const { return x; }
130  }; // class Identity<>
131 
132 
133  //---
134  //--- PairSecond declaration
135  //---
136  template <class T>
137  class PairSecond {
138  public:
139  typedef T argument_type;
140  typedef typename T::second_type result_type;
141 
142  result_type& operator() (argument_type& p) const
143  { return p.second; }
144  const result_type& operator() (const argument_type& p) const
145  { return p.second; }
146  }; // class PairSecond<>
147 
148 
149  //---
150  //--- deep_const_fwd_iterator_nested declaration
151  //---
152  template <typename ITER, typename INNERCONTEXTRACT>
153  class deep_const_fwd_iterator_nested: public std::forward_iterator_tag {
154  public:
155  using OuterIterator_t = ITER;
156  using InnerContainerExtractor_t = INNERCONTEXTRACT;
157  using InnerContainer_t = typename InnerContainerExtractor_t::result_type;
158  using InnerIterator_t
159  // = deep_fwd_const_iterator<typename ITER::value_type::const_iterator>;
161 
162  // using iterator_type = deep_fwd_const_iterator<OuterIterator_t>;
165 
166  /// Type of the value pointed by the iterator
167  using value_type = typename InnerIterator_t::value_type;
168 
169 
170  struct BeginPositionTag {};
171  struct EndPositionTag {};
172 
173  static constexpr BeginPositionTag begin = {};
174  static constexpr EndPositionTag end = {};
175 
176  /**
177  * @brief Default constructor: invalid iterator
178  *
179  * This constructor sets the iterator in an invalid, end-of-container state.
180  */
181  deep_const_fwd_iterator_nested() = default;
182 
183  /**
184  * @brief Constructor: starts from the container at the specified iterator
185  * @param src the starting point of the iterator
186  * @param end the end point of the iterator
187  *
188  * This constructor does not set and end. Due to how the class works,
189  * if the outer container has an "end", reaching it with this iterator has
190  * a undefined behaviour. You most likely want to use the constructor where
191  * you can also specify the end of the container.
192  */
194 
195  /**
196  * @brief Constructor: starts from the beginning of the specified container
197  * @param cont the container
198  * @param [anonymous] tag to select the begin-of-container behaviour
199  *
200  * The second parameter is used just to choose which constructor to use.
201  * Two constants are provided, begin and end, defined in the iterator itself
202  * (no explicit namespace is required).
203  * Example:
204  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
205  * using Data_t = std::vector<std::vector<float>>;
206  * Data_t data(5, { 1., 3., 5. });
207  * deep_const_fwd_iterator_nested<Data_t::const_iterator> iData(data, begin),
208  * data_end(data, end);
209  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
210  */
211  template <class CONT>
213  deep_const_fwd_iterator_nested(std::begin(cont), std::end(cont))
214  { skip_empty(); }
215 
216  /**
217  * @brief Constructor: starts from the end of the specified container
218  * @param cont the container
219  * @param [anonymous] tag to select the end-of-container behaviour
220  *
221  * The second parameter is used just to choose which constructor to use.
222  * Two constants are provided, begin and end, defined in the iterator itself
223  * (no explicit namespace is required).
224  * Example:
225  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
226  * using Data_t = std::vector<std::vector<float>>;
227  * Data_t data(5, { 1., 3., 5. });
228  * deep_const_fwd_iterator_nested<Data_t::const_iterator> iData(data, begin),
229  * data_end(data, end);
230  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
231  */
232  template <class CONT>
234  deep_const_fwd_iterator_nested(std::end(cont)) {}
235 
236  /**
237  * @brief Prefix increment operator: points to the next element
238  * @return this iterator, already incremented
239  *
240  * The behaviour of this method on a past-the-end iterator is undefined
241  * (currently, chances are it will access invalid memory).
242  */
243  iterator_type& operator++();
244 
245  /**
246  * @brief Postfix increment operator: points to the next element
247  * @return a copy of this iterator before the increment
248  *
249  * The behaviour of this method on a past-the-end iterator is undefined
250  * (currently, chances are it will access invalid memory).
251  */
253  { iterator_type old(*this); this->operator++(); return old; }
254 
255  ///@{
256  /// @name Dereference operators
257  const value_type& operator*() const { return *inner_iter; }
258  const value_type& operator->() const { return *inner_iter; }
259  ///@}
260 
261  ///@{
262  /// @name Comparison operators
263  /// Returns true if the two iterators are equivalent
264  bool operator== (const iterator_type& as) const
265  {
266  return (as.outer_iter == outer_iter)
267  && ((as.inner_iter == inner_iter) || (is_end() && as.is_end()));
268  }
269  /// Returns true if the two iterators are not equivalent
270  bool operator!= (const iterator_type& as) const
271  {
272  return (as.outer_iter != outer_iter)
273  || ((as.inner_iter != inner_iter) && (!is_end() || !as.is_end()));
274  }
275  ///@}
276 
277 
278  ///@{
279  /**
280  * @brief Bonus: convert to bool to find out if we are at the end
281  * @return whether this operator is past-the-end
282  */
283  operator bool() const { return !is_end(); }
284  bool operator! () const { return is_end(); }
285  ///@}
286 
287  /// Swaps this with the specified iterator
288  void swap(iterator_type& with);
289 
290  protected:
291  OuterIterator_t outer_iter; ///< points to current inner container
292  OuterIterator_t outer_end; ///< points to past-the-end inner container
293 
294  InnerIterator_t inner_iter; ///< points to the current element
295  InnerIterator_t inner_end; ///< stores the end of current inner container
296 
297  /// Internal constructor: past-the-end iterator pointing to specified place
299  deep_const_fwd_iterator_nested(end, end) {}
300 
301  private:
302  void init_inner();
303  void reset_inner();
304  void skip_empty(); ///< points to the next item
305 
306  bool is_end() const { return outer_iter == outer_end; }
307 
308  /// Extracts the value out of the inner iterator
309  const typename InnerContainerExtractor_t::result_type&
310  extract_container(const typename OuterIterator_t::value_type& v)
311  { return InnerContainerExtractor_t()(v); }
312 
313  }; // class deep_const_fwd_iterator_nested<>
314 
315 
316  //---
317  //--- deep_const_fwd_iterator_nested implementation
318  //---
319 
320  template <typename ITER, typename INNERCONTEXTRACT>
324  outer_iter(src), outer_end(end)
325  {
326  if (is_end()) return;
327  init_inner();
328  skip_empty();
329  } // deep_const_fwd_iterator_nested(OuterIterator_t, OuterIterator_t)
330 
331 
332  template <typename ITER, typename INNERCONTEXTRACT>
335  ++inner_iter;
336  skip_empty();
337  return *this;
338  } // deep_const_fwd_iterator_nested<>::operator++()
339 
340 
341  template <typename ITER, typename INNERCONTEXTRACT>
344  {
345  std::swap(outer_iter, with.outer_iter);
346  std::swap(outer_end, with.outer_end);
347  std::swap(inner_iter, with.inner_iter);
348  std::swap(inner_end, with.inner_end);
349  } // deep_const_fwd_iterator_nested<>::swap()
350 
351 
352  template <typename ITER, typename INNERCONTEXTRACT>
354  inner_iter = std::begin(extract_container(*outer_iter));
355  inner_end = std::end(extract_container(*outer_iter));
356  } // deep_const_fwd_iterator_nested<>::init_inner()
357 
358 
359  template <typename ITER, typename INNERCONTEXTRACT>
361  { inner_end = inner_iter = {}; }
362 
363  template <typename ITER, typename INNERCONTEXTRACT>
365  while(inner_iter == inner_end) {
366  ++outer_iter;
367  if (is_end()) {
368  reset_inner();
369  return;
370  } // if
371  init_inner();
372  } // while inner iterator ended
373  } // skip_empty()
374 
375 
376 } // namespace lar
377 
378 
379 namespace std {
380  template <typename CITER, typename INNERCONTEXTRACT>
381  inline void swap(
384  )
385  { a.swap(b); }
386 } // namespace std
387 
388 
389 
390 #endif // NESTEDITERATOR_H
deep_const_fwd_iterator_nested(const CONT &cont, EndPositionTag)
Constructor: starts from the end of the specified container.
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
typename InnerIterator_t::value_type value_type
Type of the value pointed by the iterator.
InnerIterator_t inner_iter
points to the current element
typename InnerContainer_t::const_iterator InnerIterator_t
std::enable_if_t< is_selector< A >, NotHelper< A > > operator!(A const &a)
Definition: Selector.h:259
const InnerContainerExtractor_t::result_type & extract_container(const typename OuterIterator_t::value_type &v)
Extracts the value out of the inner iterator.
STL namespace.
iterator_type operator++(int)
Postfix increment operator: points to the next element.
intermediate_table::const_iterator const_iterator
InnerIterator_t inner_end
stores the end of current inner container
OuterIterator_t outer_iter
points to current inner container
bool operator!=(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept
deep_const_fwd_iterator_nested(OuterIterator_t end)
Internal constructor: past-the-end iterator pointing to specified place.
std::bool_constant< Value > type_traits
Definition: MetaUtils.h:174
iterator_type & operator++()
Prefix increment operator: points to the next element.
static constexpr double as
Definition: Units.h:101
const value_type & operator*() const
const double a
p
Definition: test.py:223
void swap(iterator_type &with)
Swaps this with the specified iterator.
Functor returning the object specified as argument.
constexpr auto has_const_iterator_helper(T *=nullptr) -> decltype(typename T::const_iterator(), bool())
LArSoft-specific namespace.
OuterIterator_t outer_end
points to past-the-end inner container
Internal helper class: actual implementation of nested iterator.
static bool * b
Definition: config.cpp:1043
deep_const_fwd_iterator_nested(const CONT &cont, BeginPositionTag)
Constructor: starts from the beginning of the specified container.
const value_type & operator->() const
typename InnerContainerExtractor_t::result_type InnerContainer_t
list x
Definition: train.py:276
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
T::second_type result_type
int bool
Definition: qglobal.h:345
bool operator==(ModuleKeyAndType const &a, ModuleKeyAndType const &b) noexcept
void skip_empty()
points to the next item