Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Base/TaggedTuple.hpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.,
7 : : 2022-2025 J. Bakosi
8 : : All rights reserved. See the LICENSE file for details.
9 : : \brief Tagged tuple allowing tag-based access
10 : : \details Tagged tuple allowing tag-based access. This is very much like
11 : : [std::tuple](http://en.cppreference.com/w/cpp/utility/tuple), but instead of
12 : : having to index the elements by integers, it allows access by a tag, which
13 : : can be an empty struct with a unique name. Credit goes to
14 : : ecatmur_at_stackoverflow.com, for more details, see
15 : : http://stackoverflow.com/questions/13065166/c11-tagged-tuple.
16 : : */
17 : : // *****************************************************************************
18 : : #pragma once
19 : :
20 : : #include <type_traits>
21 : : #include <tuple>
22 : :
23 : : #include <brigand/adapted/tuple.hpp>
24 : :
25 : : #include "NoWarning/any.hpp"
26 : : #include "NoWarning/partition.hpp"
27 : : #include "NoWarning/index_of.hpp"
28 : :
29 : : #include "PUPUtil.hpp"
30 : : #include "Exception.hpp"
31 : :
32 : : namespace tag {
33 : : //! Printable tag for TaggedTuple that returns its name
34 : : #define DEFTAG(n) struct n { static const char* key() { return #n; } }
35 : : } // tag::
36 : :
37 : : namespace tk {
38 : :
39 : : //! \brief Tagged tuple, allowing tag-based access
40 : : //! \details "Tag" here is any type, but mostly an empty struct with a good name
41 : : //! for the data member
42 : : //! \tparam List Type list as brigand::list
43 : : //! \see https://stackoverflow.com/a/42988897
44 : : //! \see https://gist.github.com/underdoeg/4c5c616c1ad4cbb718f787eefcab902d
45 : : template< class List >
46 : 943 : class TaggedTuple {
47 : :
48 : : private:
49 : : //! Generate index for every 2nd type of a type list
50 : : template< typename T >
51 : : using is_odd = brigand::size_t< (brigand::index_of<List,T>::value%2) != 0 >;
52 : :
53 : : //! Partition a type list into two lists with the even and the odd types
54 : : using Pair = brigand::partition< List, brigand::bind<is_odd,brigand::_1> >;
55 : :
56 : : //! List of member types
57 : : using Data = typename Pair::first_type;
58 : :
59 : : //! Tuple of member types
60 : : using Tuple = brigand::as_tuple< Data >;
61 : :
62 : : //! False-overload for detecting if T is a tagged tuple
63 : : template< typename T, typename = std::void_t<> >
64 : : struct is_tagged_tuple_t : std::false_type {};
65 : :
66 : : //! True-overload for detecting if T is a tagged tuple
67 : : template< typename T >
68 : : struct is_tagged_tuple_t< T, std::void_t< typename T::i_am_tagged_tuple > >
69 : : : std::true_type {};
70 : :
71 : : //! Member data as a tuple
72 : : Tuple m_members;
73 : :
74 : : public:
75 : : //! List of key-value pairs
76 : : using PairList = List;
77 : :
78 : : //! List of keys
79 : : using Keys = typename Pair::second_type;
80 : :
81 : : //! Typedef defining self for identifying self
82 : : using i_am_tagged_tuple = void;
83 : :
84 : : //! Access type in tuple behind tag
85 : : template< typename Tag >
86 : : using TupleElement =
87 : : std::tuple_element_t< brigand::index_of<Keys,Tag>::value, Tuple >;
88 : :
89 : : //! Query if the type behind Tag is a TaggedTuple
90 : : //! Usage: if constexpr( is_tagged_tuple<Tag>::value ) { ... }
91 : : template< typename Tag >
92 : : using is_tagged_tuple =
93 : : is_tagged_tuple_t< std::decay_t< TupleElement<Tag> > >;
94 : :
95 : : //! Default constructor
96 : : explicit TaggedTuple() = default;
97 : : //! Initializer constructor
98 : : explicit TaggedTuple( Tuple&& tuple ) : m_members( std::move(tuple) ) {}
99 : :
100 : : //! Const-ref access to member tuple
101 : : const Tuple& tuple() const { return m_members; }
102 : :
103 : : //! Const-reference data member accessor of field of tagged tuple at depth
104 : : template< typename Tag, typename... Tags >
105 : : const auto& get() const noexcept {
106 : : constexpr std::size_t idx = brigand::index_of< Keys, Tag >::value;
107 : : if constexpr( is_tagged_tuple<Tag>::value and sizeof...(Tags) != 0 )
108 : : return std::get< idx >( m_members ).template get< Tags... >();
109 : : else
110 : : return std::get< idx >( m_members );
111 : : }
112 : :
113 : : //! Reference data member accessor of field of tagged tuple at depth
114 : : template< typename Tag, typename... Tags >
115 : : auto& get() noexcept {
116 : : constexpr std::size_t idx = brigand::index_of< Keys, Tag >::value;
117 : : if constexpr( is_tagged_tuple<Tag>::value and sizeof...(Tags) != 0 )
118 : : return std::get< idx >( m_members ).template get< Tags... >();
119 : : else
120 : : return std::get< idx >( m_members );
121 : : }
122 : :
123 : : //! Operator == between two TaggedTuple objects
124 : : //! \tparam L Type list as brigand::list for other TaggedTuple
125 : : //! \return True if the lhs and rhs equal
126 : : template< typename L >
127 : : bool operator== ( const TaggedTuple< L >& t ) const {
128 : : static_assert( std::is_same_v< L, List >, "Invoking operator== on "
129 : : "TaggedTuple objects with different typelists" );
130 : : static_assert( !brigand::any< List,
131 : : std::is_floating_point<brigand::_1> >::value, "Invoking operator== on "
132 : : "TaggedTuple objects containing a floating point type is unreliable" );
133 [ + - ]: 1 : return m_members == t.tuple();
134 : : }
135 : :
136 : : //! Operator < between two TaggedTuple objects
137 : : //! \tparam L Type list as brigand::list for other TaggedTuple
138 : : //! \return True if lhs < rhs
139 : : template< typename L >
140 : : bool operator< ( const TaggedTuple< L >& t ) const {
141 : : static_assert( std::is_same_v< L, List >, "Invoking operator< on "
142 : : "TaggedTuple objects with different typelists" );
143 : : return m_members < t.tuple();
144 : : }
145 : :
146 : : //! Return number of tuple entries
147 : : static constexpr std::size_t size() { return std::tuple_size_v< Tuple >; }
148 : :
149 : : //! Pack/Unpack
150 : : /** @name Charm++ pack/unpack serializer member functions */
151 : : ///@{
152 : : //! \brief Pack/Unpack serialize member function
153 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference
154 : : // cppcheck-suppress constParameter
155 [ - - ][ + - ]: 65228 : void pup( PUP::er& p ) { p | m_members; }
[ - - ][ + - ]
[ + - ][ + - ]
[ - - ][ - - ]
[ + - ][ + - ]
156 : : //! \brief Pack/Unpack serialize operator|
157 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference
158 : : //! \param[in,out] t TaggedTuple object reference
159 : 16988 : friend void operator|( PUP::er& p, TaggedTuple<List>& t ) { t.pup(p); }
160 : : //@}
161 : : };
162 : :
163 : : } // tk::
|