SPH
Serializer.h
Go to the documentation of this file.
1 #pragma once
2 
7 
8 #include "io/Path.h"
11 #include "system/Settings.h"
12 #include <fstream>
13 
15 
16 namespace Detail {
21 template <bool Precise, typename T, typename TEnabler = void>
23 
24 template <bool Precise, typename T>
25 struct SerializedType<Precise, T, std::enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value>> {
26  // convert all intergral types and enums to int64_t
27  using Type = std::conditional_t<Precise, int64_t, int32_t>;
28 };
29 template <bool Precise, typename T>
30 struct SerializedType<Precise, T, std::enable_if_t<std::is_floating_point<T>::value>> {
31  // convert floating point types to double
32  using Type = std::conditional_t<Precise, double, float>;
33 };
34 template <bool Precise, Size N>
35 struct SerializedType<Precise, char[N]> {
36  // keep char[] as is
37  using Type = std::add_lvalue_reference_t<const char[N]>;
38 };
39 
40 template <bool Precise, typename T>
42 
43 } // namespace Detail
44 
46 template <bool Precise>
47 class Serializer : public Noncopyable {
48 private:
49  std::ofstream ofs;
50  Array<char> buffer;
51 
52 public:
53  Serializer(const Path& path)
54  : ofs(path.native(), std::ios::binary) {}
55 
56  template <typename... TArgs>
57  void write(const TArgs&... args) {
58  buffer.clear();
59  this->serializeImpl(buffer, args...);
60  ofs.write(&buffer[0], buffer.size());
61  }
62 
63  void addPadding(const Size size) {
64  buffer.resize(size);
65  buffer.fill('\0');
66  ofs.write(&buffer[0], size);
67  }
68 
69  void flush() {
70  ofs.flush();
71  }
72 
73 private:
74  template <typename T0, typename... TArgs>
75  void serializeImpl(Array<char>& bytes, const T0& t0, const TArgs&... args) {
76  const Size size = bytes.size();
77  using ActType = Detail::Serialized<Precise, T0>;
78 
79  bytes.resize(size + sizeof(ActType));
80  ActType serializable = static_cast<ActType>(t0);
81  const char* c = reinterpret_cast<const char*>(&serializable);
82  for (Size i = 0; i < sizeof(ActType); ++i) {
83  bytes[size + i] = c[i];
84  }
85  this->serializeImpl(bytes, args...);
86  }
87 
88  template <typename... TArgs>
89  void serializeImpl(Array<char>& bytes, const std::string& s, const TArgs&... args) {
90  const Size size = bytes.size();
91  bytes.resize(size + s.size() + 1);
92  const char* c = s.c_str();
93  for (Size i = 0; i < s.size() + 1; ++i) {
94  bytes[size + i] = c[i];
95  }
96  SPH_ASSERT(bytes[bytes.size() - 1] == '\0');
97  this->serializeImpl(bytes, args...);
98  }
99 
100 
101  void serializeImpl(Array<char>& UNUSED(bytes)) {}
102 };
103 
105 class SerializerException : public std::exception {
106 private:
107  std::string error;
108 
109 public:
112  SerializerException(const std::string& error, const Size position)
113  : error(error) {
114  this->error += " at position " + std::to_string(position);
115  }
116 
117  virtual const char* what() const noexcept override {
118  return error.c_str();
119  }
120 };
121 
123 template <bool Precise>
124 class Deserializer : public Noncopyable {
125 private:
126  std::ifstream ifs;
127  Array<char> buffer;
128 
129 public:
131  Deserializer(const Path& path)
132  : ifs(path.native(), std::ios::binary) {
133  if (!ifs) {
134  this->fail("Cannot open file " + path.native() + " for reading.");
135  }
136  }
137 
143  template <typename... TArgs>
144  void read(TArgs&... args) {
145  return this->readImpl(args...);
146  }
147 
149  void skip(const Size size) {
150  if (!ifs.seekg(size, ifs.cur)) {
151  this->fail("Failed to skip " + std::to_string(size) + " bytes in the stream");
152  }
153  }
154 
155 private:
156  template <typename T0, typename... TArgs>
157  void readImpl(T0& t0, TArgs&... args) {
158  static_assert(!std::is_array<T0>::value, "String must be read as std::string");
159  using ActType = Detail::Serialized<Precise, T0>;
160  static_assert(sizeof(ActType) > 0, "Invalid size of ActType");
161  buffer.resize(sizeof(ActType));
162  if (!ifs.read(&buffer[0], sizeof(ActType))) {
164  this->fail("Failed to read a primitive of size " + std::to_string(sizeof(ActType)));
165  }
166  t0 = T0(reinterpret_cast<ActType&>(buffer[0]));
167  this->readImpl(args...);
168  }
169 
170  template <std::size_t N, typename... TArgs>
171  void readImpl(char (&ar)[N], TArgs&... args) {
172  if (!ifs.read(ar, N)) {
173  this->fail("Failed to read an array of size " + std::to_string(N));
174  }
175  this->readImpl(args...);
176  }
177 
178  template <typename... TArgs>
179  void readImpl(std::string& s, TArgs&... args) {
180  buffer.clear();
181  char c;
182  while (ifs.read(&c, 1) && c != '\0') {
183  buffer.push(c);
184  }
185  buffer.push('\0');
186  s = &buffer[0];
187  if (!ifs) {
188  this->fail("Error while deseralizing string from stream, got: " + s);
189  }
190  this->readImpl(args...);
191  }
192 
193  void readImpl() {}
194 
195  void fail(const std::string& error) {
196  throw SerializerException(error, ifs.tellg());
197  }
198 };
199 
Generic dynamically allocated resizable storage.
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
Wrapper of type value of which may or may not be present.
Object representing a path on a filesystem, similar to std::filesystem::path in c++17.
constexpr int N
void resize(const TCounter newSize)
Resizes the array to new size.
Definition: Array.h:215
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Definition: Array.h:306
void fill(const T &t)
Sets all elements of the array to given value.
Definition: Array.h:187
void clear()
Removes all elements from the array, but does NOT release the memory.
Definition: Array.h:434
INLINE TCounter size() const noexcept
Definition: Array.h:193
Object for reading serialized primitives from input stream.
Definition: Serializer.h:124
void skip(const Size size)
Skip a number of bytes in the stream; used to skip unused parameters or padding bytes.
Definition: Serializer.h:149
void read(TArgs &... args)
Definition: Serializer.h:144
Deserializer(const Path &path)
Opens a stream associated with given path and prepares the file for deserialization.
Definition: Serializer.h:131
Object representing a path on a filesystem.
Definition: Path.h:17
std::string native() const
Returns the native version of the path.
Definition: Path.cpp:71
Exception thrown by Deserializer on failure.
Definition: Serializer.h:105
SerializerException(const std::string &error, const Size position)
Definition: Serializer.h:112
virtual const char * what() const noexcept override
Definition: Serializer.h:117
Object providing serialization of primitives into a stream.
Definition: Serializer.h:47
Serializer(const Path &path)
Definition: Serializer.h:53
void addPadding(const Size size)
Definition: Serializer.h:63
void flush()
Definition: Serializer.h:69
void write(const TArgs &... args)
Definition: Serializer.h:57
Generic storage and input/output routines of settings.
typename SerializedType< Precise, T >::Type Serialized
Definition: Serializer.h:41
Vector position(const Float a, const Float e, const Float u)
Computes the position on the elliptic trajectory.
Definition: TwoBody.cpp:82
Overload of std::swap for Sph::Array.
Definition: Array.h:578
std::add_lvalue_reference_t< const char[N]> Type
Definition: Serializer.h:37
Type trait for serialization/deserialization of types.
Definition: Serializer.h:22
Object with deleted copy constructor and copy operator.
Definition: Object.h:54