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-2024 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 : : 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 : : //! Acces 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 : 25710 : explicit TaggedTuple() = default; 97 : : //! Initializer constructor 98 : 910 : explicit TaggedTuple( Tuple&& tuple ) : m_members( std::move(tuple) ) {} 99 : : 100 : : //! Const-ref access to member tuple 101 : 1 : 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 : 44144 : const auto& get() const noexcept { 106 : 44144 : 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 : 44144 : 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 : 508850058 : auto& get() noexcept { 116 : 508850058 : constexpr std::size_t idx = brigand::index_of< Keys, Tag >::value; 117 : : if constexpr( is_tagged_tuple<Tag>::value and sizeof...(Tags) != 0 ) 118 : 39 : return std::get< idx >( m_members ).template get< Tags... >(); 119 : : else 120 : 508850019 : 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 : 1 : 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 : 1 : 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 : 73510 : 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 : 72323 : friend void operator|( PUP::er& p, TaggedTuple<List>& t ) { t.pup(p); } 160 : : //@} 161 : : }; 162 : : 163 : : } // tk::