LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
ProviderPack.h
Go to the documentation of this file.
1 
13 #ifndef LARCOREALG_COREUTILS_PROVIDERPACK_H
14 #define LARCOREALG_COREUTILS_PROVIDERPACK_H
15 
16 
17 // C/C++ standard library
18 #include <tuple>
19 #include <type_traits>
20 #include <limits>
21 
22 
23 namespace lar {
24 
25  namespace details {
26 
27  template <typename... Types>
29 
30 
43  template <typename Derived, typename... Bases>
44  constexpr std::size_t indexOfBaseOf();
45 
46  template <typename Derived, typename... Bases>
47  constexpr std::size_t indexOfDerivedFrom();
48 
57  template <typename Derived, typename... Bases>
58  constexpr std::size_t findBaseOf();
59 
60  template <typename Derived, typename... Bases>
61  constexpr std::size_t findDerivedFrom();
62 
72  template <typename Derived, typename... Bases>
73  constexpr std::size_t hasBaseOf()
74  { return indexOfBaseOf<Derived, Bases...>() < sizeof...(Bases); }
75 
76  template <typename Derived, typename... Bases>
77  constexpr std::size_t hasDerivedFrom()
78  { return indexOfDerivedFrom<Derived, Bases...>() < sizeof...(Bases); }
79 
80 
82  template
83  <typename DestPack, typename SourcePack, typename... ExtractProviders>
84  struct SetFrom;
85 
86  } // namespace details
87 
88 
113  template <typename... Providers>
114  class ProviderPack {
116  "Providers in ProviderPack are repeated");
117 
118  using this_type = ProviderPack<Providers...>;
119 
121  using tuple_type = std::tuple<Providers const*...>;
122 
123  public:
124 
126  ProviderPack() = default;
127 
129  ProviderPack(Providers const* ...provider_ptrs): providers(provider_ptrs...)
130  {}
131 
140  template<typename... OtherProviders>
142  {
144  <this_type, ProviderPack<OtherProviders...>, Providers...>
145  (*this, from);
146  }
147 
156  template<typename... OtherProviders>
157  ProviderPack(OtherProviders const*... providers)
158  {
160  <this_type, ProviderPack<OtherProviders...>, Providers...>
161  (*this, ProviderPack<OtherProviders...>(providers...));
162  }
163 
184  template<typename... PackProviders, typename... OtherProviders>
185  ProviderPack(
186  ProviderPack<PackProviders...> const& fromPack,
187  OtherProviders const*... providers
188  );
189 
190 
192  template <typename Provider>
193  Provider const* get() const
194  {
195  constexpr auto providerIndex
196  = details::findDerivedFrom<Provider, Providers...>();
197  return std::get<providerIndex>(providers);
198  } // get<>()
199 
200 
202  template <typename Provider>
203  void set(Provider const* provider_ptr)
204  {
205  constexpr auto providerIndex
206  = details::findDerivedFrom<Provider, Providers...>();
207  std::get<providerIndex>(providers) = provider_ptr;
208  } // set<>()
209 
211  template <typename Provider>
212  static constexpr bool has()
213  { return details::hasDerivedFrom<Provider, Providers...>(); }
214 
215 
217  template <typename... OtherProviders>
219 
221  template <typename... OtherProviders>
222  bool operator!= (ProviderPack<OtherProviders...> const& other) const;
223 
224 
246  template <typename... OtherProviders>
247  static constexpr bool containsProviders();
248 
249  private:
250 
252 
253  }; // class ProviderPack
254 
255 
271  template <typename... Providers>
272  ProviderPack<Providers...> makeProviderPack(Providers const* ...providers)
273  { return ProviderPack<Providers...>(providers...); }
274 
275 
296  template <typename... PackProviders, typename... MoreProviders>
297  ProviderPack<PackProviders..., MoreProviders...> expandProviderPack(
298  ProviderPack<PackProviders...> const& pack,
299  MoreProviders const* ...providers
300  )
301  { return { pack, providers... }; }
302 
303 
304 } // namespace lar
305 
306 
307 //------------------------------------------------------------------------------
308 //--- Implementation details
309 //---
310 namespace lar {
311  namespace details {
312 
313  template <bool Value>
314  using bool_constant = std::integral_constant<bool, Value>; // also in C++17
315 
316  template <std::size_t Value>
317  using index_constant = std::integral_constant<std::size_t, Value>;
318 
319  //--------------------------------------------------------------------------
320  //--- has_type, has_duplicate_types, are_same_types
321  //---
322  template <typename Target, typename... Types>
323  struct has_type;
324 
325  template <typename Target, typename First, typename... Others>
326  struct has_type<Target, First, Others...>: has_type<Target, Others...> {};
327 
328  template <typename Target, typename... Others>
329  struct has_type<Target, Target, Others...>: std::true_type {};
330 
331  template <typename Target>
332  struct has_type<Target>: std::false_type {};
333 
334 
335  //--------------------------------------------------------------------------
336  template <typename Key, typename... Types>
337  struct has_duplicate_types<Key, Types...>:
338  public bool_constant
339  <has_type<Key, Types...>() || has_duplicate_types<Types...>()>
340  {};
341 
342  template <>
343  struct has_duplicate_types<>: public std::false_type {};
344 
345 
346  //--------------------------------------------------------------------------
347  template <typename... Types>
349 
350  template <typename... Types>
351  struct are_same_types {
352 
353  template <typename... AsTypes>
354  static constexpr bool as()
355  {
356  return (sizeof...(Types) == sizeof...(AsTypes))
357  && are_types_contained<Types...>::template in<AsTypes...>();
358  }
359 
360  }; // are_same_types
361 
362 
363  template <typename First, typename... OtherTypes>
364  struct are_types_contained<First, OtherTypes...> {
365  template <typename... AsTypes>
366  static constexpr bool in()
367  {
368  return are_types_contained<OtherTypes...>::template in<AsTypes...>()
370  }
371  };
372 
373  template <typename First>
374  struct are_types_contained<First> {
375  template <typename... AsTypes>
376  static constexpr bool in()
377  { return has_type<First, AsTypes...>(); }
378  };
379 
380 
381  template <typename T>
382  struct is_provider_pack: public std::false_type {};
383 
384  template <typename... Providers>
385  struct is_provider_pack<ProviderPack<Providers...>>: public std::true_type
386  {};
387 
388 
389  template <typename APack, typename BPack>
390  struct have_same_provider_types: public std::false_type {};
391 
392  template <typename... AProviders, typename... BProviders>
394  <ProviderPack<AProviders...>, ProviderPack<BProviders...>>
395  : public std::integral_constant
396  <bool, are_same_types<AProviders...>::template as<BProviders...>()>
397  {};
398 
399 
400  // --- BEGIN impementation of findDerivedFrom() ----------------------------
401  //
402  // This is the implementation of findDerivedFrom() and findBaseOf().
403  // The functions are expected to assert that there is exactly one answer to
404  // a matching condition: for findDerivedFrom() that answer is which is the
405  // derived class of Base among Derived, for findBaseOf() is the opposite.
406  //
407  // The implementation finds and returns the index of first class matching
408  // the condition, and it asserts that the answer is valid.
409  // It also finds the index of the next class matching the condition, just to
410  // assert that it is not valid (that is, there is no other matching class).
411  //
412  // The class returning the index of the first matching class is implemented
413  // recursively, on a class taking the target class, the first of the
414  // candidate classes, and then all the others in a parameter pack.
415  // When the first candidate satisfies the condition, then the recursion is
416  // over. In the simplest case, where we are just looking for a specific
417  // class, the condition (the Target is the same as the First Candidate) can
418  // be implied and the compiler can implement it directly with parameter
419  // matching. In our cases the condition is non-trivial and we use a
420  // two-level recursion: the outer level, the "dispatcher", invokes a
421  // different "answer" class whether the condition is true or false. In the
422  // former case a result is presented; in the other case recursion ensues,
423  // back to the dispatcher. The dispatcher can also terminate the recursion
424  // when no answer is found. If recursion is terminated without a match, an
425  // invalid index is returned.
426  //
427  // The class returning the next matching class is simply skipping a number
428  // of candidates, and then behaving like the one looking for the first
429  // matching candidate.
430  //
431 
432  //
433  // class to find the first matching class
434  //
435  template <
436  template <typename A, typename B> class Match,
437  typename Target, bool IsMatch, typename... Candidates
438  >
440 
441  template <
442  template <typename A, typename B> class Match,
443  typename Target, typename... Candidates
444  >
445  struct findFirstMatching_answer<Match, Target, true, Candidates...>
446  : public index_constant<0U>
447  {};
448 
449  template <
450  template <typename A, typename B> class Match,
451  typename Target, typename... Candidates
452  >
454 
455  // end-of-recursion
456  template <
457  template <typename A, typename B> class Match,
458  typename Target
459  >
460  struct findFirstMatching_dispatcher<Match, Target>
461  : findFirstMatching_answer<Match, Target, true>
462  {};
463 
464  template <
465  template <typename A, typename B> class Match,
466  typename Target, typename FirstCandidate, typename... OtherCandidates
467  >
469  <Match, Target, FirstCandidate, OtherCandidates...>
470  : public findFirstMatching_answer<
471  Match,
472  Target,
473  Match<FirstCandidate, Target>::value,
474  FirstCandidate,
475  OtherCandidates...
476  >
477  {};
478 
479  template <
480  template <typename A, typename B> class Match,
481  typename Target, typename FirstCandidate, typename... OtherCandidates
482  >
484  <Match, Target, false, FirstCandidate, OtherCandidates...>
485  : public index_constant
486  <(1U + findFirstMatching_dispatcher<Match, Target, OtherCandidates...>::value)>
487  {};
488 
489  template <
490  template <typename A, typename B> class Match,
491  typename Target, typename... Candidates
492  >
494  : findFirstMatching_dispatcher<Match, Target, Candidates...>
495  {
496  private:
497  static constexpr auto _index
498  = findFirstMatching_dispatcher<Match, Target, Candidates...>();
499  }; // struct findFirstMatching_impl
500 
501 
502  //
503  // class to apply findFirstMatching_impl after skipping some candidates
504  //
505  template <
506  unsigned int NSkip,
507  template <typename A, typename B> class Match,
508  typename Target, typename... Candidates
509  >
511 
512  // recursion: peel one
513  template <
514  unsigned int NSkip,
515  template <typename A, typename B> class Match,
516  typename Target, typename FirstCandidate, typename... OtherCandidates
517  >
519  <NSkip, Match, Target, FirstCandidate, OtherCandidates...>
520  : index_constant<(
521  1U
522  + findNextMatching_impl
523  <(NSkip - 1U), Match, Target, OtherCandidates...>::value
524  )>
525  {
526  static_assert(NSkip > 0U, "Implementation error: no arguments to skip!");
527  };
528 
529  // end-of-recursion: skipped enough
530  template <
531  template <typename A, typename B> class Match,
532  typename Target, typename FirstCandidate, typename... OtherCandidates
533  >
535  <0U, Match, Target, FirstCandidate, OtherCandidates...>
537  <Match, Target, FirstCandidate, OtherCandidates...>
538  {};
539 
540  // end-of-recursion: all arguments skipped
541  template <
542  unsigned int NSkip,
543  template <typename A, typename B> class Match,
544  typename Target
545  >
546  struct findNextMatching_impl<NSkip, Match, Target>
547  : findFirstMatching_impl<Match, Target>
548  {};
549 
550  //
551  // class finding a match and asserting its existence and unicity
552  //
553  template <
554  template <typename A, typename B> class Match,
555  typename Target, typename... Candidates
556  >
558  : findFirstMatching_impl<Match, Target, Candidates...>
559  {
560  private:
561  static constexpr auto _index
562  = findFirstMatching_dispatcher<Match, Target, Candidates...>();
563 
564  static_assert(
566  >= sizeof...(Candidates),
567  "Multiple candidate classes match the Target one"
568  );
569  }; // struct findTheMatching_impl
570 
571  //
572  // implementations with concrete matching conditions
573  //
574  template <typename Derived, typename... Bases>
575  constexpr std::size_t indexOfBaseOf()
576  { return findTheMatching_impl<std::is_base_of, Derived, Bases...>(); }
577 
578  template <typename Derived, typename... Bases>
579  constexpr std::size_t findBaseOf()
580  {
581  constexpr std::size_t index = indexOfBaseOf<Derived, Bases...>();
582  static_assert(
583  index < sizeof...(Bases),
584  "Target is not derived from any of the available classes"
585  );
586  return index;
587  } // findBaseOf()
588 
589  // this matching condition is the mirror of std::is_base_of
590  template <typename Derived, typename Base>
591  struct is_derived_of: std::is_base_of<Base, Derived> {};
592 
593  template <typename Base, typename... Derived>
594  constexpr std::size_t indexOfDerivedFrom()
595  { return findTheMatching_impl<is_derived_of, Base, Derived...>(); }
596 
597  template <typename Base, typename... Derived>
598  constexpr std::size_t findDerivedFrom()
599  {
600  constexpr std::size_t index = indexOfDerivedFrom<Base, Derived...>();
601  static_assert(
602  index < sizeof...(Derived),
603  "Target is not base of any of the available classes"
604  );
605  return index;
606  } // findDerivedFrom()
607 
608  // --- END impementation of findDerivedFrom() ------------------------------
609 
610 
611  //--------------------------------------------------------------------------
612  //--- SetFrom
613  //---
614  template <
615  typename DestPack, typename SourcePack,
616  typename FirstProvider, typename... OtherProviders
617  >
618  struct SetFrom<DestPack, SourcePack, FirstProvider, OtherProviders...> {
619  SetFrom(DestPack& pack, SourcePack const& from)
620  {
621  pack.set(from.template get<FirstProvider>());
622  SetFrom<DestPack, SourcePack, OtherProviders...>(pack, from);
623  }
624  }; // SetFrom<First, Others...>
625 
626  template <typename DestPack, typename SourcePack>
627  struct SetFrom<DestPack, SourcePack> {
628  SetFrom(DestPack&, SourcePack const&) {}
629  };
630 
631  //--------------------------------------------------------------------------
632  //--- Compare
633  //---
634  template <typename Provider, typename APack, typename BPack>
635  bool haveSameProvider(APack const& a, BPack const& b) {
637  "This class needs two ProviderPack template types.");
638  return a.template get<Provider>() == b.template get<Provider>();
639  } // haveSameProvider()
640 
641 
642  template <typename APack, typename BPack>
644 
646  "The specified provider packs have different types.");
647 
648  }; // ProviderPackComparerBase
649 
650 
651  template <typename APack, typename BPack, typename... Providers>
653 
654  template
655  <typename APack, typename BPack, typename First, typename... Others>
656  struct ProviderPackComparer<APack, BPack, First, Others...>
657  : ProviderPackComparerBase<APack, BPack>
658  {
659  static bool compare (APack const& a, BPack const& b)
660  {
661  return haveSameProvider<First>(a, b)
663  }
664  }; // ProviderPackComparer<APack, BPack, First, Others...>
665 
666  template
667  <typename APack, typename BPack, typename First>
668  struct ProviderPackComparer<APack, BPack, First>
669  : ProviderPackComparerBase<APack, BPack>
670  {
671  static bool compare (APack const& a, BPack const& b)
672  { return haveSameProvider<First>(a, b); }
673  }; // ProviderPackComparer<APack, BPack, First>
674 
675 
676  //--------------------------------------------------------------------------
677 
678  } // namespace details
679 
680 
681  //----------------------------------------------------------------------------
682  //--- ProviderPack
683  //---
684 
685  template <typename... Providers>
686  template<typename... PackProviders, typename... OtherProviders>
688  ProviderPack<PackProviders...> const& fromPack,
689  OtherProviders const*... providers
690  )
691  {
692 
693  // verify that the list of providers in argument is the exact one we need
694  static_assert(
696  ::template as<PackProviders..., OtherProviders...>(),
697  "The providers types in the arguments do not match the ones needed."
698  );
699 
700  // copy all the providers from the provider pack
702  <this_type, ProviderPack<PackProviders...>, PackProviders...>
703  (*this, fromPack);
704 
705  // put the other providers in a temporary parameter pack, and copy it
706  // (this is convenience, a direct implementation would be probably better)
708  <this_type, ProviderPack<OtherProviders...>, OtherProviders...>
709  (*this, makeProviderPack(providers...));
710 
711  } // ProviderPack<Providers...>::ProviderPack(ProviderPack, OtherProviders...)
712 
713 
714  //----------------------------------------------------------------------------
715  template <typename... Providers>
716  template <typename... OtherProviders>
717  bool ProviderPack<Providers...>::operator==
718  (ProviderPack<OtherProviders...> const& other) const
719  {
721  ProviderPack<Providers...>, ProviderPack<OtherProviders...>, Providers...
722  >::compare(*this, other);
723  }
724 
725 
726  template <typename... Providers>
727  template <typename... OtherProviders>
728  bool ProviderPack<Providers...>::operator!=
729  (ProviderPack<OtherProviders...> const& other) const
730  { return !(*this == other); }
731 
732 
733  //----------------------------------------------------------------------------
734  template <typename... Providers>
735  template <typename... OfferedProviders>
737  return details::are_types_contained<Providers...>
738  ::template in<OfferedProviders...>();
739  } // ProviderPack<>::containsProviders()
740 
741 
742  //----------------------------------------------------------------------------
743 
744 } // namespace lar
745 
746 #endif // LARCOREALG_COREUTILS_PROVIDERPACK_H
static constexpr bool as()
Definition: ProviderPack.h:354
ProviderPack< PackProviders..., MoreProviders... > expandProviderPack(ProviderPack< PackProviders... > const &pack, MoreProviders const *...providers)
Function to create a ProviderPack by adding to another.
Definition: ProviderPack.h:297
Implementation detail for the extraction constructor.
Definition: ProviderPack.h:84
ProviderPack(Providers const *...provider_ptrs)
Constructor: stores a provider pointer for each type.
Definition: ProviderPack.h:129
std::integral_constant< std::size_t, Value > index_constant
Definition: ProviderPack.h:317
constexpr std::size_t hasDerivedFrom()
Definition: ProviderPack.h:77
static constexpr bool has()
Returns whether there is a provider with the specified type.
Definition: ProviderPack.h:212
std::integral_constant< bool, Value > bool_constant
Definition: ProviderPack.h:314
SetFrom(DestPack &, SourcePack const &)
Definition: ProviderPack.h:628
static constexpr bool containsProviders()
Returns whether all our providers are in the OfferedProviders list.
Definition: ProviderPack.h:736
ProviderPack(ProviderPack< OtherProviders... > const &from)
Constructor: extracts the providers from another parameter pack.
Definition: ProviderPack.h:141
bool haveSameProvider(APack const &a, BPack const &b)
Definition: ProviderPack.h:635
std::tuple< Providers const *... > tuple_type
type used for storage of the pointers
Definition: ProviderPack.h:121
ProviderPack()=default
Default constructor: a null provider pointer for each type.
tuple_type providers
container of the pointers, type-safe
Definition: ProviderPack.h:251
constexpr std::size_t indexOfBaseOf()
Index of the class among Bases which is base of Derived.
Definition: ProviderPack.h:575
constexpr std::size_t findDerivedFrom()
Definition: ProviderPack.h:598
constexpr std::size_t hasBaseOf()
Returns whether there is exactly one base class of Derived among Bases.
Definition: ProviderPack.h:73
ProviderPack< Providers... > makeProviderPack(Providers const *...providers)
Function to create a ProviderPack from the function arguments.
Definition: ProviderPack.h:272
constexpr std::size_t indexOfDerivedFrom()
Definition: ProviderPack.h:594
static bool compare(APack const &a, BPack const &b)
Definition: ProviderPack.h:671
bool operator!=(geometry_element_iterator< GEOIDITER > const &iter, GEOIDITER const &id_iter)
Comparison operator: geometry ID and element point to different IDs.
ifstream in
Definition: comparison.C:7
ProviderPack(OtherProviders const *...providers)
Constructor: picks the providers from the specified ones.
Definition: ProviderPack.h:157
LArSoft-specific namespace.
Container for a list of pointers to providers.
Definition: ProviderPack.h:114
constexpr std::size_t findBaseOf()
Index of the class among Bases which is base of Derived.
Definition: ProviderPack.h:579
bool operator==(geometry_element_iterator< GEOIDITER > const &iter, GEOIDITER const &id_iter)
Comparison operator: geometry ID and element point to the same ID.