Learning about serialization
/* * Some user defined data structures */ struct Particle { Particle() = default; Particle(double in_x, double in_y, double in_z) : x(in_x), y(in_y), z(in_z) { } // Non-message types can use serializers like this. template <typename SerializerT> void serialize(SerializerT& s) { s | x | y | z; } double x, y, z; }; struct Data { int a; template <typename SerializerT> void serialize(SerializerT& s) { s | a; } }; // TODO - show data with non-intrusive serialization // TODO - show data that does not need serialization // VT Base Message // \----------------/ // \ / struct ParticleMsg : ::vt::Message { using MessageParentType = ::vt::Message; // base message vt_msg_serialize_required(); // mark serialization mode ParticleMsg() = default; ParticleMsg(int in_x, int in_y, int in_z) : x(in_x), y(in_y), z(in_z) { } /* * Implement a serialize method so the std::vector and pointer are properly * serialization on the send. */ template <typename SerializerT> void serialize(SerializerT& s) { MessageParentType::serialize(s); // ensure parent is serialized consistently s | particles; s | x | y | z; // Serialize a pointer by first serializing whether it is non-null and then // the actual value if it's not non-null bool has_a = a != nullptr; s | has_a; if (has_a) { s | *a; } } public: std::vector<Particle> particles; int x = 0, y = 0, z = 0; Data* a = nullptr; }; // Forward declaration for the active message handler static void msgSerialA(ParticleMsg* msg); // Tutorial code to demonstrate serialization in active message sends static inline void activeMessageSerialization() { NodeType const this_node = ::vt::theContext()->getNode(); NodeType const num_nodes = ::vt::theContext()->getNumNodes(); (void)num_nodes; // don't warn about unused variable /* * The theMsg()->sendMsg(..) will serialize the message sent to the * destination node if it has a serialize method. If not, it will send the * message as if it is sent directly the sendMsg. */ if (this_node == 0) { NodeType const to_node = 1; auto msg = ::vt::makeMessage<ParticleMsg>(1,2,3); msg->particles.push_back(Particle{10,11,12}); msg->particles.push_back(Particle{13,14,15}); ::vt::theMsg()->sendMsg<msgSerialA>(to_node, msg); } } // Message handler static void msgSerialA(ParticleMsg* msg) { vtAssert(msg->particles.size() == 2, "Should be two particles"); vtAssert(msg->x == 1 && msg->y == 2 && msg->z == 3, "Values x,y,z incorrect"); auto const cur_node = ::vt::theContext()->getNode(); /* Node 0 sends MyMsg to node 1 in the above code so this should execute on * node 1 */ vtAssert(cur_node == 1, "This handler should execute on node 1"); ::fmt::print("msgSerialA: triggered on node={}\n", cur_node); }