Learn » Examples » Non-Intrusive Polymorphic Serialization Example w/Macros

The full code for this magistrate example can be found here: examples/checkpoint_example_polymorphic_macro_nonintrusive.cc

Example source code:

#include <checkpoint/checkpoint.h>
#include "checkpoint/dispatch/dispatch_virtual.h"

// \brief Namespace containing types which will be serialized
namespace checkpoint { namespace nonintrusive { namespace examples {

// \struct Abstract base class
struct MyBase {

  MyBase() { printf("MyBase cons\n"); }
  explicit MyBase(::checkpoint::SERIALIZE_CONSTRUCT_TAG) { printf("MyBase recons\n"); }

  virtual ~MyBase() = default;

  // Add serializing macro
  magistrate_virtual_serialize_root()

  int val_ = 0;

  virtual void test() = 0;
};

struct MyObj : public MyBase {

  explicit MyObj(int val) : MyBase() { printf("MyObj cons\n"); val_ = val;}
  explicit MyObj(::checkpoint::SERIALIZE_CONSTRUCT_TAG) {}

  // Add macro for serialization
  magistrate_virtual_serialize_derived_from(MyBase)

  void test() override {
    printf("test MyObj 10 == %d ?\n", val_);
    assert(val_ == 10);
  }
};

struct MyObj2 : public MyBase {
  explicit MyObj2(int val) { printf("MyObj2 cons\n"); val_=val; }
  explicit MyObj2(::checkpoint::SERIALIZE_CONSTRUCT_TAG) {}

  // Add macro for serialization
  magistrate_virtual_serialize_derived_from(MyBase)

  void test() override {
    printf("test MyObj2 20 == %d ?\n", val_);
    assert(val_ == 20);
  }
};

struct MyObj3 : public MyBase {

  int a=0, b=0, c=0;

  explicit MyObj3(int val) { printf("MyObj3 cons\n"); a= 10; b=20; c=100; val_=val;}
  explicit MyObj3(::checkpoint::SERIALIZE_CONSTRUCT_TAG) {}

  // Add macro for serialization
  magistrate_virtual_serialize_derived_from(MyBase)

  void test() override {
    printf("val_ 30  a 10 b 20 c 100 = %d %d %d %d\n", val_, a, b, c);
    assert(val_ == 30);
    assert(a==10);
    assert(b==20);
    assert(c==100);
  }
};

struct ExampleVector {
  std::vector<std::unique_ptr<MyBase>> vec;
};

void test() {

  ExampleVector v;
  v.vec.push_back(std::make_unique<MyObj3>(30));
  v.vec.push_back(std::make_unique<MyObj2>(20));
  v.vec.push_back(std::make_unique<MyObj>(10));

  auto ret = checkpoint::serialize(v);

  {
    // Display information about serialization result
    auto const& buf = ret->getBuffer();
    auto const& buf_size = ret->getSize();
    printf("ptr=%p, size=%ld\n*****\n\n", static_cast<void*>(buf), buf_size);
  }

  auto t = checkpoint::deserialize<ExampleVector>(ret->getBuffer());

  for (auto&& elm : t->vec) {
    elm->test();
  }
}

}}} // end namespace checkpoint::nonintrusive::examples

// \brief In Non-Intrusive way, serialize function needs to be placed in the namespace
// of the type which will be serialized.
namespace checkpoint { namespace nonintrusive { namespace examples {

template <typename S>
void serialize(S& s, MyBase& obj) {
  s | obj.val_;
  printf("MyBase: serialize val %d\n", obj.val_);
}

template <typename SerializerT>
void serialize(SerializerT&, MyObj&) {
  printf("MyObj: serialize\n");
}

template <typename SerializerT>
void serialize(SerializerT&, MyObj2&) {
  printf("MyObj2: serialize\n");
}

template <typename SerializerT>
void serialize(SerializerT& s, MyObj3& obj) {
  s | obj.a;
  s | obj.b;
  s | obj.c;
  printf("MyObj3: serialize a b c %d %d %d\n", obj.a, obj.b, obj.c);
}

template <typename SerializerT>
void serialize(SerializerT& s, ExampleVector& obj) {
  s | obj.vec;
}

}}} // end namespace checkpoint::nonintrusive::examples

int main(int, char**) {
  using namespace magistrate::nonintrusive::examples;

  test();

  return 0;
}