Xyst test code coverage report
Current view: top level - Base - PUPUtil.hpp (source / functions) Hit Total Coverage
Commit: 5689ba12dc66a776d3d75f1ee48cc7d78eaa18dc Lines: 56 57 98.2 %
Date: 2024-11-22 19:17:03 Functions: 27 29 93.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 35 52 67.3 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Base/PUPUtil.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     Charm++ Pack/UnPack utilities
      10                 :            :   \details   This file contains some extensions to Charm++'s Pack/UnPack
      11                 :            :     routines.
      12                 :            : */
      13                 :            : // *****************************************************************************
      14                 :            : #ifndef PUPUtil_h
      15                 :            : #define PUPUtil_h
      16                 :            : 
      17                 :            : #include <type_traits>
      18                 :            : 
      19                 :            : #include <unordered_map>
      20                 :            : #include <unordered_set>
      21                 :            : #include <variant>
      22                 :            : #include <optional>
      23                 :            : 
      24                 :            : #include "NoWarning/pup_stl.hpp"
      25                 :            : 
      26                 :            : //! Extensions to Charm++'s Pack/Unpack routines
      27                 :            : namespace PUP {
      28                 :            : 
      29                 :            : //////////////////// Serialize enum class ////////////////////
      30                 :            : 
      31                 :            : #if defined(__clang__)
      32                 :            :   #pragma clang diagnostic push
      33                 :            :   #pragma clang diagnostic ignored "-Wuninitialized"
      34                 :            : #elif defined(STRICT_GNUC)
      35                 :            :   #pragma GCC diagnostic push
      36                 :            :   #pragma GCC diagnostic ignored "-Wuninitialized"
      37                 :            :   #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
      38                 :            : #endif
      39                 :            : 
      40                 :            : //! \brief Pack/Unpack enum class.
      41                 :            : //! \details In Charm++ usually both the pup() overload and an overload for
      42                 :            : //!   operator| are defined for all serializable types. However, we cannot
      43                 :            : //!   define operator| for enum class as it would conflict with Charm++'s
      44                 :            : //!   catch-all, template< class T > inline void operator|(PUP::er &p,T &t)
      45                 :            : //!   {...}.
      46                 :            : //! \param[in] p Charm++'s pack/unpack object
      47                 :            : //! \param[in] e Enum class to pack/unpack
      48                 :            : template< typename E,
      49                 :            :           typename std::enable_if< std::is_enum< E >::value, int >::type = 0 >
      50                 :         18 : inline void pup( PUP::er& p, E& e ) {
      51                 :         18 :   auto v = static_cast< typename std::underlying_type_t< E > >( e );
      52         [ +  - ]:         18 :   p | v;
      53                 :         18 :   e = static_cast< E >( v );
      54                 :         18 : }
      55                 :            : 
      56                 :            : #if defined(__clang__)
      57                 :            :   #pragma clang diagnostic pop
      58                 :            : #elif defined(STRICT_GNUC)
      59                 :            :   #pragma GCC diagnostic pop
      60                 :            : #endif
      61                 :            : 
      62                 :            : //////////////////// Serialize std::unordered_map ////////////////////
      63                 :            : 
      64                 :            : //! Pack/Unpack std::unordered_map.
      65                 :            : //! \param[in] p Charm++'s pack/unpack object
      66                 :            : //! \param[in] m std::unordered_map< Key, T, Hash, KeyEqual > to pack/unpack
      67                 :            : template< class Key,
      68                 :            :           class T,
      69                 :            :           class Hash = std::hash< Key >,
      70                 :            :           class KeyEqual = std::equal_to< Key > >
      71                 :      59362 : inline void pup( PUP::er& p, std::unordered_map< Key, T, Hash, KeyEqual >& m ) {
      72                 :      59362 :   auto size = PUP_stl_container_size( p, m );
      73         [ +  + ]:      59362 :   if (p.isUnpacking()) {
      74         [ +  + ]:     211487 :     for (decltype(size) s=0; s<size; ++s) {
      75                 :     192601 :       std::pair< Key, T > node;
      76         [ +  - ]:     192601 :       p | node;
      77         [ +  - ]:     192601 :       m.emplace( node );
      78                 :            :     }
      79                 :            :   } else {
      80         [ +  + ]:     522419 :     for (auto& t : m) {
      81         [ -  - ]:     481943 :       std::pair< Key, T > node( t );
      82         [ +  - ]:     481943 :       p | node;
      83                 :            :     }
      84                 :            :   }
      85                 :      59362 : }
      86                 :            : //! Pack/Unpack std::unordered_map.
      87                 :            : //! \param[in] p Charm++'s pack/unpack object
      88                 :            : //! \param[in] m std::unordered_map< Key, T, Hash, KeyEqual > to pack/unpack
      89                 :            : template< class Key,
      90                 :            :           class T,
      91                 :            :           class Hash = std::hash< Key >,
      92                 :            :           class KeyEqual = std::equal_to< Key > >
      93                 :      59362 : inline void operator|( PUP::er& p,
      94                 :            :                        std::unordered_map< Key, T, Hash, KeyEqual >& m )
      95                 :      59362 : { pup( p, m ); }
      96                 :            : 
      97                 :            : //////////////////// Serialize std::unordered_set ////////////////////
      98                 :            : 
      99                 :            : //! Pack/Unpack std::unordered_set.
     100                 :            : //! \param[in] p Charm++'s pack/unpack object
     101                 :            : //! \param[in] s std::unordered_set< Key, Hash, KeyEqual > to pack/unpack
     102                 :            : template< class Key,
     103                 :            :           class Hash = std::hash< Key >,
     104                 :            :           class KeyEqual = std::equal_to< Key > >
     105                 :      14998 : inline void pup( PUP::er& p, std::unordered_set< Key, Hash, KeyEqual >& s ) {
     106                 :      14998 :   auto size = PUP_stl_container_size( p, s );
     107         [ +  + ]:      14998 :   if (p.isUnpacking()) {
     108         [ +  + ]:      48761 :     for (decltype(size) i=0; i<size; ++i) {
     109                 :            :       Key node;
     110         [ +  - ]:      43989 :       p | node;
     111         [ +  - ]:      43989 :       s.emplace( node );
     112                 :            :     }
     113                 :            :   } else {
     114         [ +  + ]:      98204 :     for (auto& t : s) {
     115                 :      87978 :       Key node( t );
     116         [ +  - ]:      87978 :       p | node;
     117                 :            :     }
     118                 :            :   }
     119                 :      14998 : }
     120                 :            : //! Pack/Unpack std::unordered_set.
     121                 :            : //! \param[in] p Charm++'s pack/unpack object
     122                 :            : //! \param[in] s std::unordered_set< Key, Hash, KeyEqual > to pack/unpack
     123                 :            : template< class Key,
     124                 :            :           class Hash = std::hash< Key >,
     125                 :            :           class KeyEqual = std::equal_to< Key > >
     126                 :      14998 : inline void operator|( PUP::er& p,
     127                 :            :                        std::unordered_set< Key, Hash, KeyEqual >& s )
     128                 :      14998 : { pup( p, s ); }
     129                 :            : 
     130                 :            : //////////////////// Serialize std::optional ////////////////////
     131                 :            : 
     132                 :            : //! Pack/Unpack std::optional
     133                 :            : //! \param[in] p Charm++'s pack/unpack object
     134                 :            : //! \param[in] o std::optional< T > of arbitrary type T to pack/unpack
     135                 :            : template< class T >
     136                 :          6 : inline void pup( PUP::er& p, std::optional< T >& o ) {
     137 [ +  + ][ +  - ]:          6 :   T underlying_value = o ? *o : T();
     138                 :          6 :   bool exist = o ? true : false;
     139         [ +  - ]:          6 :   p | exist;
     140         [ +  - ]:          6 :   p | underlying_value;
     141 [ +  + ][ +  - ]:          6 :   o = exist ? std::make_optional(underlying_value) : std::nullopt;
     142                 :          6 : }
     143                 :            : //! Pack/Unpack std::optional
     144                 :            : //! \param[in] p Charm++'s pack/unpack object
     145                 :            : //! \param[in] o std::optional< T > of arbitrary type T to pack/unpack
     146                 :            : template< class T >
     147                 :          6 : inline void operator|( PUP::er& p, std::optional< T >& o ) { pup( p, o ); }
     148                 :            : 
     149                 :            : //////////////////// Serialize std::variant ////////////////////
     150                 :            : 
     151                 :            : // Since std::variant when default-constructed is initialized to hold a value of
     152                 :            : // the first alternative of its type list, calling PUP that works based on a
     153                 :            : // std::visit with a templated operator() would always incorrectly trigger the
     154                 :            : // overload for the first type. Thus when PUPing a variant not only its value
     155                 :            : // but its type must also be sent during migration. The pup operator template
     156                 :            : // below achieves this by reading out not only the value but also its zero-based
     157                 :            : // index of the type alternative that is currently held by the variant passed to
     158                 :            : // its initializer constructor. The index and the variant are then PUPed and
     159                 :            : // when unpacking, as an additional step, the variant is reconstructed using the
     160                 :            : // index and the value in the variant. This latter is done by invoking an
     161                 :            : // expansion of an initializer list, guaranteed to happen in order, stepping
     162                 :            : // through the typelist in the variant.  Thanks to Nils Deppe for simplifying
     163                 :            : // the original version of this operation. See UnitTest/tests/Base/TestPUPUtil.h
     164                 :            : // or Inciter::SchemeBase.h for puping a variant in action.
     165                 :            : 
     166                 :            : //! Pack/Unpack helper for std::variant
     167                 :            : //! \param[in,out] index Counter (location) for type in variant
     168                 :            : //! \param[in] send_index Target counter (location) for type in variant
     169                 :            : //! \param[in] p Charm++'s pack/unpack object
     170                 :            : //! \param[in] var std::variant< Ts... > of arbitrary types to pack/unpack
     171                 :            : template <class T, class... Ts>
     172                 :         12 : char pup_helper( std::size_t& index,
     173                 :            :                  const std::size_t send_index,
     174                 :            :                  PUP::er& p,
     175                 :            :                  std::variant<Ts...>& var )
     176                 :            : {
     177         [ +  + ]:         12 :   if (index == send_index) {
     178         [ +  + ]:          6 :     if (p.isUnpacking()) {
     179                 :          2 :       T t{};
     180         [ +  - ]:          2 :       p | t;
     181                 :          2 :       var = std::move(t);
     182                 :            :     } else {
     183                 :          4 :       p | std::get<T>(var);
     184                 :            :     }
     185                 :            :   }
     186                 :         12 :   index++;
     187                 :         12 :   return '0';
     188                 :            : }
     189                 :            : 
     190                 :            : //! Pack/Unpack std::variant
     191                 :            : //! \param[in] p Charm++'s pack/unpack object
     192                 :            : //! \param[in] var std::variant< Ts... > of arbitrary types to pack/unpack
     193                 :            : template <class... Ts>
     194                 :          6 : void pup(PUP::er& p, std::variant<Ts...>& var) {
     195                 :          6 :   std::size_t index = 0;
     196                 :          6 :   auto send_index = var.index();
     197         [ +  - ]:          6 :   p | send_index;
     198                 :          0 :   (void)std::initializer_list<char>{
     199 [ +  - ][ +  - ]:          6 :       pup_helper<Ts>(index, send_index, p, var)...};
     200                 :          6 : }
     201                 :            : 
     202                 :            : //! Pack/Unpack std::variant
     203                 :            : //! \param[in] p Charm++'s pack/unpack object
     204                 :            : //! \param[in] d std::variant< Ts... > of arbitrary types to pack/unpack
     205                 :            : template <typename... Ts>
     206                 :          6 : inline void operator|(PUP::er& p, std::variant<Ts...>& d) {
     207                 :          6 :   pup(p, d);
     208                 :          6 : }
     209                 :            : 
     210                 :            : } // PUP::
     211                 :            : 
     212                 :            : #endif // PUPUtil_h

Generated by: LCOV version 1.16