Symphony Of Empires
serializer.hpp
Go to the documentation of this file.
1 // Eng3D - General purpouse game engine
2 // Copyright (C) 2021, Eng3D contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // serializer.hpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #pragma once
26 
27 #include <cstddef>
28 #include <cstdint>
29 #include <cstring>
30 #include <exception>
31 #include <numeric>
32 #include <string>
33 #include <vector>
34 #include <memory>
35 #include <optional>
36 #include <type_traits>
37 #include <bitset>
38 #include <limits>
39 #include <concepts>
40 #include <glm/glm.hpp>
41 #include "eng3d/utils.hpp"
42 #include "eng3d/string.hpp"
43 #include "eng3d/rectangle.hpp"
44 #include "eng3d/freelist.hpp"
45 
46 namespace Eng3D::Deser {
51  class Exception : public ::std::exception {
52  ::std::string buffer;
53  public:
54  Exception(const ::std::string& msg) {
55  buffer = msg;
56  }
57  virtual const char* what() const noexcept {
58  return buffer.c_str();
59  }
60  };
61 
64  struct Archive {
65  Archive() = default;
66  ~Archive() = default;
67  void to_file(const ::std::string& path);
68  void from_file(const ::std::string& path);
69  void copy_to(void* ptr, size_t size);
70  void copy_from(const void* ptr, size_t size);
71 
72  inline void expand(size_t amount) {
73  buffer.resize(buffer.size() + amount);
74  }
75 
76  inline void end_stream() {
77  buffer.shrink_to_fit();
78  }
79 
80  inline void rewind() {
81  ptr = 0;
82  }
83 
84  inline const void* get_buffer() {
85  return static_cast<const void*>(&buffer[0]);
86  }
87 
88  inline void set_buffer(const void* buf, size_t size) {
89  buffer.resize(size);
90  ::std::memcpy(buffer.data(), buf, size);
91  }
92 
93  inline size_t size() {
94  return buffer.size();
95  }
96 
97  ::std::vector<uint8_t> buffer;
98  size_t ptr = 0;
99  };
100 
101  template<bool is_const, typename T>
103  template<typename T>
104  struct CondConstType<true, T> { using type = const ::std::remove_reference_t<T>; };
105  template<typename T>
106  struct CondConstType<false, T> { using type = ::std::remove_reference_t<T>; };
107 
110  template<typename T>
111  struct Serializer {
112  template<bool is_const>
114 #ifdef DEBUG_SERIALIZER
115  template<bool is_serialize = true>
116  static inline void deser_dynamic(Eng3D::Deser::Archive&, T&&) {
117  CXX_THROW(Eng3D::Deser::Exception, "Implement your serializer function!");
118  }
119 
120  template<bool is_serialize = false>
121  static inline void deser_dynamic(Eng3D::Deser::Archive&, const T&&) {
122  CXX_THROW(Eng3D::Deser::Exception, "Implement your deserializer function!");
123  }
124 #endif
125  };
126 
130  template<bool is_serialize, typename T>
131  void deser_dynamic(Eng3D::Deser::Archive& ar, T& obj);
132 
133  template<bool is_serialize = true, typename T>
134  void deser_dynamic(Eng3D::Deser::Archive& ar, const T& obj) {
135  Serializer<::std::remove_reference_t<T>>::template deser_dynamic<is_serialize>(ar, obj);
136  }
137 
138  template<bool is_serialize = false, typename T>
140  Serializer<::std::remove_reference_t<T>>::template deser_dynamic<is_serialize>(ar, obj);
141  }
142 
143  template<typename T>
144  inline void serialize(Eng3D::Deser::Archive& ar, const T& obj) {
145  Serializer<::std::remove_reference_t<T>>::template deser_dynamic<true>(ar, obj);
146  }
147 
148  template<typename T>
149  inline void serialize(Eng3D::Deser::Archive& ar, T& obj) {
150  Serializer<::std::remove_reference_t<T>>::template deser_dynamic<true>(ar, obj);
151  }
152 
153  template<typename T>
154  inline void deserialize(Eng3D::Deser::Archive& ar, T& obj) {
155  Serializer<::std::remove_reference_t<T>>::template deser_dynamic<false>(ar, obj);
156  }
157 
161  template<typename T>
163  template<bool is_const>
165 
166  template<bool is_serialize>
168  if constexpr(is_serialize) ar.copy_from(&obj, sizeof(T));
169  else ar.copy_to(&obj, sizeof(T));
170  }
171  };
172 
173  template<typename T>
174  concept SerializerScalar = std::is_integral_v<T> || std::is_floating_point_v<T>;
175  template<SerializerScalar T>
176  class Serializer<T> {
177  constexpr static auto scaling = 1000.f;
178  public:
179  template<bool is_const>
181 
182  template<bool is_serialize>
184  if constexpr(std::is_floating_point_v<T>) {
185  auto tmp = static_cast<int32_t>(obj * scaling);
186  Eng3D::Deser::deser_dynamic<is_serialize>(ar, tmp);
187  if constexpr(!is_serialize)
188  obj = static_cast<T>(tmp) * (1.f / scaling);
189  } else {
190  if constexpr(is_serialize && ::std::endian::native == ::std::endian::big)
191  obj = ::std::byteswap<T>(obj);
192  SerializerMemcpy<T>::template deser_dynamic<is_serialize>(ar, obj);
193  if constexpr(!is_serialize && ::std::endian::native == ::std::endian::big)
194  obj = ::std::byteswap<T>(obj);
195  }
196  }
197  };
198 
199  template<typename T>
200  concept SerializerContainer = requires(T a, T b) {
201 #if defined(__GNUC__) && !defined(__clang__) && !defined(__llvm__)
202  requires std::destructible<typename T::value_type>;
203  requires std::forward_iterator<typename T::iterator>;
204 #endif
205  { a.begin() } -> std::same_as<typename T::iterator>;
206  { a.end() } -> std::same_as<typename T::iterator>;
207  };
210  template<SerializerContainer T>
211  struct Serializer<T> {
212  static constexpr auto max_elements = 163550 * 32;
213 
214  template<bool is_const>
216 
217  template<bool is_serialize>
218  static inline void deser_dynamic(Eng3D::Deser::Archive& ar, type<is_serialize>& obj_group) {
219  uint32_t len = obj_group.size();
220  Eng3D::Deser::deser_dynamic<is_serialize>(ar, len);
221  if(!len) return; // Early exit iff nothing to do
222 
223  if(len >= max_elements)
224  CXX_THROW(Eng3D::Deser::Exception, "Exceeded max element count");
225 
226  if constexpr(is_serialize) {
227  for(auto& obj : obj_group)
228  Eng3D::Deser::deser_dynamic<true>(ar, obj);
229  } else {
230  if constexpr(requires(T a) { a.clear(); })
231  obj_group.clear();
232 
233  // No insert means this is a static array of some sort, ::std::array perhaps?
234  constexpr bool has_insert = requires(T a, typename T::value_type tp) { a.insert(tp); };
235  constexpr bool has_resize = requires(T a, size_t n) { a.resize(n); };
236  if constexpr(!has_insert && !has_resize) {
237  for(decltype(len) i = 0; i < len; i++)
238  Eng3D::Deser::deser_dynamic<false>(ar, obj_group[i]);
239  } else {
240  if constexpr(has_resize) {
241  obj_group.resize(len);
242  for(decltype(len) i = 0; i < len; i++)
243  Eng3D::Deser::deser_dynamic<false>(ar, obj_group[i]);
244  } else { // non-len, no resize
245  for(decltype(len) i = 0; i < len; i++) {
246  typename T::value_type obj{}; // Initialized but then overwritten by the deserializer
247  Eng3D::Deser::deser_dynamic<false>(ar, obj);
248  constexpr bool has_push_back = requires(T a, typename T::value_type tp) { a.push_back(tp); };
249  if constexpr(has_push_back)
250  obj_group.push_back(obj);
251  else if constexpr(has_insert)
252  obj_group.insert(obj);
253  }
254  }
255  }
256  }
257  }
258  };
259 
261  // explicitly recast this boolean into a uint8_t to avoid problems
262  template<>
263  struct Serializer<bool> {
264  template<bool is_const>
266 
267  template<bool is_serialize>
269  auto tmp = static_cast<char>(obj);
270  Eng3D::Deser::deser_dynamic<is_serialize>(ar, tmp);
271  if constexpr(!is_serialize) {
272  obj = tmp;
273  }
274  }
275  };
276 
278  template<typename T, typename U>
279  struct Serializer<::std::pair<T, U>> {
280  template<bool is_const>
282 
283  template<bool is_serialize>
285  using tp_1 = ::std::remove_const_t<T>;
286  using tp_2 = ::std::remove_const_t<U>;
287  Eng3D::Deser::deser_dynamic<is_serialize>(ar, const_cast<tp_1&>(obj.first));
288  Eng3D::Deser::deser_dynamic<is_serialize>(ar, const_cast<tp_2&>(obj.second));
289  }
290  };
291 
292  template<typename T, int N>
294  template<bool is_const>
296 
297  template<bool is_serialize>
298  static inline void deser_dynamic(Eng3D::Deser::Archive& ar, type<is_serialize>& obj_group) {
299  unsigned long num = obj_group.to_ulong();
300  if constexpr(is_serialize) {
301  Eng3D::Deser::deser_dynamic<is_serialize>(ar, num);
302  } else {
303  Eng3D::Deser::deser_dynamic<is_serialize>(ar, num);
304  obj_group = T(num);
305  }
306  }
307  };
308  template<size_t bits>
309  struct Serializer<::std::bitset<bits>> : SerializerBitset<::std::bitset<bits>, bits> {};
310 
311  template<>
313  template<bool is_const>
315 
316  template<bool is_serialize>
318  Eng3D::Deser::deser_dynamic<is_serialize>(ar, obj.id);
319  }
320  };
321 
322  template<>
324  template<bool is_const>
326 
327  template<bool is_serialize>
329  Eng3D::Deser::deser_dynamic<is_serialize>(ar, obj.left);
330  Eng3D::Deser::deser_dynamic<is_serialize>(ar, obj.right);
331  Eng3D::Deser::deser_dynamic<is_serialize>(ar, obj.top);
332  Eng3D::Deser::deser_dynamic<is_serialize>(ar, obj.bottom);
333  }
334  };
335 
336  template<typename T>
337  struct Serializer<std::optional<T>> {
338  template<bool is_const>
340 
341  template<bool is_serialize>
343  if constexpr(is_serialize) {
344  auto has_value = obj.has_value();
345  Eng3D::Deser::deser_dynamic<is_serialize>(ar, has_value);
346  if(has_value)
347  Eng3D::Deser::deser_dynamic<is_serialize>(ar, obj.value());
348  } else {
349  bool has_value = false;
350  Eng3D::Deser::deser_dynamic<is_serialize>(ar, has_value);
351  if(has_value) {
352  obj.emplace();
353  Eng3D::Deser::deser_dynamic<is_serialize>(ar, obj.value());
354  }
355  }
356  }
357  };
358 
359  template<typename T>
360  struct Serializer<Eng3D::Freelist<T>> {
361  template<bool is_const>
363 
364  template<bool is_serialize>
366  Eng3D::Deser::deser_dynamic<is_serialize>(ar, obj.data);
367  Eng3D::Deser::deser_dynamic<is_serialize>(ar, obj.slots);
368  }
369  };
370 
372 }
The purpouse of the serializer is to serialize objects onto a byte stream that can be transfered onto...
Definition: serializer.hpp:51
Exception(const ::std::string &msg)
Definition: serializer.hpp:54
virtual const char * what() const noexcept
Definition: serializer.hpp:57
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj_group)
Definition: serializer.hpp:218
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj)
Definition: serializer.hpp:183
typename CondConstType< is_const, T >::type type
Definition: serializer.hpp:180
concept SerializerScalar
Definition: serializer.hpp:174
void deser_dynamic(Eng3D::Deser::Archive &ar, T &obj)
Template generic (de)-serializer.
Definition: serializer.hpp:139
concept SerializerContainer
Definition: serializer.hpp:200
void deserialize(Eng3D::Deser::Archive &ar, T &obj)
Definition: serializer.hpp:154
void serialize(Eng3D::Deser::Archive &ar, const T &obj)
Definition: serializer.hpp:144
Definition: utils.hpp:35
Base class that serves as archiver, stores (in memory) the data required for serialization/deserializ...
Definition: serializer.hpp:64
::std::vector< uint8_t > buffer
Definition: serializer.hpp:97
void set_buffer(const void *buf, size_t size)
Definition: serializer.hpp:88
void to_file(const ::std::string &path)
Definition: serializer.cpp:40
void from_file(const ::std::string &path)
Definition: serializer.cpp:61
void expand(size_t amount)
Definition: serializer.hpp:72
const void * get_buffer()
Definition: serializer.hpp:84
void copy_from(const void *ptr, size_t size)
Definition: serializer.cpp:94
void copy_to(void *ptr, size_t size)
Definition: serializer.cpp:87
::std::remove_reference_t< T > type
Definition: serializer.hpp:106
const ::std::remove_reference_t< T > type
Definition: serializer.hpp:104
typename CondConstType< is_const, Eng3D::Freelist< T > >::type type
Definition: serializer.hpp:362
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj)
Definition: serializer.hpp:365
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj)
Definition: serializer.hpp:328
typename CondConstType< is_const, Eng3D::Rectangle >::type type
Definition: serializer.hpp:325
typename CondConstType< is_const, Eng3D::StringRef >::type type
Definition: serializer.hpp:314
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj)
Definition: serializer.hpp:317
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj)
Definition: serializer.hpp:268
typename CondConstType< is_const, bool >::type type
Definition: serializer.hpp:265
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj)
Definition: serializer.hpp:342
typename CondConstType< is_const, std::optional< T > >::type type
Definition: serializer.hpp:339
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj)
Definition: serializer.hpp:284
typename CondConstType< is_const, ::std::pair< T, U > >::type type
Definition: serializer.hpp:281
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj_group)
Definition: serializer.hpp:298
typename CondConstType< is_const, T >::type type
Definition: serializer.hpp:295
A serializer (base class) which can be used to serialize objects and create per-object optimized clas...
Definition: serializer.hpp:111
typename CondConstType< is_const, T >::type type
Definition: serializer.hpp:113
A serializer optimized to memcpy directly the element into the byte stream use only when the object c...
Definition: serializer.hpp:162
static void deser_dynamic(Eng3D::Deser::Archive &ar, type< is_serialize > &obj)
Definition: serializer.hpp:167
typename CondConstType< is_const, T >::type type
Definition: serializer.hpp:164
A reference to a string on the global string pool.
Definition: string.hpp:39
#define CXX_THROW(class,...)
Definition: utils.hpp:98