get_elements.h
Go to the documentation of this file.
1 /**
2  * @file larcorealg/CoreUtils/get_elements.h
3  * @brief Definition of `util::get_elements()` and `util::get_const_elements()`.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date December 13, 2019
6  *
7  * This is a header-only library.
8  */
9 
10 #ifndef LARCOREALG_COREUTILS_GET_ELEMENTS_H
11 #define LARCOREALG_COREUTILS_GET_ELEMENTS_H
12 
13 
14 // LArSoft libraries
15 #include "larcorealg/CoreUtils/span.h" // util::make_transformed_span()
16 #include "larcorealg/CoreUtils/StdUtils.h" // util::get()
17 
18 // C/C++ libraries
19 #include <utility> // std::get()
20 #include <type_traits>
21 #include <cstddef> // std::size_t
22 
23 
24 namespace util {
25 
26 
27  // -- BEGIN -- Transformed iterations ----------------------------------------
28  /// @name Transformed iterations
29  /// @{
30 
31  /**
32  * @brief Range-for loop helper iterating across some of the element of
33  * each value in the specified collection.
34  * @tparam Indices indices of the elements to extract
35  * @tparam Coll type of the collection to iterate through
36  * @param coll the collection to iterate through
37  * @return an object suitable for range-for loop
38  * @see `util::get_const_elements()`
39  *
40  * This function enables range-for loops with a selection of elements from
41  * a container of `tuple` (or anything responding to `util::get()`).
42  *
43  * The following example fills a map using as key the first element (`0U`)
44  * of a tuple and as value the third element (`2U`):
45  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
46  * std::vector<std::tuple<char, int, float>> data
47  * { { 'z', 0, 1.0F }, { 'o', 1, 3.0F }, { 't', 2, 9.0F } };
48  * std::map<char, double> factors;
49  *
50  * for (auto const& [ letter, factor ]: util::get_elements<0U, 2U>(data)) {
51  * factors.emplace(letter, factor);
52  * }
53  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54  * If only one index is specified, the loop will not use structured binding,
55  * but rather a simple variable:
56  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
57  * std::vector<int> exponents;
58  *
59  * for (int exponent: util::get_elements<1U>(data)) {
60  * exponents.push_back(exponent);
61  * }
62  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
63  *
64  * While the examples do not demonstrate changing the values in the `data`
65  * collection, that is also supported.
66  *
67  * @note This function also works with associative containers based on
68  * `std::pair` (`std::map` and the likes).
69  */
70  template <std::size_t... Indices, typename Coll>
71  decltype(auto) get_elements(Coll&& coll);
72 
73  /**
74  * @brief Range-for loop helper iterating across the constant values of the
75  * specified collection.
76  * @see `util::values()`
77  *
78  * This function is equivalent to `util::values()` but the values are
79  * extracted as if the specified collection were constant.
80  */
81  template <std::size_t... Indices, typename Coll>
82  decltype(auto) get_const_elements(Coll&& coll);
83 
84 
85  /// @}
86  // -- END -- Transformed iterations ------------------------------------------
87 
88 
89 } // namespace util
90 
91 
92 //==============================================================================
93 //=== template implementation
94 //==============================================================================
95 //------------------------------------------------------------------------------
96 //--- util::values()
97 //------------------------------------------------------------------------------
98 namespace util::details {
99 
100  //----------------------------------------------------------------------------
101  template <typename Coll, std::size_t First, std::size_t... Others>
103 
104  template <typename T>
105  static constexpr decltype(auto) iterate(T&& coll) noexcept
106  {
107  auto extractor = [](auto&& item) -> decltype(auto)
108  {
109  if constexpr(sizeof...(Others) == 0U) {
110  return util::get<First>(item);
111  }
112  else {
113  return std::forward_as_tuple
114  (util::get<First>(item), util::get<Others...>(item));
115  }
116  };
117  return util::make_transformed_span(coll, extractor);
118  }
119 
120  }; // struct get_elements_impl
121 
122 
123  //----------------------------------------------------------------------------
124 
125 } // namespace util::details
126 
127 
128 //------------------------------------------------------------------------------
129 template <std::size_t... Indices, typename Coll>
130 decltype(auto) util::get_elements(Coll&& coll) {
131  static_assert
132  (sizeof...(Indices) >= 1U, "At least one index must be specified");
133  return details::get_elements_impl<std::decay_t<Coll>, Indices...>::iterate
134  (std::forward<Coll>(coll));
135 } // util::get_elements()
136 
137 
138 //------------------------------------------------------------------------------
139 template <std::size_t... Indices, typename Coll>
140 decltype(auto) util::get_const_elements(Coll&& coll)
141  { return get_elements<Indices...>(std::as_const(coll)); }
142 
143 
144 //------------------------------------------------------------------------------
145 
146 
147 #endif // LARCOREALG_COREUTILS_GET_ELEMENTS_H
Namespace for general, non-LArSoft-specific utilities.
An object with a begin and end iterator.
STL namespace.
decltype(auto) get_elements(Coll &&coll)
Range-for loop helper iterating across some of the element of each value in the specified collection...
decltype(auto) get_const_elements(Coll &&coll)
Range-for loop helper iterating across the constant values of the specified collection.
auto make_transformed_span(BIter begin, EIter end, Op &&op)
Definition: span.h:294
Functions pulling in STL customization if available.