ContainerMeta.h
Go to the documentation of this file.
1 /** ****************************************************************************
2  * @file larcorealg/CoreUtils/ContainerMeta.h
3  * @brief C++ metaprogramming utilities for dealing with containers.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date July 27, 2017
6  * @ingroup Metaprogramming
7  */
8 
9 #ifndef LARCOREALG_COREUTILS_CONTAINERMETA_H
10 #define LARCOREALG_COREUTILS_CONTAINERMETA_H
11 
12 // LArSoft
13 #include "larcorealg/CoreUtils/MetaUtils.h" // for Doxygen documentation
14 
15 // C/C++ standard libraries
16 #include <iterator> // std::begin(), std::cbegin()
17 #include <functional> // std::reference_wrapper<>
18 #include <memory> // std::unique_ptr<>
19 #include <utility> // std::declval()
20 #include <type_traits> // std::enable_if_t<>
21 
22 
23 namespace util {
24 
25 
26  //--- BEGIN ContainerMetaprogramming -----------------------------------------
27  /**
28  * @defgroup ContainerMetaprogramming Traits for containers
29  * @brief Simple traits for container classes.
30  * @ingroup Metaprogramming
31  *
32  * Trait classes describing a type have a `type` member defined after that
33  * type. They are also available as template types, in the fashion of C++14.
34  *
35  * Trait classes describing a value have a `value` member (static, constexpr)
36  * defined with that value. They are also available as template constants,
37  * in the fashion of C++17.
38  *
39  *
40  * Container value traits
41  * -----------------------
42  *
43  * Container classes mimicking the C++ STL interface provide a `value_type`
44  * type detailing the contained object. This is generalised in the
45  * `util::collection_value_type` trait, which can be specialised for
46  * containers which do not support that.
47  *
48  * Two additional traits are provided, which describe the type obtained by
49  * accessing an element of the container. This is a close relative of
50  * `util::collection_value_type`, but it may be decorated by l-value reference
51  * or constantness depending on the container. The two traits represent access
52  * one to a container that is mutable, the other to one that is constant.
53  *
54  */
55  /// @{
56 
57 
58  //----------------------------------------------------------------------------
59  /// Trait of value contained in the template collection `Coll`.
60  template <typename Coll>
62 
63  /// Type contained in the collection `Coll`.
64  template <typename Coll>
66 
67 
68  //----------------------------------------------------------------------------
69  /// Trait of type obtained by access to element of collection `Coll`.
70  template <typename Coll>
72 
73  /// Type obtained by constant access to element of collection `Coll`.
74  template <typename Coll>
77 
78 
79  //----------------------------------------------------------------------------
80  /// Trait of type obtained by constant access to element of collection `Coll`.
81  template <typename Coll>
83 
84  /// Type obtained by constant access to element of collection `Coll`.
85  template <typename Coll>
88 
89 
90  //----------------------------------------------------------------------------
91  /**
92  * @brief Trait of a type that can be used to reference the collection `Coll`.
93  * @tparam Coll type of the collection to be referenced
94  *
95  * The goal is to have an object with access to the data of the collection of
96  * type `Coll`: this object should be able to be copied, but should not
97  * duplicate (copy) the data.
98  * The most versatile solution is to have a reference to `Coll`, and in
99  * particular `std::reference_wrapper` does the job. But in some special cases
100  * `Coll` itself will do already, as it is for a bare C pointer.
101  *
102  * This trait describes a type with these characteristics, privileging the
103  * simplest solution.
104  */
105  template <typename Coll>
107 
108  /// The type contained in `util::collection_reference_type` trait.
109  template <typename Coll>
111 
112 
113  /**
114  * @brief Returns an object referencing to the data contained in `coll`.
115  * @tparam Coll type of collection of the data
116  * @return an object referencing to the data contained in `coll`
117  * @see `util::collection_from_reference()`
118  *
119  * The criteria, as well as the type of the returned object, are similar to
120  * `util::collection_reference_type`.
121  * Therefore, for example a C pointer is returned unchanged, while a
122  * `std::vector` is returned wrapped into a `std::reference_wrapper`.
123  * A `std::unique_ptr` is returned as bare pointer, given that the returned
124  * object does not own the data.
125  *
126  */
127  template <typename Coll>
128  auto make_collection_reference(Coll&& coll);
129 
130 
131  /**
132  * @brief Trait with the type of collection referenced by `collRef`.
133  * @tparam CollRef type of collection of the data
134  * @see `util::make_collection_reference()`,
135  * `util::collection_from_reference()`
136  *
137  * The type is a direct reference to the unwrapper container.
138  * For example, a `CollRef` instance of `std::reference_wrapper` will result
139  * in a C reference of the wrapped container, while a C pointer is left
140  * unchanged and a `std::unique_ptr` is turned into the equivalent pointer
141  * to its elements.
142  */
143  template <typename Cont>
145 
146  /// Type contained in `util::collection_from_reference_type` trait.
147  template <typename Cont>
150 
151  /**
152  * @brief Returns the object referenced by `collRef` as a C++ reference.
153  * @tparam CollRef type of collection of the data
154  * @param collRef collection of the data to be referenced to
155  * @return a reference to the object referenced by `collRef`
156  * @see `util::make_collection_reference()`
157  *
158  * The return value is a direct reference to the unwrapped container
159  * `collRef`.
160  * For example, a `collRef` of type `std::reference_wrapper` will result
161  * in a C reference of the wrapped container, while a C pointer is left
162  * unchanged and a `std::unique_ptr` object is turned into the equivalent
163  * pointer to its elements.
164  */
165  template <typename CollRef>
166  decltype(auto) collection_from_reference(CollRef& collRef);
167 
168  /// @}
169  //--- END ContainerMetaprogramming -------------------------------------------
170 
171 
172 } // namespace util
173 
174 
175 //------------------------------------------------------------------------------
176 //--- template implementation
177 //------------------------------------------------------------------------------
178 namespace util {
179 
180  namespace details {
181 
182  //--------------------------------------------------------------------------
183  //--- collection_value_XXXX
184  //--------------------------------------------------------------------------
185  template <typename Ptr>
187 
188  template <typename T>
190  using type = T;
191  using value_type = type;
192  }; // struct collection_value_type_impl_pointer<T*>
193 
194  template <typename T>
196  using type = T;
197  using value_type = type;
198  }; // struct collection_value_type_impl_pointer<T[]>
199 
200  template <typename T, std::size_t N>
202  using type = T;
203  using value_type = type;
204  }; // struct collection_value_type_impl_pointer<T[N]>
205 
206 
207  template <typename Ptr, typename = void>
209  : collection_value_type_impl_pointer<typename Ptr::pointer>
210  {};
211 
212 
213  template <typename Coll, typename = void>
215  using type = typename Coll::value_type;
216  using value_type = type;
217  }; // struct collection_value_type_impl
218 
219  template <typename Coll>
221  <Coll, std::enable_if_t<std::is_pointer_v<std::decay_t<Coll>>>>
222  : collection_value_type_impl_pointer<std::decay_t<Coll>>
223  {};
224 
225  template <typename Coll>
227  <Coll, std::enable_if_t<util::is_unique_ptr_v<std::decay_t<Coll>>>>
228  : collection_value_type_impl_unique_ptr<std::decay_t<Coll>>
229  {};
230 
231 
232  //--------------------------------------------------------------------------
233  template <typename Coll, typename = void>
235  private:
236  static auto getBegin(Coll&& coll)
237  { using std::begin; return begin(coll); }
238 
239  public:
240  using type = decltype(*getBegin(std::declval<Coll>()));
242 
243  }; // struct collection_value_access_type_impl
244 
245  template <typename T>
247  using type = decltype(*(std::declval<T*>()));
248  using value_type = T;
249  }; // struct collection_value_access_type_impl<T*>
250 
251 
252  template <typename Ptr>
254  <Ptr, std::enable_if_t<util::is_unique_ptr_v<std::decay_t<Ptr>>>>
256  <std::remove_reference_t<typename Ptr::pointer>>
257  {};
258 
259 
260  //--------------------------------------------------------------------------
261  template <typename Coll, typename = void>
263  private:
264  static auto getCBegin(Coll&& coll)
265  { using std::cbegin; return cbegin(coll); }
266 
267  public:
268  using type = decltype(*getCBegin(std::declval<Coll>()));
270 
271  }; // struct collection_value_constant_access_type_impl
272 
273  template <typename T>
275  using type = decltype(*(std::declval<std::add_const_t<T>*>()));
276  using value_type = std::add_const_t<T>;
277  }; // struct collection_value_constant_access_type_impl
278 
279  template <typename Ptr>
281  <Ptr, std::enable_if_t<util::is_unique_ptr_v<std::decay_t<Ptr>>>>
283  <std::remove_reference_t<typename Ptr::pointer>>
284  {};
285 
286 
287  //--------------------------------------------------------------------------
288  //--- util::make_collection_reference
289 
290  template <typename Coll, typename = void>
292  using type = std::reference_wrapper<Coll>;
293  static auto make(Coll& coll) { return std::ref(coll); }
294  }; // make_collection_reference_impl
295 
296  template <typename Coll>
298  <Coll, std::enable_if_t<util::is_reference_wrapper_v<Coll>>>
299  {
300  using type = std::remove_cv_t<Coll>;
301  static type make(Coll& refw) { return refw; }
302  }; // make_collection_reference_impl<std::reference_wrapper>
303 
304  template <typename Coll>
306  <Coll, std::enable_if_t<util::is_unique_ptr_v<Coll>>>
307  {
308  using type = typename Coll::pointer;
309  static type make(Coll& uptr) { return uptr.get(); }
310  }; // make_collection_reference_impl<std::unique_ptr>
311 
312  template <typename Ptr>
314  <Ptr, std::enable_if_t<std::is_pointer_v<std::decay_t<Ptr>>>>
315  {
316  using type =
317  std::add_pointer_t< // finally add the pointer
318  std::remove_all_extents_t< // if it's a C array
319  std::remove_pointer_t<std::decay_t<Ptr>>
320  >
321  >;
322  static type make(Ptr& ptr) { return ptr; }
323  }; // make_collection_reference_impl<std::unique_ptr>
324 
325 
326  //--------------------------------------------------------------------------
327  //--- util::collection_from_reference
328 
329  template <typename CollRef, typename = void>
331  using type
332  = std::add_lvalue_reference_t<std::remove_reference_t<CollRef>>;
333  static CollRef& get(CollRef& coll) { return coll; }
334  }; // collection_from_reference_impl
335 
336  template <typename CollRef>
338  <CollRef, std::enable_if_t<util::is_reference_wrapper_v<CollRef>>>
339  {
340  using type = std::add_lvalue_reference_t<typename CollRef::type>;
341  static type get(CollRef& refw) { return refw.get(); }
342  }; // collection_from_reference_impl<std::reference_wrapper>
343 
344  template <typename CollRef>
346  <CollRef, std::enable_if_t<util::is_unique_ptr_v<CollRef>>>
347  {
348  using type = typename CollRef::pointer;
349  static type get(CollRef& uptr) { return uptr.get(); }
350  }; // collection_from_reference_impl<std::unique_ptr>
351 
352  template <typename T>
354  using type = T*;
355  static type get(T* ptr) { return ptr; }
356  }; // collection_from_reference_impl<T*>
357 
358  template <typename T>
360  using type = T*;
361  static type get(T ptr[]) { return ptr; }
362  }; // collection_from_reference_impl<T[]>
363 
364  template <typename T, std::size_t N>
366  using type = T*;
367  static type get(T ptr[N]) { return ptr; }
368  }; // collection_from_reference_impl<T[N]>
369 
370 
371  //--------------------------------------------------------------------------
372 
373  } // namespace details
374 
375 
376  //----------------------------------------------------------------------------
377  template <typename Coll>
378  struct collection_value_type {
379  // remove all referenceness, constantness etc. from `Coll`;
380  // also remove all referenceness from the result
384  >
385  ;
386  };
387 
388 
389  //----------------------------------------------------------------------------
390  template <typename Coll>
393  <util::strip_referenceness_t<Coll>>
394  {};
395 
396 
397  //----------------------------------------------------------------------------
398  template <typename Coll>
401  <util::strip_referenceness_t<Coll>>
402  {};
403 
404 
405  //----------------------------------------------------------------------------
406  template <typename Coll>
408  : details::make_collection_reference_impl<std::remove_reference_t<Coll>>
409  {};
410 
411  //----------------------------------------------------------------------------
412  template <typename Coll>
413  auto make_collection_reference(Coll&& coll) {
415  ::make(coll)
416  ;
417  }
418 
419  //----------------------------------------------------------------------------
420  template <typename CollRef>
422  : details::collection_from_reference_impl<std::remove_reference_t<CollRef>>
423  {};
424 
425  //----------------------------------------------------------------------------
426  template <typename CollRef>
427  decltype(auto) collection_from_reference(CollRef& collRef)
429 
430  //----------------------------------------------------------------------------
431 
432 } // namespace util
433 
434 
435 //------------------------------------------------------------------------------
436 
437 #endif // LARCOREALG_COREUTILS_CONTAINERMETA_H
438 
auto make_collection_reference(Coll &&coll)
Returns an object referencing to the data contained in coll.
static CollRef & get(CollRef &coll)
typename collection_value_access_type< Coll >::type collection_value_access_t
Type obtained by constant access to element of collection Coll.
Definition: ContainerMeta.h:76
typename strip_referenceness_type< T >::type strip_referenceness_t
The type T stripped of all known reference types.
Definition: MetaUtils.h:574
util::strip_referenceness_t< typename details::collection_value_type_impl< util::strip_referenceness_t< Coll >>::type > type
Namespace for general, non-LArSoft-specific utilities.
Basic C++ metaprogramming utilities.
Trait of type obtained by constant access to element of collection Coll.
Definition: ContainerMeta.h:82
std::add_lvalue_reference_t< std::remove_reference_t< std::remove_reference_t< CollRef > >> type
STL namespace.
Trait with the type of collection referenced by collRef.
Trait of type obtained by access to element of collection Coll.
Definition: ContainerMeta.h:71
typename collection_reference_type< Coll >::type collection_reference_t
The type contained in util::collection_reference_type trait.
Trait of a type that can be used to reference the collection Coll.
typename collection_from_reference_type< Cont >::type collection_from_reference_t
Type contained in util::collection_from_reference_type trait.
std::reference_wrapper< std::remove_reference_t< Coll > > type
unique_ptr< InputSource > make(ParameterSet const &conf, InputSourceDescription &desc)
static QCString type
Definition: declinfo.cpp:672
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
Definition: StdUtils.h:82
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
typename collection_value_type< Coll >::type collection_value_t
Type contained in the collection Coll.
Definition: ContainerMeta.h:65
decltype(auto) collection_from_reference(CollRef &collRef)
Returns the object referenced by collRef as a C++ reference.
typename collection_value_constant_access_type< Coll >::type collection_value_constant_access_t
Type obtained by constant access to element of collection Coll.
Definition: ContainerMeta.h:87
Trait of value contained in the template collection Coll.
Definition: ContainerMeta.h:61