LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
ProviderPack.h
Go to the documentation of this file.
1 
12 #ifndef LARCOREALG_COREUTILS_PROVIDERPACK_H
13 #define LARCOREALG_COREUTILS_PROVIDERPACK_H
14 
15 // C/C++ standard library
16 #include <limits>
17 #include <tuple>
18 #include <type_traits>
19 
20 namespace lar {
21 
22  namespace details {
23 
24  template <typename... Types>
26 
39  template <typename Derived, typename... Bases>
40  constexpr std::size_t indexOfBaseOf();
41 
42  template <typename Derived, typename... Bases>
43  constexpr std::size_t indexOfDerivedFrom();
44 
53  template <typename Derived, typename... Bases>
54  constexpr std::size_t findBaseOf();
55 
56  template <typename Derived, typename... Bases>
57  constexpr std::size_t findDerivedFrom();
58 
68  template <typename Derived, typename... Bases>
69  constexpr std::size_t hasBaseOf()
70  {
71  return indexOfBaseOf<Derived, Bases...>() < sizeof...(Bases);
72  }
73 
74  template <typename Derived, typename... Bases>
75  constexpr std::size_t hasDerivedFrom()
76  {
77  return indexOfDerivedFrom<Derived, Bases...>() < sizeof...(Bases);
78  }
79 
81  template <typename DestPack, typename SourcePack, typename... ExtractProviders>
82  struct SetFrom;
83 
84  } // namespace details
85 
110  template <typename... Providers>
111  class ProviderPack {
113  "Providers in ProviderPack are repeated");
114 
115  using this_type = ProviderPack<Providers...>;
116 
118  using tuple_type = std::tuple<Providers const*...>;
119 
120  public:
122  ProviderPack() = default;
123 
125  ProviderPack(Providers const*... provider_ptrs) : providers(provider_ptrs...) {}
126 
135  template <typename... OtherProviders>
137  {
138  details::SetFrom<this_type, ProviderPack<OtherProviders...>, Providers...>(*this, from);
139  }
140 
149  template <typename... OtherProviders>
150  ProviderPack(OtherProviders const*... providers)
151  {
152  details::SetFrom<this_type, ProviderPack<OtherProviders...>, Providers...>(
153  *this, ProviderPack<OtherProviders...>(providers...));
154  }
155 
176  template <typename... PackProviders, typename... OtherProviders>
178  OtherProviders const*... providers);
179 
181  template <typename Provider>
182  Provider const* get() const
183  {
184  constexpr auto providerIndex = details::findDerivedFrom<Provider, Providers...>();
185  return std::get<providerIndex>(providers);
186  } // get<>()
187 
189  template <typename Provider>
190  void set(Provider const* provider_ptr)
191  {
192  constexpr auto providerIndex = details::findDerivedFrom<Provider, Providers...>();
193  std::get<providerIndex>(providers) = provider_ptr;
194  } // set<>()
195 
197  template <typename Provider>
198  static constexpr bool has()
199  {
200  return details::hasDerivedFrom<Provider, Providers...>();
201  }
202 
204  template <typename... OtherProviders>
206 
208  template <typename... OtherProviders>
209  bool operator!=(ProviderPack<OtherProviders...> const& other) const;
210 
232  template <typename... OtherProviders>
233  static constexpr bool containsProviders();
234 
235  private:
237 
238  }; // class ProviderPack
239 
255  template <typename... Providers>
256  ProviderPack<Providers...> makeProviderPack(Providers const*... providers)
257  {
258  return ProviderPack<Providers...>(providers...);
259  }
260 
281  template <typename... PackProviders, typename... MoreProviders>
282  ProviderPack<PackProviders..., MoreProviders...> expandProviderPack(
283  ProviderPack<PackProviders...> const& pack,
284  MoreProviders const*... providers)
285  {
286  return {pack, providers...};
287  }
288 
289 } // namespace lar
290 
291 //------------------------------------------------------------------------------
292 //--- Implementation details
293 //---
294 namespace lar {
295  namespace details {
296 
297  template <bool Value>
298  using bool_constant = std::integral_constant<bool, Value>; // also in C++17
299 
300  template <std::size_t Value>
301  using index_constant = std::integral_constant<std::size_t, Value>;
302 
303  //--------------------------------------------------------------------------
304  //--- has_type, has_duplicate_types, are_same_types
305  //---
306  template <typename Target, typename... Types>
307  struct has_type;
308 
309  template <typename Target, typename First, typename... Others>
310  struct has_type<Target, First, Others...> : has_type<Target, Others...> {};
311 
312  template <typename Target, typename... Others>
313  struct has_type<Target, Target, Others...> : std::true_type {};
314 
315  template <typename Target>
316  struct has_type<Target> : std::false_type {};
317 
318  //--------------------------------------------------------------------------
319  template <typename Key, typename... Types>
320  struct has_duplicate_types<Key, Types...>
321  : public bool_constant<has_type<Key, Types...>() || has_duplicate_types<Types...>()> {};
322 
323  template <>
324  struct has_duplicate_types<> : public std::false_type {};
325 
326  //--------------------------------------------------------------------------
327  template <typename... Types>
329 
330  template <typename... Types>
331  struct are_same_types {
332 
333  template <typename... AsTypes>
334  static constexpr bool as()
335  {
336  return (sizeof...(Types) == sizeof...(AsTypes)) &&
337  are_types_contained<Types...>::template in<AsTypes...>();
338  }
339 
340  }; // are_same_types
341 
342  template <typename First, typename... OtherTypes>
343  struct are_types_contained<First, OtherTypes...> {
344  template <typename... AsTypes>
345  static constexpr bool in()
346  {
347  return are_types_contained<OtherTypes...>::template in<AsTypes...>() &&
349  }
350  };
351 
352  template <typename First>
353  struct are_types_contained<First> {
354  template <typename... AsTypes>
355  static constexpr bool in()
356  {
357  return has_type<First, AsTypes...>();
358  }
359  };
360 
361  template <typename T>
362  struct is_provider_pack : public std::false_type {};
363 
364  template <typename... Providers>
365  struct is_provider_pack<ProviderPack<Providers...>> : public std::true_type {};
366 
367  template <typename APack, typename BPack>
368  struct have_same_provider_types : public std::false_type {};
369 
370  template <typename... AProviders, typename... BProviders>
371  struct have_same_provider_types<ProviderPack<AProviders...>, ProviderPack<BProviders...>>
372  : public std::integral_constant<bool,
373  are_same_types<AProviders...>::template as<BProviders...>()> {
374  };
375 
376  // --- BEGIN impementation of findDerivedFrom() ----------------------------
377  //
378  // This is the implementation of findDerivedFrom() and findBaseOf().
379  // The functions are expected to assert that there is exactly one answer to
380  // a matching condition: for findDerivedFrom() that answer is which is the
381  // derived class of Base among Derived, for findBaseOf() is the opposite.
382  //
383  // The implementation finds and returns the index of first class matching
384  // the condition, and it asserts that the answer is valid.
385  // It also finds the index of the next class matching the condition, just to
386  // assert that it is not valid (that is, there is no other matching class).
387  //
388  // The class returning the index of the first matching class is implemented
389  // recursively, on a class taking the target class, the first of the
390  // candidate classes, and then all the others in a parameter pack.
391  // When the first candidate satisfies the condition, then the recursion is
392  // over. In the simplest case, where we are just looking for a specific
393  // class, the condition (the Target is the same as the First Candidate) can
394  // be implied and the compiler can implement it directly with parameter
395  // matching. In our cases the condition is non-trivial and we use a
396  // two-level recursion: the outer level, the "dispatcher", invokes a
397  // different "answer" class whether the condition is true or false. In the
398  // former case a result is presented; in the other case recursion ensues,
399  // back to the dispatcher. The dispatcher can also terminate the recursion
400  // when no answer is found. If recursion is terminated without a match, an
401  // invalid index is returned.
402  //
403  // The class returning the next matching class is simply skipping a number
404  // of candidates, and then behaving like the one looking for the first
405  // matching candidate.
406  //
407 
408  //
409  // class to find the first matching class
410  //
411  template <template <typename A, typename B> class Match,
412  typename Target,
413  bool IsMatch,
414  typename... Candidates>
416 
417  template <template <typename A, typename B> class Match,
418  typename Target,
419  typename... Candidates>
420  struct findFirstMatching_answer<Match, Target, true, Candidates...>
421  : public index_constant<0U> {};
422 
423  template <template <typename A, typename B> class Match,
424  typename Target,
425  typename... Candidates>
427 
428  // end-of-recursion
429  template <template <typename A, typename B> class Match, typename Target>
430  struct findFirstMatching_dispatcher<Match, Target>
431  : findFirstMatching_answer<Match, Target, true> {};
432 
433  template <template <typename A, typename B> class Match,
434  typename Target,
435  typename FirstCandidate,
436  typename... OtherCandidates>
437  struct findFirstMatching_dispatcher<Match, Target, FirstCandidate, OtherCandidates...>
438  : public findFirstMatching_answer<Match,
439  Target,
440  Match<FirstCandidate, Target>::value,
441  FirstCandidate,
442  OtherCandidates...> {};
443 
444  template <template <typename A, typename B> class Match,
445  typename Target,
446  typename FirstCandidate,
447  typename... OtherCandidates>
448  struct findFirstMatching_answer<Match, Target, false, FirstCandidate, OtherCandidates...>
449  : public index_constant<(
450  1U + findFirstMatching_dispatcher<Match, Target, OtherCandidates...>::value)> {};
451 
452  template <template <typename A, typename B> class Match,
453  typename Target,
454  typename... Candidates>
455  struct findFirstMatching_impl : findFirstMatching_dispatcher<Match, Target, Candidates...> {
456  private:
457  static constexpr auto _index = findFirstMatching_dispatcher<Match, Target, Candidates...>();
458  }; // struct findFirstMatching_impl
459 
460  //
461  // class to apply findFirstMatching_impl after skipping some candidates
462  //
463  template <unsigned int NSkip,
464  template <typename A, typename B>
465  class Match,
466  typename Target,
467  typename... Candidates>
469 
470  // recursion: peel one
471  template <unsigned int NSkip,
472  template <typename A, typename B>
473  class Match,
474  typename Target,
475  typename FirstCandidate,
476  typename... OtherCandidates>
477  struct findNextMatching_impl<NSkip, Match, Target, FirstCandidate, OtherCandidates...>
478  : index_constant<(
479  1U + findNextMatching_impl<(NSkip - 1U), Match, Target, OtherCandidates...>::value)> {
480  static_assert(NSkip > 0U, "Implementation error: no arguments to skip!");
481  };
482 
483  // end-of-recursion: skipped enough
484  template <template <typename A, typename B> class Match,
485  typename Target,
486  typename FirstCandidate,
487  typename... OtherCandidates>
488  struct findNextMatching_impl<0U, Match, Target, FirstCandidate, OtherCandidates...>
489  : findFirstMatching_impl<Match, Target, FirstCandidate, OtherCandidates...> {};
490 
491  // end-of-recursion: all arguments skipped
492  template <unsigned int NSkip, template <typename A, typename B> class Match, typename Target>
493  struct findNextMatching_impl<NSkip, Match, Target> : findFirstMatching_impl<Match, Target> {};
494 
495  //
496  // class finding a match and asserting its existence and unicity
497  //
498  template <template <typename A, typename B> class Match,
499  typename Target,
500  typename... Candidates>
501  struct findTheMatching_impl : findFirstMatching_impl<Match, Target, Candidates...> {
502  private:
503  static constexpr auto _index = findFirstMatching_dispatcher<Match, Target, Candidates...>();
504 
506  sizeof...(Candidates),
507  "Multiple candidate classes match the Target one");
508  }; // struct findTheMatching_impl
509 
510  //
511  // implementations with concrete matching conditions
512  //
513  template <typename Derived, typename... Bases>
514  constexpr std::size_t indexOfBaseOf()
515  {
516  return findTheMatching_impl<std::is_base_of, Derived, Bases...>();
517  }
518 
519  template <typename Derived, typename... Bases>
520  constexpr std::size_t findBaseOf()
521  {
522  constexpr std::size_t index = indexOfBaseOf<Derived, Bases...>();
523  static_assert(index < sizeof...(Bases),
524  "Target is not derived from any of the available classes");
525  return index;
526  } // findBaseOf()
527 
528  // this matching condition is the mirror of std::is_base_of
529  template <typename Derived, typename Base>
530  struct is_derived_of : std::is_base_of<Base, Derived> {};
531 
532  template <typename Base, typename... Derived>
533  constexpr std::size_t indexOfDerivedFrom()
534  {
535  return findTheMatching_impl<is_derived_of, Base, Derived...>();
536  }
537 
538  template <typename Base, typename... Derived>
539  constexpr std::size_t findDerivedFrom()
540  {
541  constexpr std::size_t index = indexOfDerivedFrom<Base, Derived...>();
542  static_assert(index < sizeof...(Derived),
543  "Target is not base of any of the available classes");
544  return index;
545  } // findDerivedFrom()
546 
547  // --- END impementation of findDerivedFrom() ------------------------------
548 
549  //--------------------------------------------------------------------------
550  //--- SetFrom
551  //---
552  template <typename DestPack,
553  typename SourcePack,
554  typename FirstProvider,
555  typename... OtherProviders>
556  struct SetFrom<DestPack, SourcePack, FirstProvider, OtherProviders...> {
557  SetFrom(DestPack& pack, SourcePack const& from)
558  {
559  pack.set(from.template get<FirstProvider>());
560  SetFrom<DestPack, SourcePack, OtherProviders...>(pack, from);
561  }
562  }; // SetFrom<First, Others...>
563 
564  template <typename DestPack, typename SourcePack>
565  struct SetFrom<DestPack, SourcePack> {
566  SetFrom(DestPack&, SourcePack const&) {}
567  };
568 
569  //--------------------------------------------------------------------------
570  //--- Compare
571  //---
572  template <typename Provider, typename APack, typename BPack>
573  bool haveSameProvider(APack const& a, BPack const& b)
574  {
576  "This class needs two ProviderPack template types.");
577  return a.template get<Provider>() == b.template get<Provider>();
578  } // haveSameProvider()
579 
580  template <typename APack, typename BPack>
582 
584  "The specified provider packs have different types.");
585 
586  }; // ProviderPackComparerBase
587 
588  template <typename APack, typename BPack, typename... Providers>
590 
591  template <typename APack, typename BPack, typename First, typename... Others>
592  struct ProviderPackComparer<APack, BPack, First, Others...>
593  : ProviderPackComparerBase<APack, BPack> {
594  static bool compare(APack const& a, BPack const& b)
595  {
596  return haveSameProvider<First>(a, b) &&
598  }
599  }; // ProviderPackComparer<APack, BPack, First, Others...>
600 
601  template <typename APack, typename BPack, typename First>
602  struct ProviderPackComparer<APack, BPack, First> : ProviderPackComparerBase<APack, BPack> {
603  static bool compare(APack const& a, BPack const& b) { return haveSameProvider<First>(a, b); }
604  }; // ProviderPackComparer<APack, BPack, First>
605 
606  //--------------------------------------------------------------------------
607 
608  } // namespace details
609 
610  //----------------------------------------------------------------------------
611  //--- ProviderPack
612  //---
613 
614  template <typename... Providers>
615  template <typename... PackProviders, typename... OtherProviders>
617  OtherProviders const*... providers)
618  {
619 
620  // verify that the list of providers in argument is the exact one we need
621  static_assert(
622  details::are_same_types<Providers...>::template as<PackProviders..., OtherProviders...>(),
623  "The providers types in the arguments do not match the ones needed.");
624 
625  // copy all the providers from the provider pack
626  details::SetFrom<this_type, ProviderPack<PackProviders...>, PackProviders...>(*this, fromPack);
627 
628  // put the other providers in a temporary parameter pack, and copy it
629  // (this is convenience, a direct implementation would be probably better)
630  details::SetFrom<this_type, ProviderPack<OtherProviders...>, OtherProviders...>(
631  *this, makeProviderPack(providers...));
632 
633  } // ProviderPack<Providers...>::ProviderPack(ProviderPack, OtherProviders...)
634 
635  //----------------------------------------------------------------------------
636  template <typename... Providers>
637  template <typename... OtherProviders>
639  {
640  return details::ProviderPackComparer<ProviderPack<Providers...>,
641  ProviderPack<OtherProviders...>,
642  Providers...>::compare(*this, other);
643  }
644 
645  template <typename... Providers>
646  template <typename... OtherProviders>
648  {
649  return !(*this == other);
650  }
651 
652  //----------------------------------------------------------------------------
653  template <typename... Providers>
654  template <typename... OfferedProviders>
656  {
657  return details::are_types_contained<Providers...>::template in<OfferedProviders...>();
658  } // ProviderPack<>::containsProviders()
659 
660  //----------------------------------------------------------------------------
661 
662 } // namespace lar
663 
664 #endif // LARCOREALG_COREUTILS_PROVIDERPACK_H
static constexpr bool as()
Definition: ProviderPack.h:334
ProviderPack< PackProviders..., MoreProviders... > expandProviderPack(ProviderPack< PackProviders... > const &pack, MoreProviders const *...providers)
Function to create a ProviderPack by adding to another.
Definition: ProviderPack.h:282
Implementation detail for the extraction constructor.
Definition: ProviderPack.h:82
ProviderPack(Providers const *...provider_ptrs)
Constructor: stores a provider pointer for each type.
Definition: ProviderPack.h:125
std::integral_constant< std::size_t, Value > index_constant
Definition: ProviderPack.h:301
constexpr std::size_t hasDerivedFrom()
Definition: ProviderPack.h:75
static constexpr bool has()
Returns whether there is a provider with the specified type.
Definition: ProviderPack.h:198
std::integral_constant< bool, Value > bool_constant
Definition: ProviderPack.h:298
SetFrom(DestPack &, SourcePack const &)
Definition: ProviderPack.h:566
static constexpr bool containsProviders()
Returns whether all our providers are in the OfferedProviders list.
Definition: ProviderPack.h:655
ProviderPack(ProviderPack< OtherProviders... > const &from)
Constructor: extracts the providers from another parameter pack.
Definition: ProviderPack.h:136
bool haveSameProvider(APack const &a, BPack const &b)
Definition: ProviderPack.h:573
std::tuple< Providers const *... > tuple_type
type used for storage of the pointers
Definition: ProviderPack.h:118
ProviderPack()=default
Default constructor: a null provider pointer for each type.
tuple_type providers
container of the pointers, type-safe
Definition: ProviderPack.h:236
constexpr std::size_t indexOfBaseOf()
Index of the class among Bases which is base of Derived.
Definition: ProviderPack.h:514
constexpr std::size_t findDerivedFrom()
Definition: ProviderPack.h:539
constexpr std::size_t hasBaseOf()
Returns whether there is exactly one base class of Derived among Bases.
Definition: ProviderPack.h:69
ProviderPack< Providers... > makeProviderPack(Providers const *...providers)
Function to create a ProviderPack from the function arguments.
Definition: ProviderPack.h:256
constexpr std::size_t indexOfDerivedFrom()
Definition: ProviderPack.h:533
static bool compare(APack const &a, BPack const &b)
Definition: ProviderPack.h:603
ifstream in
Definition: comparison.C:7
ProviderPack(OtherProviders const *...providers)
Constructor: picks the providers from the specified ones.
Definition: ProviderPack.h:150
LArSoft-specific namespace.
Container for a list of pointers to providers.
Definition: ProviderPack.h:111
bool operator!=(infinite_endcount_iterator< T > const &, count_iterator< T > const &)
Never admit a infinite_endcount_iterator to be equal to anything else.
Definition: counter.h:266
constexpr std::size_t findBaseOf()
Index of the class among Bases which is base of Derived.
Definition: ProviderPack.h:520
bool operator==(infinite_endcount_iterator< T > const &, count_iterator< T > const &)
Definition: counter.h:278
bool operator==(ProviderPack< OtherProviders... > const &other) const
Returns whether other provider pack has all the same providers as this.
Definition: ProviderPack.h:638
bool operator!=(ProviderPack< OtherProviders... > const &other) const
Returns whether other provider pack and this have different providers.
Definition: ProviderPack.h:647