SST  15.1.0
StructuralSimulationToolkit
serialize_variant.h
1 // Copyright 2009-2025 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2025, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_SERIALIZATION_IMPL_SERIALIZE_VARIANT_H
13 #define SST_CORE_SERIALIZATION_IMPL_SERIALIZE_VARIANT_H
14 
15 #ifndef SST_INCLUDING_SERIALIZE_H
16 #warning \
17  "The header file sst/core/serialization/impl/serialize_variant.h should not be directly included as it is not part of the stable public API. The file is included in sst/core/serialization/serialize.h"
18 #endif
19 
20 #include "sst/core/serialization/serializer.h"
21 
22 #include <array>
23 #include <utility>
24 #include <variant>
25 
26 namespace SST::Core::Serialization {
27 
28 // Serialize std::variant
29 template <typename... Types>
30 class serialize_impl<std::variant<Types...>>
31 {
32  void operator()(std::variant<Types...>& obj, serializer& ser, ser_opt_t UNUSED(options))
33  {
34  size_t index = std::variant_npos;
35  switch ( ser.mode() ) {
36  case serializer::SIZER:
37  index = obj.index();
38  ser.size(index);
39  break;
40 
41  case serializer::PACK:
42  index = obj.index();
43  ser.pack(index);
44  break;
45 
46  case serializer::UNPACK:
47  ser.unpack(index);
48 
49  // Set the active variant to index. The variant must be default-constructible.
50  // We cannot portably restore valueless_by_exception but we do nothing in that case.
51  if ( index != std::variant_npos ) set_index<std::index_sequence_for<Types...>>::array.at(index)(obj);
52  break;
53 
54  case serializer::MAP:
55  {
56  // TODO -- how to handle mapping of std::variant ?
57  return;
58  }
59  }
60 
61  // std::visit instantiates the generic lambda [&](auto& x) { SST_SER(x); } for each variant
62  // Types... in obj, and calls the one corresponding to obj's currently held variant
63 
64  // Serialize the currently active variant if it's not valueless_by_exception
65  if ( index != std::variant_npos ) std::visit([&](auto& x) { SST_SER(x); }, obj);
66  }
67 
68  // Table of functions to set the active variant
69  //
70  // This defines a partial specialization of the set_index<std::variant<Types...>> struct template which takes a
71  // single "type" template argument. This specialization matches std::index_sequence<INDEX...> representing a
72  // sequence of subscripts 0, 1, 2, ..., sizeof...(Types)-1 generated by std::index_sequence_for<Types...>
73  //
74  // This set_index partial specialization has a constexpr array of function pointers, each of which takes a
75  // std::variant<Types...>& obj argument and calls obj.emplace<INDEX>() which changes the active variant of obj to
76  // the Types... entry corresponding to INDEX. The emplace<INDEX>() method is called with no constructor arguments,
77  // which means that the new active variant will be default-constructed. This changing of the active variant happens
78  // before the new variant is deserialized in-place.
79  //
80  // Although std::visit can invoke a function with the currently active std::variant, it relies on knowing the
81  // currently active variant as returned by index(). To CHANGE the currently active variant requires an assignment
82  // or swap of the std::variant object or a call to the emplace() method.
83  //
84  // Changing the currently active variant to INDEX by calling emplace<INDEX>() requires that INDEX be a compile-time
85  // constant, and the effects of constructing the newly active variant are different for each of the Types... indexed
86  // by INDEX, and so a separate function table entry is needed for each INDEX so that the correct one can be
87  // dispatched at runtime.
88  //
89  // { obj.emplace<0>(), obj.emplace<1>(), obj.emplace<2>(), ..., obj.emplace<sizeof...(Types)-1>() }
90 
91  template <typename>
92  struct set_index;
93 
94  template <size_t INDEX>
95  static void set_index_func(std::variant<Types...>& obj)
96  {
97  obj.template emplace<INDEX>();
98  }
99 
100  template <size_t... INDEX>
101  struct set_index<std::index_sequence<INDEX...>>
102  {
103  static constexpr std::array<void (*)(std::variant<Types...>& obj), sizeof...(INDEX)> array = {
104  set_index_func<INDEX>...
105  };
106  };
107 
108  SST_FRIEND_SERIALIZE();
109 };
110 
111 } // namespace SST::Core::Serialization
112 
113 #endif // SST_CORE_SERIALIZATION_IMPL_SERIALIZE_VARIANT_H
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:42
Base serialize class.
Definition: serialize.h:113