Empirical
serialize.h
Go to the documentation of this file.
1 
52 #ifndef EMP_SERIALIZE_H
53 #define EMP_SERIALIZE_H
54 
55 #include <iostream>
56 
57 #include "../base/vector.h"
58 #include "serialize_macros.h"
59 
60 namespace emp {
61 namespace serialize {
62 
64  class DataPod {
65  protected:
66  std::ostream * os;
67  std::istream * is;
68  bool own_os;
69  bool own_is;
70 
71  void ClearData() {
72  if (own_os && os) delete os;
73  if (own_is && is) delete is;
74  }
75  public:
76  DataPod(std::ostream & _os, std::istream & _is)
77  : os(&_os), is(&_is), own_os(false), own_is(false) { ; }
78  DataPod(std::iostream & _ios) : DataPod(_ios, _ios) { ; }
79 
80  // Allow move transfer of a DataPod.
81  DataPod(DataPod && rhs) : os(rhs.os), is(rhs.is), own_os(rhs.own_os), own_is(rhs.own_is) {
82  rhs.own_os = false; rhs.own_is=false;
83  }
85  ClearData();
86  os = rhs.os; is = rhs.is; own_os = rhs.own_os; own_is = rhs.own_is;
87  rhs.own_os = false; rhs.own_is=false;
88  return *this;
89  }
90 
91  // Make sure these are never accidentally created or copied.
92  DataPod() = delete;
93  DataPod(const DataPod &) = delete;
94 
96 
97  std::ostream & OStream() { return *os; }
98  std::istream & IStream() { return *is; }
99  };
100 
101 
106 
107  // Custom classes should run their built-in EMP_Store member function.
108  template <typename T>
109  auto StoreVar(DataPod & pod, const T & var, bool) -> typename T::emp_load_return_type & {
110  var.EMP_Store(pod);
111  return pod;
112  }
113 
114  // Special standard library types need to have a custom StoreVar method built.
115  template <typename T>
116  void StoreVar(DataPod & pod, const emp::vector<T> & var, bool) {
117  StoreVar(pod, var.size(), true);
118  for (int i = 0; i < (int) var.size(); ++i) {
119  StoreVar(pod, var[i], true);
120  }
121 
122  // @CAO for now use ':' separator, but more generally we need to ensure uniquness.
123  pod.OStream() << ':';
124  emp_assert(pod.OStream());
125  }
126 
127  // As a fallback, just send the saved object to the DataPod's output stream.
128  template <typename T>
129  void StoreVar(DataPod & pod, const T & var, int) {
130  // @CAO for now use ':', but more generally we need to ensure uniquness.
131  pod.OStream() << var << ':';
132  emp_assert(pod.OStream());
133  }
134 
135 
136  // The SetupLoad() function determines what type of information a constructor needs from
137  // a DataPod (based on the objects types) and returns that information. By default, the
138  // function will produce an instance of the needed type to trigger the copy constructor,
139  // but if a constructor exists that takes a DataPod it will use that instead.
140 
141  // Use SFINAE technique to identify custom types.
142  template <typename T>
143  auto SetupLoad(DataPod & pod, T*, bool) -> typename T::emp_load_return_type & {
144  return pod;
145  }
146 
147  // Otherwise use default streams.
148  template <typename T>
149  auto SetupLoad(DataPod & pod, const T*, int) -> T {
150  // std::decay<T> var;
151  T var;
152  pod.IStream() >> var;
153  pod.IStream().ignore(1); // Ignore ':'
154  emp_assert(pod.IStream() && "Make sure the DataPod is still okay.");
155  return var;
156  }
157 
158  // Use special load for strings.
159  std::string SetupLoad(DataPod & pod, std::string *, bool) {
160  std::string var;
161  std::getline(pod.IStream(), var, ':');
162  emp_assert(pod.IStream() && "Make sure the DataPod is still okay.");
163  return var;
164  }
165 
166  // Use special load for vectors of arbitrary type.
167  template <typename T>
169  const uint32_t v_size(SetupLoad(pod, &v_size, true));
170  emp::vector<T> var;
171 
172  // Create vector of correct size and create elements with pod.
173  for (uint32_t i = 0; i < v_size; i++) {
174  var.emplace_back(SetupLoad(pod, &(var[0]), true));
175  }
176  emp_assert(pod.IStream() && "Make sure the DataPod is still okay.");
177  return var;
178  }
179 
180 
181 
182  // Setup for a variadic Store() function that systematically save all variables in a DataPod.
183 
184  namespace internal {
185 
186  // Base implementaion to specialize on.
187  template <typename... IGNORE> struct serial_impl;
188 
189  // Specialized to recurse, storing or loading individual vars.
190  template <typename FIRST_TYPE, typename... OTHER_TYPES>
191  struct serial_impl<FIRST_TYPE, OTHER_TYPES...> {
192  static void Store(DataPod & pod, FIRST_TYPE & arg1, OTHER_TYPES&... others) {
193  StoreVar(pod, arg1, true);
194  serial_impl<OTHER_TYPES...>::Store(pod, others...);
195  }
196  };
197 
198  // End condition for recursion when no vars remaining.
199  template <> struct serial_impl<> {
200  static void Store(DataPod &) { ; }
201  };
202  }
203 
204  template <typename... ARG_TYPES>
205  void Store(DataPod & pod, ARG_TYPES&... args) {
207  }
208 
209 }
210 }
211 
212 #endif
DataPod(DataPod &&rhs)
Definition: serialize.h:81
std::istream & IStream()
Definition: serialize.h:98
auto StoreVar(DataPod &pod, const T &var, bool) -> typename T::emp_load_return_type &
Definition: serialize.h:109
DataPod(std::ostream &_os, std::istream &_is)
Definition: serialize.h:76
std::istream * is
Definition: serialize.h:67
static void Store(DataPod &pod, FIRST_TYPE &arg1, OTHER_TYPES &...others)
Definition: serialize.h:192
DataPod(std::iostream &_ios)
Definition: serialize.h:78
size_t size() const
Definition: vector.h:151
void emplace_back(ARGS &&...args)
Definition: vector.h:219
Macros for simplifying to serialization of objects.
std::ostream * os
Definition: serialize.h:66
void Store(DataPod &pod, ARG_TYPES &...args)
Definition: serialize.h:205
Definition: serialize.h:187
If we are in emscripten, make sure to include the header.
Definition: array.h:37
bool own_is
Definition: serialize.h:69
std::ostream & OStream()
Definition: serialize.h:97
#define emp_assert(...)
Definition: assert.h:199
static void Store(DataPod &)
Definition: serialize.h:200
bool own_os
Definition: serialize.h:68
~DataPod()
Definition: serialize.h:95
DataPod & operator=(DataPod &&rhs)
Definition: serialize.h:84
void ClearData()
Definition: serialize.h:71
A DataPod managed information about another class for serialization.
Definition: serialize.h:64
auto SetupLoad(DataPod &pod, T *, bool) -> typename T::emp_load_return_type &
Definition: serialize.h:143