OGLplus  (0.59.0) a C++ wrapper for rendering APIs

write.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_SERIALIZE_WRITE_HPP
10 #define EAGINE_SERIALIZE_WRITE_HPP
11 
12 #include "../assert.hpp"
13 #include "../bitfield.hpp"
14 #include "../nothing.hpp"
15 #include "../reflect/data_members.hpp"
16 #include "../reflect/enumerators.hpp"
17 #include "../valid_if/decl.hpp"
18 #include "fwd.hpp"
19 #include "write_backend.hpp"
20 #include <array>
21 #include <chrono>
22 #include <string>
23 #include <tuple>
24 #include <type_traits>
25 #include <vector>
26 
27 namespace eagine {
28 //------------------------------------------------------------------------------
29 template <typename T>
30 class fragment_serialize_wrapper<span<const T>> {
31 public:
32  constexpr fragment_serialize_wrapper() noexcept = default;
33 
34  fragment_serialize_wrapper(span<const T> src) noexcept
35  : _src{src} {}
36 
37  auto remaining() const noexcept {
38  return skip(_src, _offset);
39  }
40 
41  auto offset() const noexcept {
42  return _offset;
43  }
44 
45  void advance(span_size_t inc) noexcept {
46  _offset += inc;
47  }
48 
49  auto is_done() const noexcept -> bool {
50  return !remaining();
51  }
52 
53 private:
54  span<const T> _src{};
55  span_size_t _offset{0};
56 };
57 //------------------------------------------------------------------------------
58 template <typename T>
59 struct serializer;
60 //------------------------------------------------------------------------------
61 template <typename T>
62 struct serializer<T&> : serializer<T> {};
63 //------------------------------------------------------------------------------
64 template <typename T>
65 struct serializer<const T&> : serializer<T> {};
66 //------------------------------------------------------------------------------
67 template <typename T>
68 struct plain_serializer {
69  template <typename Backend>
70  static auto write(T value, Backend& backend) {
71  span_size_t written{0};
72  auto errors = backend.write(view_one(value), written);
73  if(EAGINE_UNLIKELY(written < 1)) {
74  EAGINE_ASSERT(errors.has(serialization_error_code::too_much_data));
75  }
76  return errors;
77  }
78 
79  template <typename Backend>
80  static auto write(span<const T> values, Backend& backend) {
81  span_size_t written{0};
82  auto errors = backend.write(values, written);
83  if(EAGINE_UNLIKELY(written < 1)) {
84  EAGINE_ASSERT(errors.has(serialization_error_code::too_much_data));
85  } else if(EAGINE_UNLIKELY(written < values.size())) {
86  EAGINE_ASSERT(
89  }
90  return errors;
91  }
92 };
93 
94 //------------------------------------------------------------------------------
95 template <>
96 struct serializer<bool> : plain_serializer<bool> {};
97 template <>
98 struct serializer<char> : plain_serializer<char> {};
99 template <>
100 struct serializer<std::int8_t> : plain_serializer<std::int8_t> {};
101 template <>
102 struct serializer<short> : plain_serializer<short> {};
103 template <>
104 struct serializer<int> : plain_serializer<int> {};
105 template <>
106 struct serializer<long> : plain_serializer<long> {};
107 template <>
108 struct serializer<long long> : plain_serializer<long long> {};
109 template <>
110 struct serializer<std::uint8_t> : plain_serializer<std::uint8_t> {};
111 template <>
112 struct serializer<unsigned short> : plain_serializer<unsigned short> {};
113 template <>
114 struct serializer<unsigned> : plain_serializer<unsigned> {};
115 template <>
116 struct serializer<unsigned long> : plain_serializer<unsigned long> {};
117 template <>
118 struct serializer<unsigned long long> : plain_serializer<unsigned long long> {};
119 template <>
120 struct serializer<float> : plain_serializer<float> {};
121 template <>
122 struct serializer<double> : plain_serializer<double> {};
123 template <>
124 struct serializer<identifier> : plain_serializer<identifier> {};
125 template <>
126 struct serializer<decl_name> : plain_serializer<decl_name> {};
127 template <>
128 struct serializer<string_view> : plain_serializer<string_view> {};
129 //------------------------------------------------------------------------------
130 template <typename T>
131 struct common_serializer {
132 
133  template <typename Backend>
134  auto write(span<const T> values, Backend& backend) const {
137  auto& sink = extract(backend.sink());
138  serialization_errors errors{};
139  span_size_t i = 0;
140  for(auto& elem : values) {
141  auto th = sink.begin_work();
142  errors |= backend.begin_element(i);
143  if(EAGINE_LIKELY(!errors)) {
144  errors |=
145  static_cast<const serializer<T>*>(this)->write(elem, backend);
146  errors |= backend.finish_element(i++);
147  if(EAGINE_LIKELY(!errors)) {
148  sink.commit(th);
149  } else if(errors.has_at_most(tmd)) {
150  errors.clear(tmd);
151  errors |= icw;
152  sink.rollback(th);
153  break;
154  } else {
155  break;
156  }
157  } else if(errors.has_only(tmd)) {
158  errors.clear(tmd);
159  errors |= icw;
160  sink.rollback(th);
161  break;
162  } else {
163  break;
164  }
165  }
166  return errors;
167  }
168 };
169 //------------------------------------------------------------------------------
170 template <typename... T>
171 struct serializer<std::tuple<T...>> : common_serializer<std::tuple<T...>> {
172 
173  using common_serializer<std::tuple<T...>>::write;
174 
175  template <typename Backend>
176  auto write(const std::tuple<T...>& values, Backend& backend) const {
177  serialization_errors errors{};
178  errors |= backend.begin_list(span_size(sizeof...(T)));
179  if(EAGINE_LIKELY(!errors)) {
180  _write_elements(
181  errors, values, backend, std::make_index_sequence<sizeof...(T)>());
182  errors |= backend.finish_list();
183  }
184  return errors;
185  }
186 
187 private:
188  template <typename Tuple, typename Backend, std::size_t... I>
189  void _write_elements(
190  serialization_errors& errors,
191  Tuple& values,
192  Backend& backend,
193  std::index_sequence<I...>) const {
194  (...,
195  _write_element(
196  errors, I, std::get<I>(values), backend, std::get<I>(_serializers)));
197  }
198 
199  template <typename Elem, typename Backend, typename Serializer>
200  static void _write_element(
201  serialization_errors& errors,
202  std::size_t index,
203  Elem& elem,
204  Backend& backend,
205  Serializer& serial) {
206  if(EAGINE_LIKELY(!errors)) {
207  errors |= backend.begin_element(span_size(index));
208  if(EAGINE_LIKELY(!errors)) {
209  errors |= serial.write(elem, backend);
210  errors |= backend.finish_element(span_size(index));
211  }
212  }
213  }
214 
215  std::tuple<serializer<T>...> _serializers{};
216 };
217 //------------------------------------------------------------------------------
218 template <typename... T>
219 struct serializer<std::tuple<std::pair<string_view, T>...>>
220  : common_serializer<std::tuple<std::pair<string_view, T>...>> {
221 
222  template <typename Backend>
223  auto write(
224  const std::tuple<std::pair<string_view, T>...>& members,
225  Backend& backend) {
226  serialization_errors errors{};
227  errors |= backend.begin_struct(span_size(sizeof...(T)));
228  if(EAGINE_LIKELY(!errors)) {
229  _write_members(
230  errors,
231  members,
232  backend,
233  std::make_index_sequence<sizeof...(T)>());
234  errors |= backend.finish_struct();
235  }
236  return errors;
237  }
238 
239 private:
240  template <typename Tuple, typename Backend, std::size_t... I>
241  void _write_members(
242  serialization_errors& errors,
243  Tuple& members,
244  Backend& backend,
245  std::index_sequence<I...>) {
246  (...,
247  _write_member(
248  errors,
249  std::get<0>(std::get<I>(members)),
250  std::get<1>(std::get<I>(members)),
251  backend,
252  std::get<I>(_serializers)));
253  }
254 
255  template <typename Memb, typename Backend, typename Serializer>
256  static void _write_member(
257  serialization_errors& errors,
258  string_view name,
259  Memb& value,
260  Backend& backend,
261  Serializer& serial) {
262  if(EAGINE_LIKELY(!errors)) {
263  errors |= backend.begin_member(name);
264  if(EAGINE_LIKELY(!errors)) {
265  errors |= serial.write(value, backend);
266  errors |= backend.finish_member(name);
267  }
268  }
269  }
270 
271  std::tuple<serializer<T>...> _serializers{};
272 };
273 //------------------------------------------------------------------------------
274 template <typename Bit>
275 struct serializer<bitfield<Bit>> : common_serializer<bitfield<Bit>> {
276 
277  template <typename Backend>
278  auto write(bitfield<Bit> value, Backend& backend) const {
279  return _serializer.write(value.bits(), backend);
280  }
281 
282 private:
284 };
285 //------------------------------------------------------------------------------
286 template <std::size_t N>
287 struct serializer<char[N]> : serializer<string_view> {};
288 //------------------------------------------------------------------------------
289 template <typename Char, typename Traits, typename Alloc>
290 struct serializer<std::basic_string<Char, Traits, Alloc>>
291  : common_serializer<std::basic_string<Char, Traits, Alloc>> {
292 
293  using common_serializer<std::basic_string<Char, Traits, Alloc>>::write;
294 
295  template <typename Backend>
296  auto write(
297  const std::basic_string<Char, Traits, Alloc>& value,
298  Backend& backend) {
299  return _serializer.write(value, backend);
300  }
301 
302 private:
303  serializer<string_view> _serializer{};
304 };
305 //------------------------------------------------------------------------------
306 template <typename T>
307 struct serializer<span<const T>> : common_serializer<span<const T>> {
308 
309  using common_serializer<span<const T>>::write;
310 
311  template <typename Backend>
312  auto write(span<const T> values, Backend& backend) {
313  serialization_errors errors{};
314  errors |= backend.begin_list(values.size());
315  if(EAGINE_LIKELY(!errors)) {
316  errors |= _elem_serializer.write(values, backend);
317  errors |= backend.finish_list();
318  }
319  return errors;
320  }
321 
322 private:
323  serializer<T> _elem_serializer{};
324 };
325 //------------------------------------------------------------------------------
326 template <typename T>
327 struct serializer<span<T>> : serializer<span<const T>> {};
328 //------------------------------------------------------------------------------
329 template <typename T>
330 struct serializer<fragment_serialize_wrapper<span<const T>>>
331  : common_serializer<fragment_serialize_wrapper<span<const T>>> {
332 
333  using common_serializer<fragment_serialize_wrapper<span<const T>>>::write;
334 
335  template <typename Backend>
336  auto
337  write(fragment_serialize_wrapper<span<const T>>& frag, Backend& backend) {
338  serialization_errors errors{};
339  errors |= _size_serializer.write(frag.offset(), backend);
340  if(EAGINE_LIKELY(!errors)) {
341  auto todo = frag.remaining();
342  errors |= _size_serializer.write(todo.size(), backend);
343  if(EAGINE_LIKELY(!errors)) {
344  span_size_t written{0};
345  errors |= backend.write(todo, written);
346  if(EAGINE_LIKELY(errors.has_at_most(
348  frag.advance(written);
349  }
350  }
351  }
352  return errors;
353  }
354 
355  serializer<span_size_t> _size_serializer{};
356 };
357 //------------------------------------------------------------------------------
358 template <typename T, std::size_t N>
359 struct serializer<std::array<T, N>> : common_serializer<std::array<T, N>> {
360 
361  using common_serializer<std::array<T, N>>::write;
362 
363  template <typename Backend>
364  auto write(const std::array<T, N>& values, Backend& backend) const {
365  serialization_errors errors{};
366  errors |= backend.begin_list(span_size(N));
367  if(EAGINE_LIKELY(!errors)) {
368  errors |= _elem_serializer.write(view(values), backend);
369  errors |= backend.finish_list();
370  }
371  return errors;
372  }
373 
374 private:
375  serializer<T> _elem_serializer{};
376 };
377 //------------------------------------------------------------------------------
378 template <typename T, typename A>
379 struct serializer<std::vector<T, A>> : common_serializer<std::vector<T, A>> {
380 
381  using common_serializer<std::vector<T, A>>::write;
382 
383  template <typename Backend>
384  auto write(const std::vector<T, A>& values, Backend& backend) {
385  serialization_errors errors{};
386  errors |= backend.begin_list(values.size());
387  if(EAGINE_LIKELY(!errors)) {
388  errors |= _elem_serializer.write(view(values), backend);
389  errors |= backend.finish_list();
390  }
391  return errors;
392  }
393 
394 private:
395  serializer<T> _elem_serializer{};
396 };
397 //------------------------------------------------------------------------------
398 template <typename Rep>
399 struct serializer<std::chrono::duration<Rep>>
400  : common_serializer<std::chrono::duration<Rep>> {
401 
402  template <typename Backend>
403  auto write(std::chrono::duration<Rep> value, Backend& backend) {
404  return _serializer.write(value.count(), backend);
405  }
406 
407 private:
408  serializer<Rep> _serializer{};
409 };
410 //------------------------------------------------------------------------------
411 template <typename T, typename P>
412 struct serializer<valid_if<T, P>> : common_serializer<valid_if<T, P>> {
413 
414  template <typename Backend>
415  auto write(const valid_if<T, P>& value, Backend& backend) {
416  serialization_errors errors{};
417  const bool is_valid = value.is_valid();
418  errors |= backend.begin_list(is_valid ? 1 : 0);
419  if(EAGINE_LIKELY(!errors)) {
420  if(is_valid) {
421  errors |= _serializer.write(value.value_anyway(), backend);
422  }
423  errors |= backend.finish_list();
424  }
425  return errors;
426  }
427 
428 private:
429  serializer<T> _serializer{};
430 };
431 //------------------------------------------------------------------------------
432 template <typename T>
433 struct enum_serializer {
434  template <typename Backend>
435  auto write(T enumerator, Backend& backend) const {
436  serialization_errors errors{};
437  if(backend.enum_as_string()) {
438  errors |=
439  _name_serializer.write(enumerator_name(enumerator), backend);
440  } else {
441  errors |=
442  _value_serializer.write(enumerator_value(enumerator), backend);
443  }
444  return errors;
445  }
446 
447 private:
448  serializer<std::underlying_type_t<T>> _value_serializer{};
449  serializer<decl_name> _name_serializer{};
450 };
451 //------------------------------------------------------------------------------
452 template <typename T>
453 struct struct_serializer {
454 public:
455  template <typename Backend>
456  auto write(const T& instance, Backend& backend) {
457  auto member_map = map_data_members(instance);
458  return _serializer.write(member_map, backend);
459  }
460 
461 private:
462  serializer<decltype(map_data_members(std::declval<T>()))> _serializer{};
463 };
464 //------------------------------------------------------------------------------
465 template <typename T>
466 struct serializer
467  : std::conditional_t<
468  has_enumerator_mapping_v<T>,
469  enum_serializer<T>,
470  std::conditional_t<
471  has_data_member_mapping_v<T>,
472  struct_serializer<T>,
473  nothing_t>> {};
474 //------------------------------------------------------------------------------
479 template <typename T, typename Backend>
480 auto serialize(T& value, Backend& backend) -> std::enable_if_t<
481  std::is_base_of_v<serializer_backend, Backend>,
483  serialization_errors errors{};
484  errors |= backend.begin();
485  if(EAGINE_LIKELY(!errors)) {
486  serializer<std::remove_cv_t<T>> writer;
487  errors |= writer.write(value, backend);
488  errors |= backend.finish();
489  }
490  errors |= extract(backend.sink()).finalize();
491  return errors;
492 }
493 //------------------------------------------------------------------------------
494 } // namespace eagine
495 
496 #endif // EAGINE_SERIALIZE_WRITE_HPP
value_type
Value tree value element data type enumeration.
Definition: interface.hpp:27
std::ptrdiff_t span_size_t
Signed span size type used by eagine.
Definition: types.hpp:36
basic_string_span< const char > string_view
Alias for const string views.
Definition: string_span.hpp:116
static constexpr auto span_size(T v) noexcept
Converts argument to span size type.
Definition: types.hpp:59
Common code is placed in this namespace.
Definition: eagine.hpp:21
static constexpr auto extract(api_result_value< Result, api_result_validity::never > &) noexcept -> Result &
Overload of extract for api_result_value.
Definition: c_api_wrap.hpp:270
Class for manipulating and testing a group of enumeration-based bits.
Definition: bitfield.hpp:19
static constexpr auto view(T *addr, S size) noexcept -> const_span< T >
Creates a view starting at the specified pointer and specified length.
Definition: span.hpp:458
basic_span< T, T *, S > span
Default alias for basic memory spans with native pointer type.
Definition: span.hpp:415
static constexpr auto skip(basic_span< T, P, S > s, L l) noexcept -> basic_span< T, P, S >
Skips a specified count of elements from the front of a span.
Definition: span_algo.hpp:60
auto serialize(T &value, Backend &backend) -> std::enable_if_t< std::is_base_of_v< serializer_backend, Backend >, serialization_errors >
Serializes a value with the specified serialization backend.
Definition: write.hpp:480
@ incomplete_write
Incomplete write, remaining data should be written later.
@ too_much_data
Too much data to fit into serialization data sink.
bitfield< serialization_error_code > serialization_errors
Alias for serialization error bitfield.
Definition: result.hpp:100
basic_identifier< 10, 6, default_identifier_char_set, identifier_t > identifier
Default identifier type used throughout the project.
Definition: identifier.hpp:346

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).