SpECTRE Documentation Coverage Report
Current view: top level - Utilities - TaggedTuple.hpp Hit Total Coverage
Commit: f72e9195025f0dc1c39a6ae90681a46c1f20b40a Lines: 12 66 18.2 %
Date: 2025-03-14 19:47:33
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <cstddef>
       7             : #include <functional>
       8             : #include <initializer_list>
       9             : #include <ostream>
      10             : #include <stack>
      11             : #include <string>
      12             : #include <utility>
      13             : 
      14             : #include "Utilities/Overloader.hpp"
      15             : #include "Utilities/PrettyType.hpp"
      16             : #include "Utilities/PrintHelpers.hpp"
      17             : #include "Utilities/TMPL.hpp"
      18             : 
      19             : /// \cond
      20             : namespace PUP {
      21             : class er;
      22             : }  // namespace PUP
      23             : /// \endcond
      24             : 
      25             : /*!
      26             :  * \brief Contains utilities for working with tuples
      27             :  */
      28           1 : namespace tuples {
      29             : 
      30             : #if __cplusplus >= 201402L
      31             : #define TUPLES_LIB_CONSTEXPR_CXX_14 constexpr
      32             : #else
      33           0 : #define TUPLES_LIB_CONSTEXPR_CXX_14
      34             : #endif
      35             : 
      36             : namespace tuples_detail {
      37             : 
      38             : template <class T>
      39             : inline constexpr T&& forward(typename std::remove_reference<T>::type& t) {
      40             :   return static_cast<T&&>(t);
      41             : }
      42             : 
      43             : template <class T>
      44             : inline constexpr T&& forward(typename std::remove_reference<T>::type&& t) {
      45             :   static_assert(!std::is_lvalue_reference<T>::value,
      46             :                 "cannot forward an rvalue as an lvalue");
      47             :   return static_cast<T&&>(t);
      48             : }
      49             : 
      50             : template <class T, T...>
      51             : struct value_list {};
      52             : 
      53             : template <class...>
      54             : struct typelist {};
      55             : 
      56             : template <bool... Bs>
      57             : using all = typename std::is_same<
      58             :     value_list<bool, Bs...>,
      59             :     value_list<bool, (static_cast<void>(Bs), true)...>>::type;
      60             : 
      61             : struct no_such_type {
      62             :   no_such_type() = delete;
      63             :   no_such_type(no_such_type const& /*unused*/) = delete;
      64             :   no_such_type(no_such_type&& /*unused*/) = delete;
      65             :   ~no_such_type() = delete;
      66             :   no_such_type& operator=(no_such_type const& /*unused*/) = delete;
      67             :   no_such_type operator=(no_such_type&& /*unused*/) = delete;
      68             : };
      69             : 
      70             : namespace detail {
      71             : using std::swap;
      72             : 
      73             : template <class T, class S,
      74             :           bool = not std::is_void<T>::value and not std::is_void<S>::value>
      75             : struct is_swappable_with {
      76             :   template <class L, class R>
      77             :   static auto test_swap(int)
      78             :       -> decltype(swap(std::declval<L&>(), std::declval<R&>()));
      79             :   template <class L, class R>
      80             :   static tuples::tuples_detail::no_such_type test_swap(...);
      81             : 
      82             :   static const bool value =
      83             :       not std::is_same<decltype(test_swap<T, S>(0)),
      84             :                        tuples::tuples_detail::no_such_type>::value and
      85             :       not std::is_same<decltype(test_swap<S, T>(0)),
      86             :                        tuples::tuples_detail::no_such_type>::value;
      87             : };
      88             : 
      89             : template <class T, class S>
      90             : struct is_swappable_with<T, S, false> : std::false_type {};
      91             : }  // namespace detail
      92             : 
      93             : template <class T, class S>
      94             : using is_swappable_with = detail::is_swappable_with<T, S>;
      95             : 
      96             : template <typename... Ts>
      97             : constexpr char expand_pack(Ts&&... /*unused*/) {
      98             :   return '0';
      99             : }
     100             : }  // namespace tuples_detail
     101             : 
     102             : namespace tuples_detail {
     103             : template <class Tag, bool Ebo = std::is_empty<typename Tag::type>::value &&
     104             :                                 !__is_final(typename Tag::type)>
     105             : class TaggedTupleLeaf;
     106             : 
     107             : template <class T, bool B>
     108             : void swap(TaggedTupleLeaf<T, B>& lhs, TaggedTupleLeaf<T, B>& rhs) {
     109             :   using std::swap;
     110             :   swap(lhs.get_data(), rhs.get_data());
     111             : }
     112             : 
     113             : template <class Tag>
     114             : class TaggedTupleLeaf<Tag, false> {
     115             :   using value_type = typename Tag::type;
     116             :   value_type value_;
     117             : 
     118             :   template <class T>
     119             :   static constexpr bool can_bind_reference() {
     120             :     using rem_ref_value_type = typename std::remove_reference<value_type>::type;
     121             :     using rem_ref_T = typename std::remove_reference<T>::type;
     122             :     using is_lvalue_type = std::integral_constant<
     123             :         bool,
     124             :         std::is_lvalue_reference<T>::value or
     125             :             std::is_same<std::reference_wrapper<rem_ref_value_type>,
     126             :                          rem_ref_T>::value or
     127             :             std::is_same<std::reference_wrapper<typename std::remove_const<
     128             :                              rem_ref_value_type>::type>,
     129             :                          rem_ref_T>::value>;
     130             :     return not std::is_reference<value_type>::value or
     131             :            (std::is_lvalue_reference<value_type>::value and
     132             :             is_lvalue_type::value) or
     133             :            (std::is_rvalue_reference<value_type>::value and
     134             :             not std::is_lvalue_reference<T>::value);
     135             :   }
     136             : 
     137             :  public:
     138             :   // Tested in constexpr context in Unit.TaggedTuple.Ebo
     139             :   constexpr TaggedTupleLeaf() : value_() {
     140             :     static_assert(
     141             :         !std::is_reference<value_type>::value,
     142             :         "Cannot default construct a reference element in a TaggedTuple");
     143             :   }
     144             : 
     145             :   // clang-tidy: forwarding references can be bad
     146             :   template <
     147             :       class T,
     148             :       typename std::enable_if<
     149             :           !std::is_same<typename std::decay<T>::type, TaggedTupleLeaf>::value &&
     150             :           std::is_constructible<value_type, T>::value>::type* = nullptr>
     151             :   constexpr explicit TaggedTupleLeaf(T&& t)
     152             :       : value_(tuples_detail::forward<T>(t)) {
     153             :     static_assert(can_bind_reference<T>(),
     154             :                   "Cannot construct an lvalue reference with an rvalue");
     155             :   }
     156             : 
     157             :   constexpr TaggedTupleLeaf(TaggedTupleLeaf const& /*rhs*/) = default;
     158             :   constexpr TaggedTupleLeaf(TaggedTupleLeaf&& /*rhs*/) = default;
     159             :   constexpr TaggedTupleLeaf& operator=(TaggedTupleLeaf const& /*rhs*/) =
     160             :       default;
     161             :   constexpr TaggedTupleLeaf& operator=(TaggedTupleLeaf&& /*rhs*/) = default;
     162             : 
     163             :   ~TaggedTupleLeaf() = default;
     164             : 
     165             :   // Note: name get_data instead of get to enable structured binding support.
     166             : #if __cplusplus < 201402L
     167             :   value_type& get_data() { return value_; }
     168             : #else
     169             :   constexpr value_type& get_data() { return value_; }
     170             : #endif
     171             :   constexpr const value_type& get_data() const { return value_; }
     172             : 
     173             :   bool swap(TaggedTupleLeaf& t) {
     174             :     using std::swap;
     175             :     swap(*this, t);
     176             :     return false;
     177             :   }
     178             : 
     179             :   // clang-tidy: runtime-references
     180             :   void pup(PUP::er& p) { p | value_; }  // NOLINT
     181             : };
     182             : 
     183             : template <class Tag>
     184             : class TaggedTupleLeaf<Tag, true> : private Tag::type {
     185             :   using value_type = typename Tag::type;
     186             : 
     187             :  public:
     188             :   constexpr TaggedTupleLeaf() : value_type{} {}
     189             : 
     190             :   template <
     191             :       class T,
     192             :       typename std::enable_if<
     193             :           !std::is_same<typename std::decay<T>::type, TaggedTupleLeaf>::value &&
     194             :           std::is_constructible<value_type, T&&>::value>::type* = nullptr>
     195             :   constexpr explicit TaggedTupleLeaf(T&& t)
     196             :       : value_type(tuples_detail::forward<T>(t)) {}
     197             : 
     198             :   constexpr TaggedTupleLeaf(TaggedTupleLeaf const& /*rhs*/) = default;
     199             :   constexpr TaggedTupleLeaf(TaggedTupleLeaf&& /*rhs*/) = default;
     200             :   constexpr TaggedTupleLeaf& operator=(TaggedTupleLeaf const& /*rhs*/) =
     201             :       default;
     202             :   constexpr TaggedTupleLeaf& operator=(TaggedTupleLeaf&& /*rhs*/) = default;
     203             : 
     204             :   ~TaggedTupleLeaf() = default;
     205             : 
     206             :   // Note: name get_data instead of get to enable structured binding support.
     207             : #if __cplusplus < 201402L
     208             :   value_type& get_data() { return static_cast<value_type&>(*this); }
     209             : #else
     210             :   constexpr value_type& get_data() { return static_cast<value_type&>(*this); }
     211             : #endif
     212             : 
     213             :   constexpr const value_type& get_data() const {
     214             :     return static_cast<const value_type&>(*this);
     215             :   }
     216             : 
     217             :   bool swap(TaggedTupleLeaf& t) {
     218             :     using std::swap;
     219             :     swap(*this, t);
     220             :     return false;
     221             :   }
     222             : 
     223             :   // NOLINTNEXTLINE(google-runtime-references)
     224             :   void pup(PUP::er& p) { p | static_cast<typename Tag::type&>(*this); }
     225             : };
     226             : 
     227             : struct disable_constructors {
     228             :   static constexpr bool enable_default() { return false; }
     229             :   static constexpr bool enable_explicit() { return false; }
     230             :   static constexpr bool enable_implicit() { return false; }
     231             : };
     232             : }  // namespace tuples_detail
     233             : 
     234             : /*!
     235             :  * \ingroup UtilitiesGroup
     236             :  * \brief An associative container that is indexed by structs
     237             :  *
     238             :  * A data structure that is indexed by Tags. A Tag is a struct that contains
     239             :  * a type alias named `type`, which is the type of the object stored with
     240             :  * index Tag.
     241             :  *
     242             :  * \tparam Tags the tags of the objects to be placed in the tuple
     243             :  */
     244             : template <class... Tags>
     245             : class TaggedTuple;
     246             : 
     247             : template <class Tag, class... Tags>
     248             : constexpr const typename Tag::type& get(const TaggedTuple<Tags...>& t);
     249             : template <class Tag, class... Tags>
     250             : constexpr typename Tag::type& get(TaggedTuple<Tags...>& t);
     251             : template <class Tag, class... Tags>
     252             : constexpr const typename Tag::type&& get(const TaggedTuple<Tags...>&& t);
     253             : template <class Tag, class... Tags>
     254             : constexpr typename Tag::type&& get(TaggedTuple<Tags...>&& t);
     255             : 
     256             : /*!
     257             :  * \brief Returns the type of the Tag
     258             :  */
     259             : template <class Tag>
     260           1 : using tag_type = typename Tag::type;
     261             : 
     262             : // clang-tidy: class does not define copy or move assignment (it does)
     263             : template <class... Tags>
     264           1 : class TaggedTuple : private tuples_detail::TaggedTupleLeaf<Tags>... {  // NOLINT
     265             :   template <class... Args>
     266           0 :   struct pack_is_TaggedTuple : std::false_type {};
     267             :   template <class... Args>
     268           0 :   struct pack_is_TaggedTuple<TaggedTuple<Args...>> : std::true_type {};
     269             : 
     270             :   template <bool EnableConstructor, class Dummy = void>
     271           0 :   struct args_constructor : tuples_detail::disable_constructors {};
     272             : 
     273             :   template <class Dummy>
     274           0 :   struct args_constructor<true, Dummy> {
     275           0 :     static constexpr bool enable_default() {
     276             :       return tuples_detail::all<
     277             :           std::is_default_constructible<tag_type<Tags>>::value...>::value;
     278             :     }
     279             : 
     280             :     template <class... Ts>
     281           0 :     static constexpr bool enable_explicit() {
     282             :       return tuples_detail::all<std::is_constructible<
     283             :                  tuples_detail::TaggedTupleLeaf<Tags>, Ts>::value...>::value and
     284             :              not tuples_detail::all<
     285             :                  std::is_convertible<Ts, tag_type<Tags>>::value...>::value;
     286             :     }
     287             :     template <class... Ts>
     288           0 :     static constexpr bool enable_implicit() {
     289             :       return tuples_detail::all<std::is_constructible<
     290             :                  tuples_detail::TaggedTupleLeaf<Tags>, Ts>::value...>::value and
     291             :              tuples_detail::all<
     292             :                  std::is_convertible<Ts, tag_type<Tags>>::value...>::value;
     293             :     }
     294             :   };
     295             : 
     296             :   // C++17 Draft 23.5.3.2 Assignment - helper aliases
     297           0 :   using is_copy_assignable =
     298             :       tuples_detail::all<std::is_copy_assignable<tag_type<Tags>>::value...>;
     299           0 :   using is_nothrow_copy_assignable = tuples_detail::all<
     300             :       std::is_nothrow_copy_assignable<tag_type<Tags>>::value...>;
     301           0 :   using is_move_assignable =
     302             :       tuples_detail::all<std::is_move_assignable<tag_type<Tags>>::value...>;
     303           0 :   using is_nothrow_move_assignable = tuples_detail::all<
     304             :       std::is_nothrow_move_assignable<tag_type<Tags>>::value...>;
     305             : 
     306             :   // clang-tidy: redundant declaration
     307             :   template <class Tag, class... LTags>
     308           0 :   friend constexpr const typename Tag::type& get(  // NOLINT
     309             :       const TaggedTuple<LTags...>& t);
     310             :   template <class Tag, class... LTags>
     311           0 :   friend constexpr typename Tag::type& get(  // NOLINT
     312             :       TaggedTuple<LTags...>& t);
     313             :   template <class Tag, class... LTags>
     314           0 :   friend constexpr const typename Tag::type&& get(  // NOLINT
     315             :       const TaggedTuple<LTags...>&& t);
     316             :   template <class Tag, class... LTags>
     317           0 :   friend constexpr typename Tag::type&& get(  // NOLINT
     318             :       TaggedTuple<LTags...>&& t);
     319             : 
     320             :  public:
     321           0 :   using tags_list = tmpl::list<Tags...>;
     322             : 
     323           0 :   static constexpr size_t size() { return sizeof...(Tags); }
     324             : 
     325             :   // clang-tidy: runtime-references
     326             :   // NOLINTNEXTLINE(google-runtime-references)
     327           0 :   void pup(PUP::er& p) {
     328             :     static_cast<void>(std::initializer_list<char>{
     329             :         (tuples_detail::TaggedTupleLeaf<Tags>::pup(p), '0')...});
     330             :   }
     331             : 
     332             :   // C++17 Draft 23.5.3.1 Construction
     333             :   template <bool Dummy = true, typename std::enable_if<args_constructor<
     334             :                                    Dummy>::enable_default()>::type* = nullptr>
     335           0 :   constexpr TaggedTuple() {}
     336             : 
     337           0 :   TaggedTuple(TaggedTuple const& /*rhs*/) = default;
     338           0 :   TaggedTuple(TaggedTuple&& /*rhs*/) = default;
     339             : 
     340             :   /*!
     341             :    * \brief Construct a TaggedTuple with Args
     342             :    * \requires `std::is_convertible_v<Us, typename Tags::type>...` is `true`
     343             :    *
     344             :    * \example
     345             :    * \snippet Test_TaggedTuple.cpp construction_example
     346             :    */
     347             :   template <class... Us,
     348             :             typename std::enable_if<
     349             :                 args_constructor<not pack_is_TaggedTuple<Us...>::value and
     350             :                                  sizeof...(Us) == sizeof...(Tags)>::
     351             :                     template enable_explicit<Us...>()>::type* = nullptr>
     352           1 :   constexpr explicit TaggedTuple(Us&&... us)
     353             :       : tuples_detail::TaggedTupleLeaf<Tags>(
     354             :             tuples_detail::forward<Us>(us))... {}
     355             : 
     356             :   /*!
     357             :    * \brief Construct a TaggedTuple with Args
     358             :    * \requires `std::is_convertible_v<Us, typename Tags::type>...` is `true`
     359             :    *
     360             :    * \example
     361             :    * \snippet Test_TaggedTuple.cpp construction_example
     362             :    */
     363             :   template <class... Us,
     364             :             typename std::enable_if<
     365             :                 args_constructor<not pack_is_TaggedTuple<Us...>::value and
     366             :                                  sizeof...(Us) == sizeof...(Tags)>::
     367             :                     template enable_implicit<Us...>()>::type* = nullptr>
     368             :   // clang-tidy: mark explicit
     369           1 :   constexpr TaggedTuple(Us&&... us)
     370             :       : tuples_detail::TaggedTupleLeaf<Tags>(
     371             :             tuples_detail::forward<Us>(us))... {}
     372             : 
     373             :   template <
     374             :       class... UTags,
     375             :       typename std::enable_if<
     376             :           sizeof...(Tags) == sizeof...(UTags) and
     377             :           tuples_detail::all<std::is_constructible<
     378             :               tag_type<Tags>, const tag_type<UTags>&>::value...>::value and
     379             :           not tuples_detail::all<std::is_same<Tags, UTags>::value...>::value>::
     380             :           type* = nullptr>
     381           0 :   constexpr explicit TaggedTuple(TaggedTuple<UTags...> const& t)
     382             :       : tuples_detail::TaggedTupleLeaf<Tags>(get<UTags>(t))... {}
     383             : 
     384             :   template <class... UTags,
     385             :             typename std::enable_if<
     386             :                 sizeof...(Tags) == sizeof...(UTags) and
     387             :                 tuples_detail::all<std::is_constructible<
     388             :                     tag_type<Tags>, tag_type<UTags>&&>::value...>::value and
     389             :                 not tuples_detail::all<std::is_same<Tags, UTags>::value...>::
     390             :                     value>::type* = nullptr>
     391           0 :   constexpr explicit TaggedTuple(TaggedTuple<UTags...>&& t)
     392             :       : tuples_detail::TaggedTupleLeaf<Tags>(std::move(get<UTags>(t)))... {}
     393             : 
     394           0 :   ~TaggedTuple() = default;
     395             : 
     396             :   // C++17 Draft 23.5.3.2 Assignment
     397           0 :   TaggedTuple& operator=(
     398             :       tmpl::conditional_t<is_copy_assignable::value, TaggedTuple,
     399             :                           tuples_detail::no_such_type> const& t) {
     400             :     static_cast<void>(
     401             :         tuples_detail::expand_pack((get<Tags>(*this) = get<Tags>(t))...));
     402             :     return *this;
     403             :   }
     404             : 
     405           0 :   TaggedTuple& operator=(
     406             :       tmpl::conditional_t<is_move_assignable::value, TaggedTuple,
     407             :                           tuples_detail::no_such_type>&& t) {
     408             :     static_cast<void>(tuples_detail::expand_pack(
     409             :         (get<Tags>(*this) =
     410             :              tuples_detail::forward<tag_type<Tags>>(get<Tags>(t)))...));
     411             :     return *this;
     412             :   }
     413             : 
     414             :   template <class... UTags,
     415             :             typename std::enable_if<
     416             :                 sizeof...(Tags) == sizeof...(UTags) and
     417             :                 tuples_detail::all<std::is_assignable<
     418             :                     tag_type<Tags>&,
     419             :                     tag_type<UTags> const&>::value...>::value>::type* = nullptr>
     420           0 :   TaggedTuple& operator=(TaggedTuple<UTags...> const& t) {
     421             :     static_cast<void>(
     422             :         tuples_detail::expand_pack((get<Tags>(*this) = get<UTags>(t))...));
     423             :     return *this;
     424             :   }
     425             : 
     426             :   template <
     427             :       class... UTags,
     428             :       typename std::enable_if<
     429             :           sizeof...(Tags) == sizeof...(UTags) and
     430             :           tuples_detail::all<std::is_assignable<
     431             :               tag_type<Tags>&, tag_type<UTags>&&>::value...>::value>::type* =
     432             :           nullptr>
     433           0 :   TaggedTuple& operator=(TaggedTuple<UTags...>&& t) {
     434             :     static_cast<void>(tuples_detail::expand_pack(
     435             :         (get<Tags>(*this) =
     436             :              tuples_detail::forward<tag_type<UTags>>(get<UTags>(t)))...));
     437             :     return *this;
     438             :   }
     439             : 
     440             :   // C++17 Draft 23.5.3.3 swap
     441           0 :   void swap(TaggedTuple& t) {
     442             :     tuples_detail::expand_pack(tuples_detail::TaggedTupleLeaf<Tags>::swap(
     443             :         static_cast<tuples_detail::TaggedTupleLeaf<Tags>&>(t))...);
     444             :   }
     445             : };
     446             : 
     447             : template <>
     448           0 : class TaggedTuple<> {
     449             :  public:
     450           0 :   using tags_list = tmpl::list<>;
     451           0 :   static constexpr size_t size() { return 0; }
     452           0 :   TaggedTuple() = default;
     453           0 :   void swap(TaggedTuple& /*unused*/) {}
     454             :   // clang-tidy: runtime-references
     455           0 :   void pup(PUP::er& /*p*/) {}  // NOLINT
     456             : };
     457             : 
     458             : // C++17 Draft 23.5.3.6 Tuple helper classes
     459             : template <class T>
     460           0 : struct tuple_size;
     461             : 
     462             : template <class... Tags>
     463           0 : struct tuple_size<TaggedTuple<Tags...>>
     464             :     : std::integral_constant<size_t, sizeof...(Tags)> {};
     465             : template <class... Tags>
     466           0 : struct tuple_size<const TaggedTuple<Tags...>>
     467             :     : tuple_size<TaggedTuple<Tags...>> {};
     468             : template <class... Tags>
     469           0 : struct tuple_size<volatile TaggedTuple<Tags...>>
     470             :     : tuple_size<TaggedTuple<Tags...>> {};
     471             : template <class... Tags>
     472           0 : struct tuple_size<const volatile TaggedTuple<Tags...>>
     473             :     : tuple_size<TaggedTuple<Tags...>> {};
     474             : 
     475             : // C++17 Draft 23.5.3.7 Element access
     476             : /// @{
     477             : /*!
     478             :  * \ingroup UtilitiesGroup
     479             :  * \brief Retrieve the element of `Tag` in the TaggedTuple
     480             :  */
     481             : template <class Tag, class... Tags>
     482           1 : inline constexpr const typename Tag::type& get(const TaggedTuple<Tags...>& t) {
     483             :   static_assert(std::is_base_of<tuples_detail::TaggedTupleLeaf<Tag>,
     484             :                                 TaggedTuple<Tags...>>::value,
     485             :                 "Could not retrieve Tag from TaggedTuple. See the first "
     486             :                 "template parameter of the instantiation for what Tag is being "
     487             :                 "retrieved and the remaining template parameters for what Tags "
     488             :                 "are available.");
     489             :   return static_cast<const tuples_detail::TaggedTupleLeaf<Tag>&>(t).get_data();
     490             : }
     491             : template <class Tag, class... Tags>
     492           1 : inline constexpr typename Tag::type& get(TaggedTuple<Tags...>& t) {
     493             :   static_assert(std::is_base_of<tuples_detail::TaggedTupleLeaf<Tag>,
     494             :                                 TaggedTuple<Tags...>>::value,
     495             :                 "Could not retrieve Tag from TaggedTuple. See the first "
     496             :                 "template parameter of the instantiation for what Tag is being "
     497             :                 "retrieved and the remaining template parameters for what Tags "
     498             :                 "are available.");
     499             :   return static_cast<tuples_detail::TaggedTupleLeaf<Tag>&>(t).get_data();
     500             : }
     501             : template <class Tag, class... Tags>
     502           1 : inline constexpr const typename Tag::type&& get(
     503             :     const TaggedTuple<Tags...>&& t) {
     504             :   static_assert(std::is_base_of<tuples_detail::TaggedTupleLeaf<Tag>,
     505             :                                 TaggedTuple<Tags...>>::value,
     506             :                 "Could not retrieve Tag from TaggedTuple. See the first "
     507             :                 "template parameter of the instantiation for what Tag is being "
     508             :                 "retrieved and the remaining template parameters for what Tags "
     509             :                 "are available.");
     510             :   return static_cast<const typename Tag::type&&>(
     511             :       static_cast<const tuples_detail::TaggedTupleLeaf<Tag>&&>(t).get_data());
     512             : }
     513             : template <class Tag, class... Tags>
     514           1 : inline constexpr typename Tag::type&& get(TaggedTuple<Tags...>&& t) {
     515             :   static_assert(std::is_base_of<tuples_detail::TaggedTupleLeaf<Tag>,
     516             :                                 TaggedTuple<Tags...>>::value,
     517             :                 "Could not retrieve Tag from TaggedTuple. See the first "
     518             :                 "template parameter of the instantiation for what Tag is being "
     519             :                 "retrieved and the remaining template parameters for what Tags "
     520             :                 "are available.");
     521             :   return static_cast<typename Tag::type&&>(
     522             :       static_cast<tuples_detail::TaggedTupleLeaf<Tag>&&>(t).get_data());
     523             : }
     524             : /// @}
     525             : 
     526             : template <size_t I, class... Tags>
     527           0 : inline constexpr typename tmpl::at_c<tmpl::list<Tags...>, I>::type&& get(
     528             :     TaggedTuple<Tags...>&& t) {
     529             :   return get<tmpl::at_c<tmpl::list<Tags...>, I>>(t);
     530             : }
     531             : 
     532             : template <size_t I, class... Tags>
     533           0 : inline constexpr const typename tmpl::at_c<tmpl::list<Tags...>, I>::type& get(
     534             :     const TaggedTuple<Tags...>& t) {
     535             :   return get<tmpl::at_c<tmpl::list<Tags...>, I>>(t);
     536             : }
     537             : 
     538             : template <size_t I, class... Tags>
     539           0 : inline constexpr typename tmpl::at_c<tmpl::list<Tags...>, I>::type& get(
     540             :     TaggedTuple<Tags...>& t) {
     541             :   return get<tmpl::at_c<tmpl::list<Tags...>, I>>(t);
     542             : }
     543             : 
     544             : // C++17 Draft 23.5.3.8 Relational operators
     545             : namespace tuples_detail {
     546             : struct equal {
     547             :   template <class T, class U>
     548             :   static TUPLES_LIB_CONSTEXPR_CXX_14 void apply(T const& lhs, U const& rhs,
     549             :                                                 bool* result) {
     550             :     *result = *result and lhs == rhs;
     551             :   }
     552             : };
     553             : 
     554             : template <class... LTags, class... RTags>
     555             : TUPLES_LIB_CONSTEXPR_CXX_14 bool tuple_equal_impl(
     556             :     TaggedTuple<LTags...> const& lhs, TaggedTuple<RTags...> const& rhs) {
     557             :   bool equal = true;
     558             :   // This short circuits in the sense that the operator== is only evaluated if
     559             :   // the result thus far is true
     560             :   static_cast<void>(std::initializer_list<char>{
     561             :       (equal::apply(get<LTags>(lhs), get<RTags>(rhs), &equal), '0')...});
     562             :   return equal;
     563             : }
     564             : }  // namespace tuples_detail
     565             : 
     566             : template <class... LTags, class... RTags,
     567             :           typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
     568             :               nullptr>
     569           0 : TUPLES_LIB_CONSTEXPR_CXX_14 bool operator==(TaggedTuple<LTags...> const& lhs,
     570             :                                             TaggedTuple<RTags...> const& rhs) {
     571             :   return tuples_detail::tuple_equal_impl(lhs, rhs);
     572             : }
     573             : 
     574             : template <class... LTags, class... RTags,
     575             :           typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
     576             :               nullptr>
     577           0 : TUPLES_LIB_CONSTEXPR_CXX_14 bool operator!=(TaggedTuple<LTags...> const& lhs,
     578             :                                             TaggedTuple<RTags...> const& rhs) {
     579             :   return not(lhs == rhs);
     580             : }
     581             : 
     582             : namespace tuples_detail {
     583             : struct less {
     584             :   template <class T, class U>
     585             :   static TUPLES_LIB_CONSTEXPR_CXX_14 void apply(T const& lhs, U const& rhs,
     586             :                                                 bool* last_rhs_less_lhs,
     587             :                                                 bool* result) {
     588             :     if (*result or *last_rhs_less_lhs) {
     589             :       return;
     590             :     }
     591             :     *result = lhs < rhs;
     592             :     if (*result) {
     593             :       return;
     594             :     }
     595             :     *last_rhs_less_lhs = rhs < lhs;
     596             :   }
     597             : };
     598             : 
     599             : template <class... LTags, class... RTags>
     600             : TUPLES_LIB_CONSTEXPR_CXX_14 bool tuple_less_impl(
     601             :     TaggedTuple<LTags...> const& lhs, TaggedTuple<RTags...> const& rhs) {
     602             :   bool result = false;
     603             :   bool last_rhs_less_lhs = false;
     604             :   static_cast<void>(
     605             :       std::initializer_list<char>{(less::apply(get<LTags>(lhs), get<RTags>(rhs),
     606             :                                                &last_rhs_less_lhs, &result),
     607             :                                    '0')...});
     608             :   return result;
     609             : }
     610             : }  // namespace tuples_detail
     611             : 
     612             : template <class... LTags, class... RTags,
     613             :           typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
     614             :               nullptr>
     615           0 : TUPLES_LIB_CONSTEXPR_CXX_14 bool operator<(TaggedTuple<LTags...> const& lhs,
     616             :                                            TaggedTuple<RTags...> const& rhs) {
     617             :   return tuples_detail::tuple_less_impl(lhs, rhs);
     618             : }
     619             : 
     620             : template <class... LTags, class... RTags,
     621             :           typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
     622             :               nullptr>
     623           0 : TUPLES_LIB_CONSTEXPR_CXX_14 bool operator>(TaggedTuple<LTags...> const& lhs,
     624             :                                            TaggedTuple<RTags...> const& rhs) {
     625             :   return rhs < lhs;
     626             : }
     627             : 
     628             : template <class... LTags, class... RTags,
     629             :           typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
     630             :               nullptr>
     631           0 : TUPLES_LIB_CONSTEXPR_CXX_14 bool operator<=(TaggedTuple<LTags...> const& lhs,
     632             :                                             TaggedTuple<RTags...> const& rhs) {
     633             :   return not(rhs < lhs);
     634             : }
     635             : 
     636             : template <class... LTags, class... RTags,
     637             :           typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
     638             :               nullptr>
     639           0 : TUPLES_LIB_CONSTEXPR_CXX_14 bool operator>=(TaggedTuple<LTags...> const& lhs,
     640             :                                             TaggedTuple<RTags...> const& rhs) {
     641             :   return not(lhs < rhs);
     642             : }
     643             : 
     644             : // C++17 Draft 23.5.3.3 swap
     645             : template <
     646             :     class... Tags,
     647             :     typename std::enable_if<tuples_detail::all<tuples_detail::is_swappable_with<
     648             :         tuples_detail::TaggedTupleLeaf<Tags>,
     649             :         tuples_detail::TaggedTupleLeaf<Tags>>::value...>::value>::type* =
     650             :         nullptr>
     651           0 : void swap(TaggedTuple<Tags...>& lhs, TaggedTuple<Tags...>& rhs) {
     652             :   lhs.swap(rhs);
     653             : }
     654             : 
     655             : namespace TaggedTuple_detail {
     656             : template <typename T>
     657             : struct tagged_tuple_typelist_impl;
     658             : 
     659             : template <template <typename...> class List, typename... Tags>
     660             : struct tagged_tuple_typelist_impl<List<Tags...>> {
     661             :   using type = TaggedTuple<Tags...>;
     662             : };
     663             : }  // namespace TaggedTuple_detail
     664             : 
     665             : /// \ingroup UtilitiesGroup
     666             : template <typename T>
     667           0 : using tagged_tuple_from_typelist =
     668             :     typename TaggedTuple_detail::tagged_tuple_typelist_impl<T>::type;
     669             : 
     670             : namespace TaggedTuple_detail {
     671             : template <typename... InputTags, typename... OutputTags>
     672             : TaggedTuple<OutputTags...> reorder_impl(TaggedTuple<InputTags...>&& input,
     673             :                                         tmpl::list<OutputTags...> /*meta*/) {
     674             :   static_assert(
     675             :       std::is_same_v<tmpl::list_difference<tmpl::list<OutputTags...>,
     676             :                                            tmpl::list<InputTags...>>,
     677             :                      tmpl::list<>> and
     678             :           std::is_same_v<tmpl::list_difference<tmpl::list<InputTags...>,
     679             :                                                tmpl::list<OutputTags...>>,
     680             :                          tmpl::list<>>,
     681             :       "The input and output TaggedTuples must be the same except "
     682             :       "for ordering.");
     683             :   return TaggedTuple<OutputTags...>(std::move(get<OutputTags>(input))...);
     684             : }
     685             : }  // namespace TaggedTuple_detail
     686             : 
     687             : /// Given an input TaggedTuple, produce an output TaggedTuple
     688             : /// with the tags in a different order.  All tags must be the same
     689             : /// except for ordering.
     690             : /// \example
     691             : /// \snippet Test_TaggedTuple.cpp reorder_example
     692             : template <typename ReturnedTaggedTuple, typename... Tags>
     693           1 : ReturnedTaggedTuple reorder(TaggedTuple<Tags...> input) {
     694             :   return TaggedTuple_detail::reorder_impl(
     695             :       std::move(input), typename ReturnedTaggedTuple::tags_list{});
     696             : }
     697             : 
     698             : /// Stream operator for TaggedTuple
     699             : using ::operator<<;
     700             : template <class... Tags>
     701           0 : std::ostream& operator<<(std::ostream& os, const TaggedTuple<Tags...>& t) {
     702             :   os << "TaggedTuple:\n";
     703             :   const auto print_item = [&os, &t](auto tag_v) {
     704             :     using tag = tmpl::type_from<decltype(tag_v)>;
     705             :     using type = typename tag::type;
     706             :     os << "----------\n";
     707             :     os << "Name:  " << pretty_type::get_name<tag>() << "\n";
     708             :     os << "Type:  " << pretty_type::get_name<type>() << "\n";
     709             :     os << "Value: ";
     710             :     print_value(os, get<tag>(t));
     711             :     os << "\n";
     712             :   };
     713             :   tmpl::for_each<tmpl::list<Tags...>>(print_item);
     714             :   return os;
     715             : }
     716             : 
     717             : namespace TaggedTuple_detail {
     718             : 
     719             : template <typename F, typename... Tags, typename... ApplyTags>
     720             : constexpr decltype(auto) apply_impl(F&& f, const TaggedTuple<Tags...>& t,
     721             :                                     tmpl::list<ApplyTags...> /* meta */) {
     722             :   return std::forward<F>(f)(get<ApplyTags>(t)...);
     723             : }
     724             : 
     725             : }  // namespace TaggedTuple_detail
     726             : 
     727             : /// @{
     728             : /*!
     729             :  * \ingroup UtilitiesGroup
     730             :  * \brief Invoke `f` with the `ApplyTags` taken from `t` expanded in a parameter
     731             :  * pack
     732             :  *
     733             :  * `ApplyTags` defaults to the full list of tags in `t`.
     734             :  *
     735             :  * Here is an example how to use the function:
     736             :  *
     737             :  * \snippet Test_TaggedTuple.cpp expand_tuple_example
     738             :  *
     739             :  * This is the function being called in the above example:
     740             :  *
     741             :  * \snippet Test_TaggedTuple.cpp expand_tuple_example_function
     742             :  *
     743             :  * \see std::apply
     744             :  */
     745             : template <typename ApplyTags, typename F, typename... Tags>
     746           1 : constexpr decltype(auto) apply(F&& f, const TaggedTuple<Tags...>& t) {
     747             :   return TaggedTuple_detail::apply_impl(std::forward<F>(f), t, ApplyTags{});
     748             : }
     749             : 
     750             : template <typename F, typename... Tags>
     751           1 : constexpr decltype(auto) apply(F&& f, const TaggedTuple<Tags...>& t) {
     752             :   return TaggedTuple_detail::apply_impl(
     753             :       std::forward<F>(f), t, typename TaggedTuple<Tags...>::tags_list{});
     754             : }
     755             : /// @}
     756             : 
     757             : }  // namespace tuples
     758             : 
     759             : namespace std {
     760             : template <typename... Tags>
     761             : struct tuple_size<tuples::TaggedTuple<Tags...>>
     762             :     : std::integral_constant<int, sizeof...(Tags)> {};
     763             : template <size_t I, typename... Tags>
     764             : struct tuple_element<I, tuples::TaggedTuple<Tags...>> {
     765             :   using type = typename tmpl::at_c<tmpl::list<Tags...>, I>::type;
     766             : };
     767             : }  // namespace std

Generated by: LCOV version 1.14