Learn » Examples » Non-Intrusive Program Example Serialize To File

One potential application for this approach is to generate a restart file for a simulation.

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

Example source code:

#include <checkpoint/checkpoint.h>

#include <iostream>
#include <vector>

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

static constexpr int const u_val = 934;

// \struct MyTestType
// \brief Simple structure with two variables of built-in types
struct MyTestType {

  // \brief Default constructor
  //
  // The default constructor is needed for the (de)serialization.
  //
  MyTestType() = default;

  // \brief Constructor with two parameters
  //
  // \param[in] Initial value for `a`
  // \param[in] Initial value for `b`
  //
  explicit MyTestType(int len) : u_(), len_(len)
  {
    u_.resize(len_);
    for (int i = 0; i < len_; ++i)
      u_[i] = u_val + i;
  }

  //
  // Friend functions
  //
  friend bool operator== (const MyTestType &c1, const MyTestType &c2);

  //
  // Variables
  //

  std::vector<double> u_;
  int len_ = 0;

};

bool operator==(const MyTestType &c1, const MyTestType &c2)
{
  if (c1.len_ != c2.len_)
    return false;
  bool isEqual = true;
  for (int i = 0; i < c1.len_; ++i) {
    if (c1.u_[i] != c2.u_[i]) {
      isEqual = false;
      break;
    }
  }
  return isEqual;
}

}}} // 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 {

// \brief Templated function for serializing/deserializing
// a variable of type `MyTestType`
//
// \tparam <Serializer> { Type for storing the serialized result }
// \param[in,out] Variable for storing the serialized result
//
// \note The routine `serialize` is actually a two-way routine:
// - it creates the serialized result `s` by combining
//   the variables `u_` and `len_`; this creation phase is run
//   when the status of the serializer `s` is `Packing`.
// - it can extract from a serialized result `s` the values
//   to place in the variables `u_` and `len_`; this extraction phase is run
//   when the status of the serializer `s` is `Unpacking`.
//
template <typename Serializer>
void serialize(Serializer& s, MyTestType& c) {
  s | c.u_;
  s | c.len_;
}

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

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

  // Define a variable of custom type `MyTestType`
  MyTestType my_test_inst(11);

  // Call the serialization routine for the variable `my_test_inst`
  // The output is a unique pointer: `std::unique_ptr<SerializedInfo>`
  // (defined in `src/checkpoint_api.h`)
  std::string my_filename = "CheckpointExampleToFileNoninstrusive.txt";
  magistrate::serializeToFile(my_test_inst, my_filename);

  //
  // De-serializes from the file an object of type 'MyTestType'
  // out will be an object of type 'std::unique_ptr<MyTestType>'
  //
  auto out = magistrate::deserializeFromFile<MyTestType>(my_filename);

  if (my_test_inst == *out) {
    std::cout << " Serialization / Deserialization from file worked. \n";
  } else {
    std::cout << " Serialization / Deserialization from file failed. \n" << std::flush;
    assert(false);
  }

  //
  // Another option is to de-serialize into an existing object of type 'MyTestType'
  //
  MyTestType out_2;

  //
  // Here 'out_2' will contain an empty vector and an integer 'len_' set to 0.
  //

  magistrate::deserializeInPlaceFromFile<MyTestType>(my_filename, &out_2);

  //
  // Now 'out_2' will contain:
  // - a resized vector filled with the values stored in the file;
  // - an integer 'len_' equal to the length of the vector stored in the file.
  //

  if (my_test_inst == out_2) {
    std::cout << " Deserialization in-place from file worked. \n";
  } else {
    std::cout << " Deserialization in-place from file failed. \n" << std::flush;
    assert(false);
  }

  return 0;
}