LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
zip.h
Go to the documentation of this file.
1 
10 #ifndef LARCOREALG_COREUTILS_ZIP_H
11 #define LARCOREALG_COREUTILS_ZIP_H
12 
14 
15 // C/C++ libraries
16 #include <cstddef> // std::size_t
17 #include <iterator> // std::begin(), std::end()
18 #include <tuple>
19 #include <type_traits> // std::remove_cv_t<>, ...
20 #include <utility> // std::forward(), std::index_sequence_for(), ...
21 
22 namespace util {
23 
24  // -- BEGIN -- Parallel iterations -------------------------------------------
27 
73  template <std::size_t Lead, typename... Iterables>
74  auto zip(Iterables&&... iterables);
75 
77  template <typename... Iterables>
78  auto zip(Iterables&&... iterables)
79  {
80  return zip<0U>(std::forward<Iterables>(iterables)...);
81  }
82 
84  // -- END -- Parallel iterations ---------------------------------------------
85 
86 } // namespace util
87 
88 //==============================================================================
89 //=== template implementation
90 //==============================================================================
91 //------------------------------------------------------------------------------
92 //--- util::zip()
93 //------------------------------------------------------------------------------
94 namespace util::details {
95 
96  //----------------------------------------------------------------------------
97  template <std::size_t Lead, typename... Iters>
98  class zip_iterator {
99 
100  static_assert(Lead < sizeof...(Iters), "The index (Lead) of the leading iterator is invalid.");
101 
103  using this_iterator_t = zip_iterator<Lead, Iters...>;
104 
105  public:
106  // --- BEGIN -- Data types -------------------------------------------------
109 
110  using difference_type = std::ptrdiff_t;
111  using reference = std::tuple<typename std::iterator_traits<Iters>::reference...>;
112  using value_type = std::remove_cv_t<reference>;
113  using pointer = std::add_pointer_t<std::remove_reference_t<reference>>;
114  using iterator_category = std::forward_iterator_tag;
115 
117  // --- END -- Data types ---------------------------------------------------
118 
119  // --- BEGIN -- Constructors -----------------------------------------------
122 
124  zip_iterator(Iters&&... iterators) : fIterators(std::forward<Iters>(iterators)...) {}
125 
127  // --- END -- Constructors -------------------------------------------------
128 
129  // --- BEGIN -- Access -----------------------------------------------------
132 
134  auto operator*() const { return dereference_impl(std::index_sequence_for<Iters...>()); }
135 
137  template <std::size_t Index>
138  decltype(auto) get() const
139  {
140  return std::get<Index>(fIterators);
141  }
142 
144  // --- END -- Access -------------------------------------------------------
145 
146  // --- BEGIN -- Modification -----------------------------------------------
149 
152  {
153  increment_impl(std::index_sequence_for<Iters...>());
154  return *this;
155  }
156 
160  {
161  this_iterator_t old(*this);
162  operator++();
163  return old;
164  }
165 
167  // --- END -- Modification -------------------------------------------------
168 
169  // --- BEGIN -- Comparisons ------------------------------------------------
172 
174  template <std::size_t OtherLead, typename... OtherIter>
176  {
177  return get<Lead>() != other.template get<OtherLead>();
178  }
179 
181  template <std::size_t OtherLead, typename... OtherIter>
183  {
184  return get<Lead>() == other.template get<OtherLead>();
185  }
186 
188  // --- END -- Comparisons --------------------------------------------------
189 
190  private:
191  std::tuple<Iters...> fIterators;
192 
194  template <typename... Args>
195  static void expandStatements(Args&... args)
196  {}
197 
198  template <std::size_t... Indices>
199  void increment_impl(std::index_sequence<Indices...>)
200  {
201  expandStatements(++std::get<Indices>(fIterators)...);
202  }
203 
204  template <std::size_t... Indices>
205  auto dereference_impl(std::index_sequence<Indices...>) const
206  {
207  // std::tie returns a tuple of references, which is what we want.
208  return std::tie(*std::get<Indices>(fIterators)...);
209  }
210 
211  }; // class zip_iterator
212 
213  //----------------------------------------------------------------------------
214  template <std::size_t Lead, typename... Iterables>
215  auto make_zip_begin_iterator(Iterables&&... iterables)
216  {
217  using std::begin;
218  return zip_iterator<Lead, decltype(begin(iterables))...>{begin(iterables)...};
219  }
220 
221  //----------------------------------------------------------------------------
222  template <std::size_t Lead, typename... Iterables>
223  auto make_zip_end_iterator(Iterables&&... iterables)
224  {
225  using std::end;
226  return zip_iterator<Lead, decltype(end(iterables))...>{end(iterables)...};
227  }
228 } // namespace util::details
229 
230 //------------------------------------------------------------------------------
231 template <std::size_t Lead /* = 0U */, typename... Iterables>
232 auto util::zip(Iterables&&... iterables)
233 {
234  static_assert(sizeof...(Iterables) > 0, "Must zip at least one iterable.");
235  return span{details::make_zip_begin_iterator<Lead>(iterables...),
236  details::make_zip_end_iterator<Lead>(iterables...)};
237 }
238 
239 //------------------------------------------------------------------------------
240 
241 #endif // LARCOREALG_COREUTILS_ZIP_H
void increment_impl(std::index_sequence< Indices... >)
Definition: zip.h:199
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:26
bool operator!=(zip_iterator< OtherLead, OtherIter... > const &other) const
Comparison (based on the Lead iterator only).
Definition: zip.h:175
An object with a begin and end iterator.
std::tuple< Iters... > fIterators
Tuple of all zipped iterators.
Definition: zip.h:191
std::add_pointer_t< std::remove_reference_t< reference >> pointer
Definition: zip.h:113
auto dereference_impl(std::index_sequence< Indices... >) const
Definition: zip.h:205
bool operator==(zip_iterator< OtherLead, OtherIter... > const &other) const
Comparison (based on the Lead iterator only).
Definition: zip.h:182
auto make_zip_begin_iterator(Iterables &&...iterables)
Definition: zip.h:215
STL namespace.
decltype(auto) get() const
Returns the iterator at the specified Index.
Definition: zip.h:138
Simple class with a begin and an end.
Definition: span.h:129
std::tuple< typename std::iterator_traits< Iters >::reference... > reference
Definition: zip.h:111
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
static void expandStatements(Args &...args)
Helper to trigger parameter pack expansion in expressions.
Definition: zip.h:195
this_iterator_t operator++(int)
Definition: zip.h:159
auto operator*() const
Returns a tuple with values from all dereferenced iterators.
Definition: zip.h:134
std::ptrdiff_t difference_type
Definition: zip.h:110
std::remove_cv_t< reference > value_type
Definition: zip.h:112
this_iterator_t & operator++()
Increments all the iterators.
Definition: zip.h:151
auto zip(Iterables &&...iterables)
Range-for loop helper iterating across many collections at the same time.
Definition: zip.h:232
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
zip_iterator(Iters &&...iterators)
Constructor: copies all iterator values.
Definition: zip.h:124
auto make_zip_end_iterator(Iterables &&...iterables)
Definition: zip.h:223
std::forward_iterator_tag iterator_category
Definition: zip.h:114