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 : : All rights reserved. See the LICENSE file for details. 8 : : \brief Tagged tuple allowing tag-based access 9 : : \details Tagged tuple allowing tag-based access. This is very much like 10 : : [std::tuple](http://en.cppreference.com/w/cpp/utility/tuple), but instead of 11 : : having to index the elements by integers, it allows access by a tag, which 12 : : can be an empty struct with a unique name. Credit goes to 13 : : ecatmur_at_stackoverflow.com, for more details, see 14 : : http://stackoverflow.com/questions/13065166/c11-tagged-tuple. For tags, see 15 : : Control/Tags.h. Tagged tuples are extensively used for transferring data 16 : : from the parser to an internal data structure in a type-save manner, which 17 : : is a tagged tuple containing a hierarchy of various containers. As an 18 : : example on how tagged tuples are used for parsing an input file, see 19 : : Control/Inciter/InputDeck/InputDeck.h. Another way to use a tagged tuple is 20 : : a compile-time associated container between tags and an arbitrary type. 21 : : */ 22 : : // ***************************************************************************** 23 : : #ifndef TaggedTuple_h 24 : : #define TaggedTuple_h 25 : : 26 : : #include <type_traits> 27 : : #include <tuple> 28 : : 29 : : #include <brigand/adapted/tuple.hpp> 30 : : 31 : : #include "NoWarning/any.hpp" 32 : : #include "NoWarning/partition.hpp" 33 : : #include "NoWarning/index_of.hpp" 34 : : 35 : : #include "PUPUtil.hpp" 36 : : #include "Exception.hpp" 37 : : 38 : : namespace tag { 39 : : //! Printable tag for TaggedTuple that returns its name 40 : : #define DEFTAG(n) struct n { static const char* name() { return #n; } } 41 : : } // tag:: 42 : : 43 : : namespace tk { 44 : : 45 : : //! \brief Tagged tuple, allowing tag-based access 46 : : //! \details "Tag" here is any type, but mostly an empty struct with a good name 47 : : //! for the data member 48 : : //! \tparam List Type list as brigand::list 49 : : //! \see https://stackoverflow.com/a/42988897 50 : : //! \see https://gist.github.com/underdoeg/4c5c616c1ad4cbb718f787eefcab902d 51 : : template< class List > 52 : : class TaggedTuple{ 53 : : 54 : : private: 55 : : //! Generate index for every 2nd type of a type list 56 : : template< typename T > 57 : : using is_odd = brigand::size_t< (brigand::index_of<List,T>::value%2) != 0 >; 58 : : 59 : : //! Partition a type list into two lists with the even and the odd types 60 : : using Pair = brigand::partition< List, brigand::bind<is_odd,brigand::_1> >; 61 : : 62 : : //! List of member types 63 : : using Data = typename Pair::first_type; 64 : : 65 : : //! Tuple of member types 66 : : using Tuple = brigand::as_tuple< Data >; 67 : : 68 : : //! False-overload for detecting if T is a tagged tuple 69 : : template< typename T, typename = std::void_t<> > 70 : : struct is_tagged_tuple_t : std::false_type {}; 71 : : 72 : : //! True-overload for detecting if T is a tagged tuple 73 : : template< typename T > 74 : : struct is_tagged_tuple_t< T, std::void_t< typename T::i_am_tagged_tuple > > 75 : : : std::true_type {}; 76 : : 77 : : //! Member data as a tuple 78 : : Tuple m_members; 79 : : 80 : : public: 81 : : //! List of key-value pairs 82 : : using PairList = List; 83 : : 84 : : //! List of keys 85 : : using Keys = typename Pair::second_type; 86 : : 87 : : //! Typedef defining self for identifying self 88 : : using i_am_tagged_tuple = void; 89 : : 90 : : //! Acces type in tuple behind tag 91 : : template< typename Tag > 92 : : using TupleElement = 93 : : std::tuple_element_t< brigand::index_of<Keys,Tag>::value, Tuple >; 94 : : 95 : : //! Query if the type behind Tag is a TaggedTuple 96 : : //! Usage: if constexpr( is_tagged_tuple<Tag>::value ) { ... } 97 : : template< typename Tag > 98 : : using is_tagged_tuple = 99 : : is_tagged_tuple_t< std::decay_t< TupleElement<Tag> > >; 100 : : 101 : : //! Default constructor 102 : 263299 : explicit TaggedTuple() = default; 103 : : //! Initializer constructor 104 : 195573 : explicit TaggedTuple( Tuple&& tuple ) : m_members( std::move(tuple) ) {} 105 : : 106 : : //! Const-ref access to member tuple 107 : 1196562 : const Tuple& tuple() const { return m_members; } 108 : : 109 : : //! Const-reference data member accessor of field of tagged tuple at depth 110 : : template< typename Tag, typename... Tags > 111 : 111383731 : const auto& get() const noexcept { 112 : 111383731 : constexpr std::size_t idx = brigand::index_of< Keys, Tag >::value; 113 : : if constexpr( is_tagged_tuple<Tag>::value and sizeof...(Tags) != 0 ) 114 : 12894 : return std::get< idx >( m_members ).template get< Tags... >(); 115 : : else 116 : 111370837 : return std::get< idx >( m_members ); 117 : : } 118 : : 119 : : //! Reference data member accessor of field of tagged tuple at depth 120 : : template< typename Tag, typename... Tags > 121 : 577806964 : auto& get() noexcept { 122 : 577806964 : constexpr std::size_t idx = brigand::index_of< Keys, Tag >::value; 123 : : if constexpr( is_tagged_tuple<Tag>::value and sizeof...(Tags) != 0 ) 124 : 222277985 : return std::get< idx >( m_members ).template get< Tags... >(); 125 : : else 126 : 355528979 : return std::get< idx >( m_members ); 127 : : } 128 : : 129 : : //! Convert and store value converting from string at depth 130 : : //! \param[in] value Value to convert and store 131 : : template< typename Tag, typename... Tags > 132 : 505 : void store( const std::string& value ) noexcept { 133 : : if constexpr( is_tagged_tuple<Tag>::value and sizeof...(Tags) != 0 ) 134 : : { 135 : : using T = std::remove_reference_t< decltype( get<Tag,Tags...>() ) >; 136 : 406 : get< Tag, Tags... >() = convert< T >( value ); 137 : : } else { 138 : : using T = std::remove_reference_t< decltype( get< Tag >() ) >; 139 : 99 : get< Tag >() = convert< T >( value ); 140 : : } 141 : 505 : } 142 : : 143 : : //! Operator == between two TaggedTuple objects 144 : : //! \tparam L Type list as brigand::list for other TaggedTuple 145 : : //! \return True if the lhs and rhs equal 146 : : template< typename L > 147 : 1 : bool operator== ( const TaggedTuple< L >& t ) const { 148 : : static_assert( std::is_same_v< L, List >, "Invoking operator== on " 149 : : "TaggedTuple objects with different typelists" ); 150 : : static_assert( !brigand::any< List, 151 : : std::is_floating_point<brigand::_1> >::value, "Invoking operator== on " 152 : : "TaggedTuple objects containing a floating point type is unreliable" ); 153 : 1 : return m_members == t.tuple(); 154 : : } 155 : : 156 : : //! Operator < between two TaggedTuple objects 157 : : //! \tparam L Type list as brigand::list for other TaggedTuple 158 : : //! \return True if lhs < rhs 159 : : template< typename L > 160 : 1196561 : bool operator< ( const TaggedTuple< L >& t ) const { 161 : : static_assert( std::is_same_v< L, List >, "Invoking operator< on " 162 : : "TaggedTuple objects with different typelists" ); 163 : 1196561 : return m_members < t.tuple(); 164 : : } 165 : : 166 : : //! Return number of tuple entries 167 : 1 : static constexpr std::size_t size() { return std::tuple_size_v< Tuple >; } 168 : : 169 : : //! Pack/Unpack 170 : : /** @name Charm++ pack/unpack serializer member functions */ 171 : : ///@{ 172 : : //! \brief Pack/Unpack serialize member function 173 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference 174 : 495972 : void pup( PUP::er& p ) { p | m_members; } 175 : : //! \brief Pack/Unpack serialize operator| 176 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference 177 : : //! \param[in,out] t TaggedTuple object reference 178 : 492437 : friend void operator|( PUP::er& p, TaggedTuple<List>& t ) { t.pup(p); } 179 : : //@} 180 : : 181 : : //! Convert/parse string to and return as type given by template argument 182 : : //! \param[in] str String to convert 183 : : //! \return A value of type given by the template argument 184 : : template< typename type > 185 : 505 : type convert( const std::string& str ) { 186 [ + - ]: 909 : std::stringstream ss( str ); 187 : 404 : type num; 188 [ + - ][ + - ]: 505 : ss >> std::boolalpha >> num; 189 [ + - ][ - + ]: 505 : if (ss.fail()) 190 [ - - ][ - - ]: 0 : Throw( "Failed to convert '" + str + [ - - ][ - - ] [ - - ] 191 : : "' to typeid " + typeid(num).name() ); 192 : 1010 : return num; 193 : : } 194 : : }; 195 : : 196 : : } // tk:: 197 : : 198 : : #endif // TaggedTuple_h