Learn » Examples » Program Example Traversal

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

Example source code:

#include <checkpoint/checkpoint.h>

#include <cstdio>
#include <string>

namespace checkpoint { namespace intrusive { namespace examples {

struct TestObject {

  TestObject() = default;

  struct MakeTag { };

  explicit TestObject(MakeTag) {
    for (int i = 0; i < 10; i++) {
      vec1.push_back(i);
      vec2.push_back(i * 29.34);
      vec3.push_back("hello: " + std::to_string(vec2.back()));
    }
  }

  template <typename Serializer>
  void serialize(Serializer& s) {
    s | a | b | vec1 | vec2 | vec3;
  }

private:
  int a = 29;
  int b = 36;
  std::vector<int> vec1;
  std::vector<double> vec2;
  std::vector<std::string> vec3;
};

}}} // end namespace checkpoint::intrusive::examples

struct PrintBytesTraverse : magistrate::BaseSerializer {
  PrintBytesTraverse() : magistrate::BaseSerializer(magistrate::eSerializationMode::None) { }

  void contiguousBytes(void*, std::size_t size, std::size_t num_elms) {
    printf("PrintBytesTraverse: size=%zu, num_elms=%zu\n", size, num_elms);
  }
};

template <typename U>
struct ToString {
  static std::string apply(U& u) { return std::to_string(u); }
};

template <>
struct ToString<std::string> {
  static std::string apply(std::string& u) { return u; }
};

template <typename SerializerT, typename T>
struct CustomDispatch {
  static void serializeIntrusive(SerializerT& s, T& t) {
    t.serialize(s);
  }
  static void serializeNonIntrusive(SerializerT& s, T& t) {
    serialize(s, t);
  }
};

// std::vector specialization for dispatcher, vector is always non-intrusive so
// skip that overload
template <typename SerializerT, typename U>
struct CustomDispatch<SerializerT, std::vector<U>> {
  static void serializeNonIntrusive(SerializerT&, std::vector<U>& t) {
    // Do something special here: e.g., an RDMA for the vector during packing
    printf("Traversing vector: size=%zu\n", t.size());
    for (std::size_t i = 0; i < t.size(); i++) {
      printf("\t vector[%zu]=%s", i, ToString<U>::apply(t[i]).c_str());
    }
    printf("\n");
  }
};

struct TypedTraverse : magistrate::BaseSerializer {
  template <typename U, typename V>
  using DispatcherType = CustomDispatch<U, V>;

  TypedTraverse() : magistrate::BaseSerializer(magistrate::eSerializationMode::None) { }

  template <typename SerializerT, typename T>
  void contiguousTyped(SerializerT&, T*, std::size_t num_elms) {
    printf("TypedTraverse: type is %s, num=%zu\n", typeid(T).name(), num_elms);
  }
};

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

  TestObject my_obj(TestObject::MakeTag{});

  // Traverse my_obj with a custom traverser that prints the bytes
  magistrate::dispatch::Traverse::with<TestObject, PrintBytesTraverse>(my_obj);

  // Traverse my_obj with a custom traverser and dispatcher that prints the
  // types and lens
  magistrate::dispatch::Traverse::with<TestObject, TypedTraverse>(my_obj);

  return 0;
}