CppSerdes  1.0
A serialization/deserialization library designed with embedded systems in mind
serdes.h
Go to the documentation of this file.
1 #ifndef _SERDES_H_
9 #define _SERDES_H_
10 
11 #include <functional>
12 #include <cstring>
13 #include "bitcpy.h"
14 #include "bitliterals.h"
15 #include "serdes_errors.h"
16 #include "serdes_formatter.h"
18 #include "serdes_fwd_declarations.h"
19 
21 namespace serdes
22 {
24  struct packet
25  {
27  size_t bit_offset;
30  const size_t bit_capacity;
31 
33  inline void reset() noexcept
34  {
35  status = status_e::NO_ERROR;
36  bit_offset = 0;
37  }
38 
45  template <typename T_pointer, typename std::enable_if<std::is_pointer<T_pointer>::value, int *>::type = nullptr>
46  packet(T_pointer array_init, size_t max_elements = ~size_t(0), size_t b_offset = 0, mode_e m = mode_e::UNSPECIFIED)
47  : buffer{array_init, max_elements},
48  bit_offset{b_offset},
49  mode{m},
50  bit_capacity{buffer.bit_capacity()} {}
51 
58  template <typename T_array, size_t N>
59  packet(T_array (&array_init)[N], size_t max_elements = ~size_t(0), size_t b_offset = 0, mode_e m = mode_e::UNSPECIFIED)
60  : buffer{array_init, max_elements < N ? max_elements : N},
61  bit_offset{b_offset},
62  mode{m},
63  bit_capacity{buffer.bit_capacity()} {}
64 
70  template <typename T_sized_pointer, typename std::enable_if<serdes::detail::is_sized_pointer<T_sized_pointer>::value, int *>::type = nullptr>
71  packet(T_sized_pointer array_init, size_t b_offset = 0, mode_e m = mode_e::UNSPECIFIED)
72  : buffer{array_init.value, array_init.size},
73  bit_offset{b_offset},
74  mode{m},
75  bit_capacity{buffer.bit_capacity()} {}
76 
79  void pad(const size_t bits)
80  {
81  if (status == status_e::NO_ERROR)
82  pad_assuming_no_prior_errors(bits);
83  }
84 
87  void align(size_t bits)
88  {
89  if (status == status_e::NO_ERROR)
90  align_assuming_no_prior_errors(bits);
91  }
92 
93  //
94  // LOAD SECTION (load from serial = deserialize)
95  //
96 
102  template <typename T, size_t N>
103  void load(T (&value)[N], size_t bits = detail::default_bitsize<T>::value)
104  {
105  constexpr size_t size = N;
106  array<T, size_t> temp_arr(value, size);
107  load(temp_arr, bits);
108  }
109 
114  template <typename T, typename std::enable_if<!detail::is_format_modifier<T>::value, int *>::type = nullptr>
115  void load(T &value, size_t bits = detail::default_bitsize<T>::value)
116  {
117  if (status != status_e::NO_ERROR)
118  return;
119  ensure_load();
120  const size_t bits_touched = bitcpy(value, buffer, bit_offset, bits);
121  bit_offset += bits_touched;
122  if (bits_touched < bits)
124  }
125 
128  template <typename T, typename std::enable_if<std::is_rvalue_reference<T &&>::value && !std::is_base_of<packet_base, T>::value, int *>::type = nullptr>
129  void load(T &&value, size_t bits = detail::default_bitsize<T>::value)
130  {
131  (void)value;
132  (void)bits;
133  if (status != status_e::NO_ERROR)
134  return;
135  ensure_load();
137  }
138 
141  void load(formatter &value)
142  {
143  if (status != status_e::NO_ERROR)
144  return;
145  ensure_load();
146  if (value.formatter_lambda == nullptr)
147  {
149  return;
150  }
151  value.formatter_lambda(*this);
152  }
153 
156  void load(formatter &&value)
157  {
158  load(value);
159  }
160 
165  template <typename T, typename std::enable_if<!detail::is_format_modifier<T>::value, int *>::type = nullptr>
166  void load(delimited_array<T> &value, size_t bits = detail::default_bitsize<T>::value)
167  {
168  if (status != status_e::NO_ERROR)
169  return;
170  ensure_load();
171  constexpr size_t bits_per_element = sizeof(T) * 8;
172 
173  // shortcut for memory aligned situations
174  if (bits == bits_per_element && buffer.element_size == sizeof(T) && bit_offset % bits_per_element == 0)
175  {
176  if (bit_capacity < bits_per_element)
177  {
179  return;
180  }
181  const size_t max_bit_offset_minus_one_element = bit_capacity - bits_per_element;
182  const T *buffer_head = &reinterpret_cast<const T *>(buffer.value)[bit_offset / bits_per_element];
183  for (size_t i = 0; i < value.max_size; i++)
184  {
185  if (bit_offset > max_bit_offset_minus_one_element)
186  {
188  return;
189  }
190  const T &source_value = *buffer_head;
191  value.value[i] = source_value;
192  bit_offset += bits;
193  if (source_value == value.delimiter)
194  return;
195  ++buffer_head;
196  }
197  }
198  else
199  {
200  for (size_t i = 0; i < value.max_size; i++)
201  {
202  const size_t bits_touched = bitcpy(value.value[i], buffer, bit_offset, bits);
203  bit_offset += bits_touched;
204  if (bits_touched < bits)
205  {
207  return;
208  }
209  if (value.value[i] == value.delimiter)
210  return;
211  }
212  }
214  }
215 
219  template <typename T, typename std::enable_if<std::is_base_of<packet_base, T>::value, int *>::type = nullptr>
221  {
222  if (status != status_e::NO_ERROR)
223  return;
224  ensure_load();
225  for (size_t i = 0; i < value.max_size; i++)
226  {
227  value.value[i].format(*this);
228  if (value.value[i] == value.delimiter || status != status_e::NO_ERROR)
229  return;
230  }
232  }
233 
237  template <typename T>
238  void load(delimited_array<T> &&value)
239  {
240  load(value);
241  }
242 
248  template <typename T, typename T2, typename std::enable_if<!detail::is_format_modifier<T>::value, int *>::type = nullptr>
249  void load(array<T, T2> &value, size_t bits = detail::default_bitsize<T>::value)
250  {
251  if (status != status_e::NO_ERROR)
252  return;
253  ensure_load();
254  size_t array_size = static_cast<size_t>(value.size);
255  if (array_size > value.max_size)
256  {
257  array_size = value.max_size;
259  }
260  const size_t total_bits = array_size * sizeof(T) * 8;
261  // shortcut for memory aligned situations
262  if (sizeof(T) == 1 && bits == 8 && buffer.element_size == 1 && (bit_offset & 7u) == 0u && bit_capacity - bit_offset >= total_bits)
263  {
264  memcpy(&value.value[0], &reinterpret_cast<uint8_t *>(buffer.value)[bit_offset >> 3], array_size);
265  bit_offset += total_bits;
266  return;
267  }
268  for (size_t i = 0; i < array_size; i++)
269  {
270  const size_t bits_touched = bitcpy(value.value[i], buffer, bit_offset, bits);
271  bit_offset += bits_touched;
272  if (bits_touched < bits)
273  {
275  return;
276  }
277  }
278  }
279 
284  template <typename T, typename T2, typename std::enable_if<std::is_base_of<packet_base, T>::value, int *>::type = nullptr>
285  void load(array<T, T2> &value)
286  {
287  if (status != status_e::NO_ERROR)
288  return;
289  ensure_load();
290  size_t array_size = static_cast<size_t>(value.size);
291  if (array_size > value.max_size)
292  {
294  return;
295  }
296  for (size_t i = 0; i < array_size; i++)
297  {
298  value.value[i].format(*this);
299  if (status != status_e::NO_ERROR)
300  return;
301  }
302  }
303 
308  template <typename T, typename T2>
309  void load(array<T, T2> &&value)
310  {
311  load(value);
312  }
313 
317  template <typename ST>
318  void load(const serdes::pad<ST> padding)
319  {
320  if (status != status_e::NO_ERROR)
321  return;
322  ensure_load();
323  pad_assuming_no_prior_errors(padding.value);
324  }
325 
329  template <typename ST>
330  void load(const serdes::align<ST> alignment)
331  {
332  if (status != status_e::NO_ERROR)
333  return;
334  ensure_load();
335  align_assuming_no_prior_errors(alignment.value);
336  }
337 
342  template <typename T, typename ST>
343  void load(bitpack<T, ST> &&value)
344  {
345  load(value.value, value.bits);
346  }
347 
352  template <typename T, typename ST>
353  void load(bitpack<T, ST> &value)
354  {
355  load(value.value, value.bits);
356  }
357 
360  void load(packet_base &value)
361  {
362  if (status != status_e::NO_ERROR)
363  return;
364  ensure_load();
365  value.format(*this);
366  }
367 
370  void load(packet_base &&value)
371  {
372  load(value);
373  }
374 
375  //
376  // STORE SECTION (store into serial = serialize)
377  //
378 
383  template <typename T, typename std::enable_if<!detail::is_format_modifier<T>::value, int *>::type = nullptr>
384  void store(const T &value, size_t bits = detail::default_bitsize<T>::value)
385  {
386  if (status != status_e::NO_ERROR)
387  return;
388  ensure_store();
389  const size_t bits_touched = bitcpy(buffer, value, bit_offset, bits);
390  bit_offset += bits_touched;
391  if (bits_touched < bits)
393  }
394 
400  template <typename T, size_t N>
401  void store(const T (&value)[N], size_t bits = detail::default_bitsize<T>::value)
402  {
403  store(array<const T, size_t>(value, N), bits);
404  }
405 
411  template <typename T, size_t N>
412  void store(const T(&&value)[N], size_t bits = detail::default_bitsize<T>::value)
413  {
414  store(array<const T, size_t>(value, N), bits);
415  }
416 
421  template <typename T, typename std::enable_if<!detail::is_format_modifier<T>::value, int *>::type = nullptr>
422  void store(const delimited_array<T> &value, size_t bits = detail::default_bitsize<T>::value)
423  {
424  if (status != status_e::NO_ERROR)
425  return;
426  ensure_store();
427  constexpr size_t bits_per_element = sizeof(T) * 8;
428  // shortcut for memory aligned situations
429  if (bits == bits_per_element && buffer.element_size == sizeof(T) && bit_offset % bits_per_element == 0)
430  {
431  if (bit_capacity < bits_per_element)
432  {
434  return;
435  }
436  const size_t max_bit_offset_minus_one_element = bit_capacity - bits_per_element;
437  T *buffer_head = &reinterpret_cast<T *>(buffer.value)[bit_offset / bits_per_element];
438  for (size_t i = 0; i < value.max_size; i++)
439  {
440  if (bit_offset > max_bit_offset_minus_one_element)
441  {
443  return;
444  }
445  const T &source_value = value.value[i];
446  *buffer_head = source_value;
447  bit_offset += bits;
448  if (source_value == value.delimiter)
449  return;
450  ++buffer_head;
451  }
452  }
453  else
454  {
455  for (size_t i = 0; i < value.max_size; i++)
456  {
457  const size_t bits_touched = bitcpy(buffer, value.value[i], bit_offset, bits);
458  bit_offset += bits_touched;
459  if (bits_touched < bits)
460  {
462  return;
463  }
464  if (value.value[i] == value.delimiter)
465  return;
466  }
467  }
469  }
470 
474  template <typename T, typename std::enable_if<std::is_base_of<packet_base, T>::value, int *>::type = nullptr>
475  void store(const delimited_array<T> &value)
476  {
477  if (status != status_e::NO_ERROR)
478  return;
479  ensure_store();
480  for (size_t i = 0; i < value.max_size; i++)
481  {
482  value.value[i].format(*this);
483  if (value.value[i] == value.delimiter || status != status_e::NO_ERROR)
484  return;
485  }
487  }
488 
492  template <typename T>
493  void store(const delimited_array<T> &&value)
494  {
495  store(value);
496  }
497 
503  template <typename T, typename T2, typename std::enable_if<!detail::is_format_modifier<T>::value, int *>::type = nullptr>
504  void store(const array<T, T2> &value, size_t bits = detail::default_bitsize<T>::value)
505  {
506  if (status != status_e::NO_ERROR)
507  return;
508  ensure_store();
509  size_t array_size = static_cast<size_t>(value.size);
510  if (array_size > value.max_size)
511  {
512  array_size = value.max_size;
514  }
515  const size_t total_bits = array_size * sizeof(T) * 8;
516  // shortcut for memory aligned situations
517  if (sizeof(T) == 1 && bits == 8 && buffer.element_size == 1 && (bit_offset & 7u) == 0u && bit_capacity - bit_offset >= total_bits)
518  {
519  memcpy(&reinterpret_cast<uint8_t *>(buffer.value)[bit_offset >> 3], &value.value[0], array_size);
520  bit_offset += total_bits;
521  return;
522  }
523  for (size_t i = 0; i < array_size; i++)
524  {
525  const size_t bits_touched = bitcpy(buffer, value.value[i], bit_offset, bits);
526  bit_offset += bits_touched;
527  if (bits_touched < bits)
528  {
530  return;
531  }
532  }
533  }
534 
539  template <typename T, typename T2, typename std::enable_if<std::is_base_of<packet_base, T>::value, int *>::type = nullptr>
540  void store(const array<T, T2> &value)
541  {
542  if (status != status_e::NO_ERROR)
543  return;
544  ensure_store();
545  size_t array_size = static_cast<size_t>(value.size);
546  if (array_size > value.max_size)
547  {
549  return;
550  }
551  for (size_t i = 0; i < array_size; i++)
552  {
553  value.value[i].format(*this);
554  if (status != status_e::NO_ERROR)
555  return;
556  }
557  }
558 
563  template <typename T, typename T2>
564  void store(const array<T, T2> &&value)
565  {
566  store(value);
567  }
568 
571  void store(const formatter &value)
572  {
573  if (status != status_e::NO_ERROR)
574  return;
575  ensure_store();
576  if (value.formatter_lambda == nullptr)
577  {
579  return;
580  }
581  value.formatter_lambda(*this);
582  }
583 
586  void store(const formatter &&value)
587  {
588  store(value);
589  }
590 
594  template <typename ST>
595  void store(const serdes::pad<ST> padding)
596  {
597  if (status != status_e::NO_ERROR)
598  return;
599  ensure_store();
600  pad_assuming_no_prior_errors(padding.value);
601  }
602 
606  template <typename ST>
607  void store(const serdes::align<ST> alignment)
608  {
609  if (status != status_e::NO_ERROR)
610  return;
611  ensure_store();
612  align(alignment.value);
613  }
614 
619  template <typename T, typename ST>
620  void store(const bitpack<T, ST> &&value)
621  {
622  store(value.value, value.bits);
623  }
624 
629  template <typename T, typename ST>
630  void store(const bitpack<T, ST> &value)
631  {
632  store(value.value, value.bits);
633  }
634 
637  void store(const packet_base &value)
638  {
639  if (status != status_e::NO_ERROR)
640  return;
641  ensure_store();
642  const_cast<packet_base &>(value).format(*this);
643  }
644 
647  void store(const packet_base &&value)
648  {
649  store(value);
650  }
651 
652  //
653  // stream operator SECTION (<< is store, >> is load)
654  //
655 
660  template <typename T>
662  {
663  load(std::forward<T>(x));
664  return *this;
665  }
666 
671  template <typename T>
673  {
674  store(std::forward<T>(x));
675  return *this;
676  }
677 
678  //
679  // add() SECTION (same as "+", either store or load)
680  //
681 
686  template <typename T>
687  void add(T &&x, size_t bits)
688  {
689  if (mode == mode_e::LOADING)
690  load(std::forward<T>(x), bits);
691  else if (mode == mode_e::STORING)
692  store(std::forward<T>(x), bits);
693  }
694 
699  template <typename T, size_t N>
700  void add(T (&x)[N], size_t bits)
701  {
702  if (mode == mode_e::LOADING)
703  for (size_t i = 0; i < N; i++)
704  load(x[i], bits);
705  else if (mode == mode_e::STORING)
706  for (size_t i = 0; i < N; i++)
707  store(x[i], bits);
708  }
709 
713  template <typename T>
714  void add(T &&x)
715  {
716  if (mode == mode_e::LOADING)
717  load(std::forward<T>(x));
718  else if (mode == mode_e::STORING)
719  store(std::forward<T>(x));
720  }
721 
725  template <typename T, size_t N>
726  void add(T (&x)[N])
727  {
728  if (mode == mode_e::LOADING)
729  for (size_t i = 0; i < N; i++)
730  load(x[i]);
731  else if (mode == mode_e::STORING)
732  for (size_t i = 0; i < N; i++)
733  store(x[i]);
734  }
735 
741  template <typename T>
742  void add(T &value, const std::function<bool()> &validation)
743  {
744  if (status != status_e::NO_ERROR)
745  return;
746  if (mode == mode_e::LOADING)
747  load(value);
748  if (!validation())
749  status = status_e::INVALID_FIELD;
750  else if (mode == mode_e::STORING)
751  store(value);
752  }
753 
759  template <typename T>
760  void add(T &&value, std::function<bool()> &&validation)
761  {
762  add(value, validation);
763  }
764 
765  //
766  // "+" steam operator SECTION (same as add(), either store or load)
767  //
768 
769 #if (defined(__GNUC__) && !defined(__clang__))
770 #pragma GCC diagnostic push
771 #pragma GCC diagnostic ignored "-Weffc++"
772 #endif
773  template <typename T>
778  packet &operator+(T &&value)
779  {
780  add(std::forward<T>(value));
781  return *this;
782  }
783 #if (defined(__GNUC__) && !defined(__clang__))
784 #pragma GCC diagnostic pop
785 #endif
786 
787  private:
790  inline void pad_assuming_no_prior_errors(const size_t bits)
791  {
792  const size_t next_bit_offset = bit_offset + bits;
793  if (next_bit_offset > bit_capacity)
794  {
796  return;
797  }
798  bit_offset = next_bit_offset;
799  }
800 
803  inline void align_assuming_no_prior_errors(size_t bits)
804  {
805  const size_t alignment = bit_offset % bits;
806  if (alignment > 0)
807  {
808  const size_t next_bit_offset = bit_offset + bits - alignment;
809  if (next_bit_offset > bit_capacity)
810  {
812  return;
813  }
814  bit_offset = next_bit_offset;
815  }
816  }
817 
819  inline void ensure_load()
820  {
821  if (mode != mode_e::LOADING)
822  {
823  if (mode == mode_e::STORING)
824  reset();
825  mode = mode_e::LOADING;
826  }
827  }
828 
830  inline void ensure_store()
831  {
832  if (mode != mode_e::STORING)
833  {
834  if (mode == mode_e::LOADING)
835  reset();
836  mode = mode_e::STORING;
837  }
838  }
839  };
840 
841  template <typename T_array, size_t N>
842  status_t packet_base::store(T_array (&target_buffer)[N], size_t max_elements, size_t bit_offset)
843  {
844  if (N < max_elements)
845  max_elements = N;
846  packet pkt_obj(serdes::sized_pointer<T_array>(&target_buffer[0], max_elements), bit_offset, mode_e::STORING);
847  format(pkt_obj);
848  return {pkt_obj.status, pkt_obj.bit_offset};
849  }
850 
851  template <typename T_pointer, typename std::enable_if<std::is_pointer<T_pointer>::value, int *>::type>
852  status_t packet_base::store(T_pointer target_buffer, size_t max_elements, size_t bit_offset)
853  {
854  packet pkt_obj(serdes::sized_pointer<typename std::remove_pointer<T_pointer>::type>(target_buffer, max_elements), bit_offset, mode_e::STORING);
855  format(pkt_obj);
856  return {pkt_obj.status, pkt_obj.bit_offset};
857  }
858 
859  template <typename T_sized_pointer, typename std::enable_if<serdes::detail::is_sized_pointer<T_sized_pointer>::value, int *>::type>
860  status_t packet_base::store(T_sized_pointer target_buffer, size_t bit_offset)
861  {
862  packet pkt_obj(target_buffer, bit_offset, mode_e::STORING);
863  format(pkt_obj);
864  return {pkt_obj.status, pkt_obj.bit_offset};
865  }
866  template <typename T_array, size_t N>
867  status_t packet_base::load(const T_array (&source_buffer)[N], size_t max_elements, size_t bit_offset)
868  {
869  if (N < max_elements)
870  max_elements = N;
871  packet pkt_obj(serdes::sized_pointer<const T_array>(&source_buffer[0], N), bit_offset, mode_e::LOADING);
872  format(pkt_obj);
873  return {pkt_obj.status, pkt_obj.bit_offset};
874  }
875  template <typename T_pointer, typename std::enable_if<std::is_pointer<T_pointer>::value, int *>::type>
876  status_t packet_base::load(const T_pointer source_buffer, size_t max_elements, size_t bit_offset)
877  {
878  packet pkt_obj(serdes::sized_pointer<const typename std::remove_pointer<T_pointer>::type>(source_buffer, max_elements), bit_offset, mode_e::LOADING);
879  format(pkt_obj);
880  return {pkt_obj.status, pkt_obj.bit_offset};
881  }
882  template <typename T_sized_pointer, typename std::enable_if<serdes::detail::is_sized_pointer<T_sized_pointer>::value, int *>::type>
883  status_t packet_base::load(const T_sized_pointer target_buffer, size_t bit_offset)
884  {
885  packet pkt_obj(target_buffer, bit_offset, mode_e::LOADING);
886  format(pkt_obj);
887  return {pkt_obj.status, pkt_obj.bit_offset};
888  }
889  template <typename T>
891  {
892  return store(std::forward<T>(value));
893  }
894  template <typename T>
896  {
897  return load(std::forward<T>(value));
898  }
899 }
900 
901 #endif // _SERDES_H_
const size_t bit_capacity
buffer.bit_capacity() value
Definition: serdes.h:30
tried to loading data from a serial buffer into a temperary rvalue (causes the serdes process to abor...
void load(T(&value)[N], size_t bits=detail::default_bitsize< T >::value)
[[deserialize]] loads from serial buffer into the passed array of values
Definition: serdes.h:103
specifies a number of bits to be used to pad (add to) the current bit offset
Definition: serdes_format_modifiers.h:35
const size_t max_size
maximum size of the array (used for bounds checking)
Definition: serdes_format_modifiers.h:139
void store(const formatter &value)
[[serialize]] stores a formatter reference into a serial buffer
Definition: serdes.h:571
not yet configured for storing/loading
packet & operator+(T &&value)
adds a field to the serial format for both serialization and deserialization (same as packet...
Definition: serdes.h:778
void align(size_t bits)
aligns (increases) the bit offset to a multiple of the specified bits
Definition: serdes.h:87
packet & operator>>(T &&x)
[[deserialize]] loads serial data into the passed value (same as load)
Definition: serdes.h:661
mode_e mode
the serdes mode (LOADING, STORING, or UNSPECIFIED)
Definition: serdes.h:28
specifies a number of bits to be used to align the bit offset as a multiple of
Definition: serdes_format_modifiers.h:18
void load(const serdes::pad< ST > padding)
[[deserialize, pad]] applies a padding step to the load process
Definition: serdes.h:318
a fields validation check failed (causes the serdes process to abort)
void reset() noexcept
resets the bit offset to 0 and the status to NO_ERROR
Definition: serdes.h:33
serdes::status_t store(T_array(&target_buffer)[N], size_t max_elements=N, size_t bit_offset=0)
[[serialize]] stores data into the target "sized" serial array according to the format() process ...
status_e
error status of serialization/deserialization process
Definition: serdes_errors.h:14
a serialization/deserialization helper class, with load, store, and stream operators ...
Definition: serdes.h:24
void store(const array< T, T2 > &value)
[[serialize]] stores an array<packet_base, T2> reference into a serial buffer
Definition: serdes.h:540
const ST & value
bit pad reference value
Definition: serdes_format_modifiers.h:38
CppSerdes library namespace.
Definition: bitcpy_common.h:69
void load(bitpack< T, ST > &&value)
[[deserialize]] loads from serial buffer into a bitpack<T, ST> rvalue
Definition: serdes.h:343
void add(T &&x)
adds a referenced field to the serial format for both serialization and deserialization ...
Definition: serdes.h:714
void store(const array< T, T2 > &value, size_t bits=detail::default_bitsize< T >::value)
[[serialize]] stores an array<T1, T2> reference into a serial buffer
Definition: serdes.h:504
void load(array< T, T2 > &value, size_t bits=detail::default_bitsize< T >::value)
[[deserialize]] loads from serial buffer into a array<T1, T2> reference
Definition: serdes.h:249
void store(const delimited_array< T > &value)
[[serialize]] stores a delimited_array<packet_base> reference into a serial buffer ...
Definition: serdes.h:475
a lambda function wrapper that can describe any serialization/deserialization formatting process...
Definition: serdes_formatter.h:32
void add(T &&x, size_t bits)
adds a referenced field to the serial format for both serialization and deserialization ...
Definition: serdes.h:687
void store(const bitpack< T, ST > &&value)
[[serialize]] stores a bitpack<T, ST> rvalue into a serial buffer
Definition: serdes.h:620
void store(const serdes::align< ST > alignment)
[[serialize, align]] applies an alignment step to the store process
Definition: serdes.h:607
void store(const bitpack< T, ST > &value)
[[serialize]] stores a bitpack<T, ST> reference into a serial buffer
Definition: serdes.h:630
void store(const packet_base &value)
[[serialize]] stores a packet_base reference into a serial buffer
Definition: serdes.h:637
inheritable base class to allow format recording and application with no additional memory storage (e...
Definition: serdes_fwd_declarations.h:42
void store(const T &value, size_t bits=detail::default_bitsize< T >::value)
[[serialize]] stores a value reference into a serial buffer
Definition: serdes.h:384
mode_e
the serdes mode of operation
Definition: serdes_errors.h:82
serdes::status_t operator>>(T &&value)
[[serialize]] stores the packet_base object into the passed serial data (same as store) ...
Defines string literals for fixed sized types, useful for serdes definitions. For example: Writting "...
packet & operator<<(T &&x)
[[serialize]] stores the passed value into the serial data (same as store)
Definition: serdes.h:672
during serialization/deserialization the serial array boundary was reached (causes the serdes process...
packet(T_array(&array_init)[N], size_t max_elements=~size_t(0), size_t b_offset=0, mode_e m=mode_e::UNSPECIFIED)
Construct a new packet object from an c style array pointer.
Definition: serdes.h:59
void load(const serdes::align< ST > alignment)
[[deserialize, align]] applies an alignment step to the load process
Definition: serdes.h:330
void add(T &&value, std::function< bool()> &&validation)
adds a referenced field to the serial format for both serialization and deserialization along with a ...
Definition: serdes.h:760
packet(T_pointer array_init, size_t max_elements=~size_t(0), size_t b_offset=0, mode_e m=mode_e::UNSPECIFIED)
Construct a new packet object from an c style array pointer.
Definition: serdes.h:46
void load(formatter &&value)
[[deserialize]] loads from serial buffer into a formatter rvalue
Definition: serdes.h:156
void load(bitpack< T, ST > &value)
[[deserialize]] loads from serial buffer into a bitpack<T, ST> reference
Definition: serdes.h:353
a container for dynamically sized arrays with their ending marked by a reserved delimiter value ...
Definition: serdes_format_modifiers.h:130
serdes::sized_pointer< void > buffer
underlying buffer to serialize/deserialize to/from
Definition: serdes.h:26
the serdes::array object&#39;s size exceeded the maximum size of the array when evaluated (causes the ser...
void load(delimited_array< T > &value)
[[deserialize]] loads from serial buffer into a delimited_array<packet_base> reference ...
Definition: serdes.h:220
void add(T &value, const std::function< bool()> &validation)
adds a referenced field to the serial format for both serialization and deserialization along with a ...
Definition: serdes.h:742
size_t bit_offset
current bit offset in the serdes process
Definition: serdes.h:27
void store(const array< T, T2 > &&value)
[[serialize]] stores an array<T, T2> rvalue into a serial buffer
Definition: serdes.h:564
void load(packet_base &value)
[[deserialize]] loads from serial buffer into a packet_base reference
Definition: serdes.h:360
status returned after any serialization/deserialization process
Definition: serdes_errors.h:72
void load(array< T, T2 > &&value)
[[deserialize]] loads from serial buffer into a array<T, T2> forwarding reference ...
Definition: serdes.h:309
Includes all the bitcpy definitions for serialization and deserialization.
std::function< void(packet &)> formatter_lambda
the formatting function taking a packet process (and any captures) as instructions ...
Definition: serdes_formatter.h:35
const size_t max_size
maximum size of the array (used for bounds checking)
Definition: serdes_format_modifiers.h:96
status_e status
the current error status of the serdes process
Definition: serdes.h:29
void store(const T(&&value)[N], size_t bits=detail::default_bitsize< T >::value)
[[serialize]] stores a raw array rvalue into a serial buffer
Definition: serdes.h:412
a pure_virtual_formatter (a.k.a "serdes::formatter(nullptr)") was used but not overriden (causes the ...
const T & delimiter
reference to a reserved delimiter value marking the end of the array
Definition: serdes_format_modifiers.h:136
packet(T_sized_pointer array_init, size_t b_offset=0, mode_e m=mode_e::UNSPECIFIED)
Construct a new packet object from an sized_pointer array for size safety.
Definition: serdes.h:71
void load(array< T, T2 > &value)
[[deserialize]] loads from serial buffer into a array<packet_base, T2> reference
Definition: serdes.h:285
void load(delimited_array< T > &&value)
[[deserialize]] loads from serial buffer into a delimited_array<T> reference
Definition: serdes.h:238
size_t bit_capacity() const noexcept
returns the number of bits in the array
Definition: bitcpy_sized_pointer.h:76
(serializing) storing variables into serial data
Defines error and status types: status_e, status_t, mode_e, status2str(status_e)
const uint_fast8_t element_size
Number of bytes per element of the original array type, same as sizeof(T_original) ...
Definition: bitcpy_sized_pointer.h:57
T * value
pointer to the head of the array
Definition: serdes_format_modifiers.h:133
const ST & size
a reference to a value that contains the dynamic size of the array
Definition: serdes_format_modifiers.h:93
CONSTEXPR_ABOVE_CPP11 size_t bitcpy(T_val &dest, const T_array *const source, const size_t bit_offset=0, const size_t bits=detail::default_bitsize< T_val >::value) noexcept
[[deserialize, uint destination]] copies the specified number of bits from an array into a value ...
Definition: bitcpy_from_array.h:29
a container for fixed or dynamically sized arrays, with an upper bounds limit for safety ...
Definition: serdes_format_modifiers.h:87
the specified delimiter in a delimited_array object was not found before the end of the array (causes...
void load(delimited_array< T > &value, size_t bits=detail::default_bitsize< T >::value)
[[deserialize]] loads from serial buffer into a delimited_array reference
Definition: serdes.h:166
virtual void format(packet &)=0
override to declare the serdes process used in store() and load()
Defines format modification classes: align, pad, bitpack, array, delimited_array. ...
void store(const T(&value)[N], size_t bits=detail::default_bitsize< T >::value)
[[serialize]] stores a raw array reference into a serial buffer
Definition: serdes.h:401
void store(const formatter &&value)
[[serialize]] stores a formatter rvalue into a serial buffer
Definition: serdes.h:586
void load(formatter &value)
[[deserialize]] loads from serial buffer into a formatter reference
Definition: serdes.h:141
void store(const serdes::pad< ST > padding)
[[serialize, pad]] applies a padding step to the store process
Definition: serdes.h:595
T * value
a pointer to the array head
Definition: serdes_format_modifiers.h:90
no serialization/deserialization errors occurred
serdes::status_t load(const T_array(&source_buffer)[N], size_t max_elements=N, size_t bit_offset=0)
[[deserialize]] loads data from the source "sized" array according to the format() process ...
const ST & value
bit alignment reference value
Definition: serdes_format_modifiers.h:21
defines the serdes::formatter class for recording arbitrary format lambda procedures ...
void store(const packet_base &&value)
[[serialize]] stores a packet_base rvalue into a serial buffer
Definition: serdes.h:647
T & value
a reference to the bitpacked value
Definition: serdes_format_modifiers.h:57
const ST & bits
a reference to the number of bits to use when storing/loading the referenced value ...
Definition: serdes_format_modifiers.h:60
void add(T(&x)[N])
adds an array field to the serial format for both serialization and deserialization ...
Definition: serdes.h:726
serdes::status_t operator<<(T &&value)
[[deserialize]] loads packet_base data into the passed serial data (same as load) ...
void add(T(&x)[N], size_t bits)
adds an array field to the serial format for both serialization and deserialization ...
Definition: serdes.h:700
void *const value
the underlying pointer reinterpreted as a void* type
Definition: bitcpy_sized_pointer.h:51
void pad(const size_t bits)
moves the bit offset head the specified bits
Definition: serdes.h:79
(deserializing) loading from serial data into variables
void store(const delimited_array< T > &&value)
[[serialize]] stores a delimited_array<packet_base> rvalue into a serial buffer
Definition: serdes.h:493
Holds a pointer to an array (with its type information) with a constant size.
Definition: bitcpy_sized_pointer.h:19
void load(T &value, size_t bits=detail::default_bitsize< T >::value)
[[deserialize]] loads from serial buffer into the passed value reference
Definition: serdes.h:115
void load(T &&value, size_t bits=detail::default_bitsize< T >::value)
[[deserialize]] loads from serial buffer into the passed value rvalue NOTE: using this method will ca...
Definition: serdes.h:129
void load(packet_base &&value)
[[deserialize]] loads from serial buffer into a packet_base rvalue
Definition: serdes.h:370
Holds a pointer to a void array (with type information stored as a runtime element size paramenter) w...
Definition: bitcpy_sized_pointer.h:48
void store(const delimited_array< T > &value, size_t bits=detail::default_bitsize< T >::value)
[[serialize]] stores a delimited_array reference into a serial buffer
Definition: serdes.h:422
bitpack a value into an exact number of specified bits. If applied to an array it will be applied to ...
Definition: serdes_format_modifiers.h:54