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 // clang-format off
12 #include <cstring>
13 #include "bitcpy.h"
14 #include "bitliterals.h"
15 #include "serdes_errors.h"
16 #include "serdes_formatter.h"
17 #include "serdes_validator.h"
19 #include "serdes_fwd_declarations.h"
20 #include "serdes_byte_iterator.h"
21 
22 // define configCPP_SERDES_LIB_EXCLUDE_CPP_CRC to skip including "cppcrc.h"
23 // NOTE: cppcrc.h relies on C++14 or greater constexpr support
24 #if !defined(configCPP_SERDES_LIB_EXCLUDE_CPP_CRC) && BITCPY_CONSTEXPR_SUPPORTED
25 #include "cppcrc.h"
26 #endif
27 
28 // if inlining is increasing your binary size too much, you can disable them using configCPP_SERDES_LIB_INLINE_PACKET_API_AGGRESSION=0
29 //
30 // level 0 disables all unnecessary inline statements (functions that aren't templatized still need inline)
31 // level 1 leaves inline on very small or important functions (functions that just wrap bitcpy for example)
32 // level 2 puts inline on pretty much everything
33 #ifndef configCPP_SERDES_LIB_INLINE_PACKET_API_AGGRESSION
34 #define configCPP_SERDES_LIB_INLINE_PACKET_API_AGGRESSION 1
35 #endif
36 #if configCPP_SERDES_LIB_INLINE_PACKET_API_AGGRESSION < 0 || configCPP_SERDES_LIB_INLINE_PACKET_API_AGGRESSION > 2
37 #error "configCPP_SERDES_LIB_INLINE_PACKET_API_AGGRESSION must be 0, 1, or 2"
38 #endif
39 #if configCPP_SERDES_LIB_INLINE_PACKET_API_AGGRESSION == 0
40 #define CPP_SERDES_LIB_PACKET_API_INLINE1
41 #define CPP_SERDES_LIB_PACKET_API_INLINE2
42 #elif configCPP_SERDES_LIB_INLINE_PACKET_API_AGGRESSION == 1
43 #define CPP_SERDES_LIB_PACKET_API_INLINE1 inline
44 #define CPP_SERDES_LIB_PACKET_API_INLINE2
45 #elif configCPP_SERDES_LIB_INLINE_PACKET_API_AGGRESSION == 2
46 #define CPP_SERDES_LIB_PACKET_API_INLINE1 inline
47 #define CPP_SERDES_LIB_PACKET_API_INLINE2 inline
48 #endif
49 
51 namespace serdes
52 {
54  struct packet
55  {
57  size_t bit_offset;
60  const size_t bit_capacity;
61 
63  inline void reset() noexcept
64  {
66  bit_offset = 0;
67  }
68 
75  template <typename T_pointer, typename std::enable_if<std::is_pointer<T_pointer>::value, int *>::type = nullptr>
76  packet(T_pointer array_init, size_t max_elements = ~size_t(0), size_t b_offset = 0, mode_e m = mode_e::UNSPECIFIED)
77  : buffer{array_init, max_elements},
78  bit_offset{b_offset},
79  mode{m},
81 
88  template <typename T_array, size_t N>
89  packet(T_array (&array_init)[N], size_t max_elements = ~size_t(0), size_t b_offset = 0, mode_e m = mode_e::UNSPECIFIED)
90  : buffer{array_init, max_elements < N ? max_elements : N},
91  bit_offset{b_offset},
92  mode{m},
94 
100  template <typename T_sized_pointer, typename std::enable_if<serdes::detail::is_sized_pointer<T_sized_pointer>::value, int *>::type = nullptr>
101  packet(T_sized_pointer array_init, size_t b_offset = 0, mode_e m = mode_e::UNSPECIFIED)
102  : buffer(array_init),
103  bit_offset{b_offset},
104  mode{m},
106 
114  template <typename T_array, detail::requires_data_and_size<T_array>* = nullptr>
115  packet(T_array &array_init, size_t max_elements = ~size_t(0), size_t b_offset = 0, mode_e m = mode_e::UNSPECIFIED)
116  : buffer{array_init.data(), max_elements < array_init.size() ? max_elements : array_init.size()},
117  bit_offset{b_offset},
118  mode{m},
120 
123  inline void pad(const size_t bits) noexcept
124  {
125  if (status == status_e::NO_ERROR)
126  pad_assuming_no_prior_errors(bits);
127  }
128 
131  inline void align(size_t bits) noexcept
132  {
133  if (status == status_e::NO_ERROR)
134  align_assuming_no_prior_errors(bits);
135  }
136 
137  //
138  // LOAD SECTION (load from serial = deserialize)
139  //
140 
146  template <typename T, size_t N>
147  CPP_SERDES_LIB_PACKET_API_INLINE1 void load(T (&value)[N], size_t bits = detail::default_bitsize<T>::value)
148  {
149  array<T, size_t> temp_arr(value, N);
150  load(temp_arr, bits);
151  }
152 
158  template <typename T, typename std::enable_if<
159  detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::value &&
160  !detail::has_custom_type_override<typename detail::remove_cvref_cpp11<T>::type>::value
161  , int *>::type = nullptr>
162  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(T &&value, size_t bits = detail::default_bitsize<typename detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::elem_type>::value)
163  {
164  if (status != status_e::NO_ERROR)
165  return;
166  size_t size = value.size();
167  if (size == 0u) // no space to load
168  {
169  if (bits > 0u)
171  return;
172  }
173  using elem_type = typename detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::elem_type;
174  array<elem_type, size_t> temp_arr(&value.data()[0], size, size);
175  load(temp_arr, bits);
176  }
177 
182  template <typename T, typename std::enable_if<
183  !detail::is_format_modifier<typename detail::remove_cvref_cpp11<T>::type>::value &&
184  detail::supported_by_bitcpy<typename detail::remove_cvref_cpp11<T>::type>::value,
185  int *>::type = nullptr>
186  CPP_SERDES_LIB_PACKET_API_INLINE1 void load(T &value, size_t bits = detail::default_bitsize<T>::value)
187  {
188  if (status != status_e::NO_ERROR)
189  return;
190  ensure_load();
191  const size_t bits_touched = bitcpy(value, buffer, bit_offset, bits);
192  bit_offset += bits_touched;
193  if (bits_touched < bits)
195  }
196 
203  template <typename T, typename std::enable_if<
204  detail::has_custom_type_with_bit_support<typename detail::remove_cvref_cpp11<T>::type>::value
205  && (
206  // and has an override
207  detail::has_custom_type_override<typename detail::remove_cvref_cpp11<T>::type>::value ||
208  // or, not already supported by another overload
209  (
210  !detail::is_format_modifier<typename detail::remove_cvref_cpp11<T>::type>::value &&
211  !detail::supported_by_bitcpy<typename detail::remove_cvref_cpp11<T>::type>::value &&
212  !std::is_array<typename detail::remove_cvref_cpp11<T>::type>::value &&
213  !detail::has_load_and_store<typename detail::remove_cvref_cpp11<T>::type>::value &&
214  !detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::value
215  )
216  ), int *>::type = nullptr>
217  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(T &&value, size_t bits = custom_type<typename detail::remove_cvref_cpp11<T>::type>::default_bits)
218  {
219  if (status != status_e::NO_ERROR)
220  return;
221  ensure_load();
222  custom_type<typename detail::remove_cvref_cpp11<T>::type>::format(*this, std::forward<T>(value), bits);
223  }
224 
230  template <typename T, typename std::enable_if<
231  detail::has_custom_type_without_bit_support<typename detail::remove_cvref_cpp11<T>::type>::value
232  && (
233  // and has an override
234  detail::has_custom_type_override<typename detail::remove_cvref_cpp11<T>::type>::value ||
235  // or, not already supported by another overload
236  (
237  !detail::is_format_modifier<typename detail::remove_cvref_cpp11<T>::type>::value &&
238  !detail::supported_by_bitcpy<typename detail::remove_cvref_cpp11<T>::type>::value &&
239  !std::is_array<typename detail::remove_cvref_cpp11<T>::type>::value &&
240  !detail::has_load_and_store<typename detail::remove_cvref_cpp11<T>::type>::value &&
241  !detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::value
242  )
243  ), int *>::type = nullptr>
244  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(T &&value)
245  {
246  if (status != status_e::NO_ERROR)
247  return;
248  ensure_load();
249  custom_type<typename detail::remove_cvref_cpp11<T>::type>::format(*this, std::forward<T>(value));
250  }
251 
256  template <typename T, typename std::enable_if<detail::has_format_method<T>::value, int *>::type = nullptr>
257  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(T &&value)
258  {
259  if (status != status_e::NO_ERROR)
260  return;
261  ensure_load();
262  std::forward<T>(value).format(*this);
263  }
264 
269  template <typename T, typename std::enable_if<detail::has_load_and_store<typename detail::remove_cvref_cpp11<T>::type>::value, int *>::type = nullptr>
270  CPP_SERDES_LIB_PACKET_API_INLINE1 void load(T &&value)
271  {
272  if (status != status_e::NO_ERROR)
273  return;
274  ensure_load();
275  typename detail::get_inner_wrapped_type<typename detail::remove_cvref_cpp11<T>::type>::type temp_value{};
276  load(temp_value);
277  if (status != status_e::NO_ERROR)
278  value.store(temp_value);
279  }
280 
283  template <typename T, typename std::enable_if<
284  std::is_rvalue_reference<T &&>::value
285  // don't set this NO_LOAD_TO_RVALUE warning for any complex types whose rvalue
286  // could wrap a valid lvalue variable such as "packet >> serdes::array(data);"
287  && detail::supported_by_bitcpy<T>::value,
288  int *>::type = nullptr>
289  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(T &&value, size_t bits = detail::default_bitsize<T>::value)
290  {
291  (void)value;
292  (void)bits;
293  if (status != status_e::NO_ERROR)
294  return;
295  ensure_load();
297  }
298 
301  template<typename T, typename std::enable_if<
302  detail::is_formatter<typename detail::remove_cvref_cpp11<T>::type>::value,
303  int *>::type* = nullptr>
304  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(T &&value)
305  {
306  if (status != status_e::NO_ERROR)
307  return;
308  ensure_load();
309  if (value.formatter_lambda == nullptr)
310  {
312  return;
313  }
314  value.formatter_lambda(*this);
315  }
316 
321  template <typename T, typename std::enable_if<!detail::is_format_modifier<typename delimited_array<T>::elem_type>::value, int *>::type = nullptr>
322  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(delimited_array<T> &value, size_t bits = detail::default_bitsize<typename delimited_array<T>::elem_type>::value)
323  {
324  if (status != status_e::NO_ERROR)
325  return;
326  ensure_load();
327  using elem_type = typename delimited_array<T>::elem_type;
328  constexpr size_t bits_per_element = sizeof(elem_type) * 8;
329 
330  // shortcut for memory aligned situations
331  if (bits == bits_per_element && buffer.element_size == sizeof(elem_type) && bit_offset % bits_per_element == 0)
332  {
333  if (bit_capacity < bits_per_element)
334  {
336  return;
337  }
338  const size_t max_bit_offset_minus_one_element = bit_capacity - bits_per_element;
339  const elem_type *buffer_head = &reinterpret_cast<const elem_type *>(buffer.value)[bit_offset / bits_per_element];
340  for (size_t i = 0; i < value.max_size; i++)
341  {
342  if (bit_offset > max_bit_offset_minus_one_element)
343  {
345  return;
346  }
347  const elem_type &source_value = *buffer_head;
348  value.value[i] = source_value;
349  bit_offset += bits;
350  if (source_value == value.delimiter)
351  return;
352  ++buffer_head;
353  }
354  }
355  else
356  {
357  for (size_t i = 0; i < value.max_size; i++)
358  {
359  const size_t bits_touched = bitcpy(value.value[i], buffer, bit_offset, bits);
360  bit_offset += bits_touched;
361  if (bits_touched < bits)
362  {
364  return;
365  }
366  if (value.value[i] == value.delimiter)
367  return;
368  }
369  }
371  }
372 
377  template <typename T, typename std::enable_if<detail::has_format_method<typename delimited_array<T>::elem_type>::value, int *>::type = nullptr>
378  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(delimited_array<T> &value)
379  {
380  if (status != status_e::NO_ERROR)
381  return;
382  ensure_load();
383  for (size_t i = 0; i < value.max_size; i++)
384  {
385  value.value[i].format(*this);
386  if (value.value[i] == value.delimiter || status != status_e::NO_ERROR)
387  return;
388  }
390  }
391 
395  template <typename T>
396  CPP_SERDES_LIB_PACKET_API_INLINE1 void load(delimited_array<T> &&value)
397  {
398  load(value);
399  }
400 
406  template <typename T, typename T2, typename std::enable_if<
407  !detail::is_format_modifier<typename serdes::array<T, T2>::elem_type>::value &&
408  detail::supported_by_bitcpy<typename serdes::array<T, T2>::elem_type>::value
409  , int *>::type = nullptr>
410  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(serdes::array<T, T2> &value, size_t bits = detail::default_bitsize<typename serdes::array<T, T2>::elem_type>::value)
411  {
412  if (status != status_e::NO_ERROR)
413  return;
414  ensure_load();
415 
416  // here the "size" reference is finally copied, in case it changed after the reference bind occurred
417  size_t array_size = static_cast<size_t>(value.size);
418  if (array_size > value.max_size)
419  {
420  array_size = value.max_size;
422  }
423  const size_t total_bits = array_size * sizeof(typename serdes::array<T, T2>::elem_type) * 8;
424  // shortcut for memory aligned situations
425  if (sizeof(typename serdes::array<T, T2>::elem_type) == 1 && bits == 8 && buffer.element_size == 1 && (bit_offset & 7u) == 0u && bit_capacity - bit_offset >= total_bits)
426  {
427  std::memcpy(&value.value[0], &reinterpret_cast<uint8_t *>(buffer.value)[bit_offset >> 3], array_size);
428  bit_offset += total_bits;
429  return;
430  }
431  for (size_t i = 0; i < array_size; i++)
432  {
433  const size_t bits_touched = bitcpy(value.value[i], buffer, bit_offset, bits);
434  bit_offset += bits_touched;
435  if (bits_touched < bits)
436  {
438  return;
439  }
440  }
441  }
442 
448  template <typename T, typename T2, typename std::enable_if<
449  !detail::is_format_modifier<typename serdes::array<T, T2>::elem_type>::value &&
450  !detail::supported_by_bitcpy<typename serdes::array<T, T2>::elem_type>::value
451  , int *>::type = nullptr>
452  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(serdes::array<T, T2> &value, size_t bits = detail::default_bitsize<typename serdes::array<T, T2>::elem_type>::value)
453  {
454  if (status != status_e::NO_ERROR)
455  return;
456  ensure_load();
457 
458  // here the "size" reference is finally copied, in case it changed after the reference bind occurred
459  size_t array_size = static_cast<size_t>(value.size);
460  if (array_size > value.max_size)
461  {
462  array_size = value.max_size;
464  }
465  for (size_t i = 0; i < array_size && status != status_e::NO_ERROR; i++)
466  load(value.value[i], bits);
467  }
468 
473  template <typename T, typename T2, typename std::enable_if<detail::has_format_method<typename serdes::array<T, T2>::elem_type>::value, int *>::type = nullptr>
474  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(serdes::array<T, T2> &value)
475  {
476  if (status != status_e::NO_ERROR)
477  return;
478  ensure_load();
479 
480  // here the "size" reference is finally copied, in case it changed after the reference bind occurred
481  size_t array_size = static_cast<size_t>(value.size);
482  if (array_size > value.max_size)
483  {
485  return;
486  }
487  for (size_t i = 0; i < array_size; i++)
488  {
489  value.value[i].format(*this);
490  if (status != status_e::NO_ERROR)
491  return;
492  }
493  }
494 
499  template <typename T, typename T2>
500  CPP_SERDES_LIB_PACKET_API_INLINE1 void load(serdes::array<T, T2> &&value)
501  {
502  load(value);
503  }
504 
508  template <typename ST>
509  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(const serdes::pad<ST> padding)
510  {
511  if (status != status_e::NO_ERROR)
512  return;
513  ensure_load();
514  pad_assuming_no_prior_errors(padding.value);
515  }
516 
520  template <typename ST>
521  CPP_SERDES_LIB_PACKET_API_INLINE2 void load(const serdes::align<ST> alignment)
522  {
523  if (status != status_e::NO_ERROR)
524  return;
525  ensure_load();
526  align_assuming_no_prior_errors(alignment.value);
527  }
528 
533  template <typename T, typename ST>
534  CPP_SERDES_LIB_PACKET_API_INLINE1 void load(bitpack<T, ST> &&value)
535  {
536  load(value.value, value.bits);
537  }
538 
543  template <typename T, typename ST>
544  CPP_SERDES_LIB_PACKET_API_INLINE1 void load(bitpack<T, ST> &value)
545  {
546  load(value.value, value.bits);
547  }
548 
551  inline void load(packet_base &value)
552  {
553  if (status != status_e::NO_ERROR)
554  return;
555  ensure_load();
556  value.format(*this);
557  }
558 
561  inline void load(packet_base &&value)
562  {
563  load(value);
564  }
565 
566  //
567  // STORE SECTION (store into serial = serialize)
568  //
569 
574  template <typename T, typename std::enable_if<
575  !detail::is_format_modifier<typename detail::remove_cvref_cpp11<T>::type>::value &&
576  detail::supported_by_bitcpy<typename detail::remove_cvref_cpp11<T>::type>::value,
577  int *>::type = nullptr>
578  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(const T &value, size_t bits = detail::default_bitsize<T>::value)
579  {
580  if (status != status_e::NO_ERROR)
581  return;
582  ensure_store();
583  const size_t bits_touched = bitcpy(buffer, value, bit_offset, bits);
584  bit_offset += bits_touched;
585  if (bits_touched < bits)
587  }
588 
595  template <typename T, typename std::enable_if<
596  detail::has_custom_type_with_bit_support<typename detail::remove_cvref_cpp11<T>::type>::value
597  &&
598  (
599  // and has an override
600  detail::has_custom_type_override<typename detail::remove_cvref_cpp11<T>::type>::value ||
601  // or, not already supported by another overload
602  (
603  !detail::is_format_modifier<typename detail::remove_cvref_cpp11<T>::type>::value &&
604  !detail::supported_by_bitcpy<typename detail::remove_cvref_cpp11<T>::type>::value &&
605  !std::is_array<typename detail::remove_cvref_cpp11<T>::type>::value &&
606  !detail::has_load_and_store<typename detail::remove_cvref_cpp11<T>::type>::value &&
607  !detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::value
608  )
609  ), int *>::type = nullptr>
610  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(T &&value, size_t bits = custom_type<typename detail::remove_cvref_cpp11<T>::type>::default_bits)
611  {
612  if (status != status_e::NO_ERROR)
613  return;
614  ensure_store();
615  custom_type<typename detail::remove_cvref_cpp11<T>::type>::format(*this, std::forward<T>(value), bits);
616  }
617 
622  template <typename T, typename std::enable_if<
623  detail::has_custom_type_without_bit_support<typename detail::remove_cvref_cpp11<T>::type>::value
624  &&
625  (
626  // and has an override
627  detail::has_custom_type_override<typename detail::remove_cvref_cpp11<T>::type>::value ||
628  // or, not already supported by another overload
629  (
630  !detail::is_format_modifier<typename detail::remove_cvref_cpp11<T>::type>::value &&
631  !detail::supported_by_bitcpy<typename detail::remove_cvref_cpp11<T>::type>::value &&
632  !std::is_array<typename detail::remove_cvref_cpp11<T>::type>::value &&
633  !detail::has_load_and_store<typename detail::remove_cvref_cpp11<T>::type>::value &&
634  !detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::value
635  )
636  ), int *>::type = nullptr>
637  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(T &&value)
638  {
639  if (status != status_e::NO_ERROR)
640  return;
641  ensure_store();
642  custom_type<typename detail::remove_cvref_cpp11<T>::type>::format(*this, std::forward<T>(value));
643  }
644 
648  template <typename T, typename std::enable_if<detail::has_format_method<T>::value, int *>::type = nullptr>
649  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(T &&value)
650  {
651  if (status != status_e::NO_ERROR)
652  return;
653  ensure_store();
654  std::forward<T>(value).format(*this);
655  }
656 
660  template <typename T, typename std::enable_if<detail::has_load_and_store<
661  typename detail::remove_cvref_cpp11<T>::type>::value, int *>::type = nullptr>
662  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(T &&value)
663  {
664  if (status != status_e::NO_ERROR)
665  return;
666  ensure_store();
667  store(value.load());
668  }
669 
675  template <typename T, size_t N>
676  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(const T (&value)[N], size_t bits = detail::default_bitsize<T>::value)
677  {
678  store(array<const T, size_t>(value, N), bits);
679  }
680 
686  template <typename T, typename std::enable_if<
687  detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::value &&
688  !detail::has_custom_type_override<typename detail::remove_cvref_cpp11<T>::type>::value
689  , int *>::type = nullptr>
690  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(T &&value, size_t bits = detail::default_bitsize<typename detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::elem_type>::value)
691  {
692  size_t size = value.size();
693  if (size == 0u)
694  return; // nothing to store
695  using elem_type = typename detail::has_data_and_size<typename detail::remove_cvref_cpp11<T>::type>::elem_type;
696  array<elem_type, size_t> temp_arr(&value.data()[0], size, size);
697  store(temp_arr, bits);
698  }
699 
705  template <typename T, size_t N>
706  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(const T (&&value)[N], size_t bits = detail::default_bitsize<T>::value)
707  {
708  store(array<const T, size_t>(value, N), bits);
709  }
710 
715  template <typename T, typename std::enable_if<!detail::is_format_modifier<typename delimited_array<T>::elem_type>::value, int *>::type = nullptr>
716  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(const delimited_array<T> &value, size_t bits = detail::default_bitsize<typename delimited_array<T>::elem_type>::value)
717  {
718  if (status != status_e::NO_ERROR)
719  return;
720  ensure_store();
721  using elem_type = typename detail::remove_cvref_cpp11<typename delimited_array<T>::elem_type>::type;
722  constexpr size_t bits_per_element = sizeof(elem_type) * 8;
723  // shortcut for memory aligned situations
724  if (bits == bits_per_element && buffer.element_size == sizeof(elem_type) && bit_offset % bits_per_element == 0)
725  {
726  if (bit_capacity < bits_per_element)
727  {
729  return;
730  }
731  const size_t max_bit_offset_minus_one_element = bit_capacity - bits_per_element;
732  elem_type *buffer_head = &reinterpret_cast<elem_type *>(buffer.value)[bit_offset / bits_per_element];
733  for (size_t i = 0; i < value.max_size; i++)
734  {
735  if (bit_offset > max_bit_offset_minus_one_element)
736  {
738  return;
739  }
740  const elem_type &source_value = value.value[i];
741  *buffer_head = source_value;
742  bit_offset += bits;
743  if (source_value == value.delimiter)
744  return;
745  ++buffer_head;
746  }
747  }
748  else
749  {
750  for (size_t i = 0; i < value.max_size; i++)
751  {
752  const size_t bits_touched = bitcpy(buffer, value.value[i], bit_offset, bits);
753  bit_offset += bits_touched;
754  if (bits_touched < bits)
755  {
757  return;
758  }
759  if (value.value[i] == value.delimiter)
760  return;
761  }
762  }
764  }
765 
769  template <typename T, typename std::enable_if<detail::has_format_method<typename delimited_array<T>::elem_type>::value, int *>::type = nullptr>
770  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(const delimited_array<T> &value)
771  {
772  if (status != status_e::NO_ERROR)
773  return;
774  ensure_store();
775  for (size_t i = 0; i < value.max_size; i++)
776  {
777  value.value[i].format(*this);
778  if (value.value[i] == value.delimiter || status != status_e::NO_ERROR)
779  return;
780  }
782  }
783 
787  template <typename T>
788  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(const delimited_array<T> &&value)
789  {
790  store(value);
791  }
792 
798  template <typename T, typename T2, typename std::enable_if<
799  !detail::is_format_modifier<typename serdes::array<T, T2>::elem_type>::value &&
800  detail::supported_by_bitcpy<typename serdes::array<T, T2>::elem_type>::value
801  , int *>::type = nullptr>
802  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(const serdes::array<T, T2> &value, size_t bits = detail::default_bitsize<typename serdes::array<T, T2>::elem_type>::value)
803  {
804  if (status != status_e::NO_ERROR)
805  return;
806  ensure_store();
807 
808  // here the "size" reference is finally copied, in case it changed after the reference bind occurred
809  size_t array_size = static_cast<size_t>(value.size);
810  if (array_size > value.max_size)
811  {
812  array_size = value.max_size;
814  }
815  const size_t total_bits = array_size * sizeof(typename serdes::array<T, T2>::elem_type) * 8;
816  // shortcut for memory aligned situations
817  if (sizeof(typename serdes::array<T, T2>::elem_type) == 1 && bits == 8 && buffer.element_size == 1 && (bit_offset & 7u) == 0u && bit_capacity - bit_offset >= total_bits)
818  {
819  std::memcpy(&reinterpret_cast<uint8_t *>(buffer.value)[bit_offset >> 3], &value.value[0], array_size);
820  bit_offset += total_bits;
821  return;
822  }
823  for (size_t i = 0; i < array_size; i++)
824  {
825  const size_t bits_touched = bitcpy(buffer, value.value[i], bit_offset, bits);
826  bit_offset += bits_touched;
827  if (bits_touched < bits)
828  {
830  return;
831  }
832  }
833  }
834 
840  template <typename T, typename T2, typename std::enable_if<
841  !detail::is_format_modifier<typename serdes::array<T, T2>::elem_type>::value &&
842  !detail::supported_by_bitcpy<typename serdes::array<T, T2>::elem_type>::value
843  , int *>::type = nullptr>
844  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(const serdes::array<T, T2> &value, size_t bits = detail::default_bitsize<typename serdes::array<T, T2>::elem_type>::value)
845  {
846  if (status != status_e::NO_ERROR)
847  return;
848  ensure_store();
849 
850  // here the "size" reference is finally copied, in case it changed after the reference bind occurred
851  size_t array_size = static_cast<size_t>(value.size);
852  if (array_size > value.max_size)
853  {
854  array_size = value.max_size;
856  }
857  for (size_t i = 0; i < array_size && status != status_e::NO_ERROR; i++)
858  store(value.value[i], bits);
859  }
860 
865  template <typename T, typename T2, typename std::enable_if<detail::has_format_method<typename serdes::array<T, T2>::elem_type>::value, int *>::type = nullptr>
866  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(const serdes::array<T, T2> &value)
867  {
868  if (status != status_e::NO_ERROR)
869  return;
870  ensure_store();
871 
872  // here the "size" reference is finally copied, in case it changed after the reference bind occurred
873  size_t array_size = static_cast<size_t>(value.size);
874  if (array_size > value.max_size)
875  {
877  return;
878  }
879  for (size_t i = 0; i < array_size; i++)
880  {
881  value.value[i].format(*this);
882  if (status != status_e::NO_ERROR)
883  return;
884  }
885  }
886 
891  template <typename T, typename T2>
892  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(const array<T, T2> &&value)
893  {
894  store(value);
895  }
896 
899  template<typename T, typename std::enable_if<
900  detail::is_formatter<typename detail::remove_cvref_cpp11<T>::type>::value,
901  int *>::type* = nullptr>
902  CPP_SERDES_LIB_PACKET_API_INLINE2 void store(T &&value)
903  {
904  if (status != status_e::NO_ERROR)
905  return;
906  ensure_store();
907  if (value.formatter_lambda == nullptr)
908  {
910  return;
911  }
912  value.formatter_lambda(*this);
913  }
914 
918  template <typename ST>
919  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(const serdes::pad<ST> padding)
920  {
921  if (status != status_e::NO_ERROR)
922  return;
923  ensure_store();
924  pad_assuming_no_prior_errors(padding.value);
925  }
926 
930  template <typename ST>
931  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(const serdes::align<ST> alignment)
932  {
933  if (status != status_e::NO_ERROR)
934  return;
935  ensure_store();
936  align(alignment.value);
937  }
938 
943  template <typename T, typename ST>
944  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(const bitpack<T, ST> &&value)
945  {
946  store(value.value, value.bits);
947  }
948 
953  template <typename T, typename ST>
954  CPP_SERDES_LIB_PACKET_API_INLINE1 void store(const bitpack<T, ST> &value)
955  {
956  store(value.value, value.bits);
957  }
958 
961  inline void store(const packet_base &value)
962  {
963  if (status != status_e::NO_ERROR)
964  return;
965  ensure_store();
966  const_cast<packet_base &>(value).format(*this);
967  }
968 
971  inline void store(const packet_base &&value)
972  {
973  store(value);
974  }
975 
976  //
977  // stream operator SECTION (<< is store, >> is load)
978  //
979 
984  template <typename T>
985  CPP_SERDES_LIB_PACKET_API_INLINE1 packet &operator>>(T &&x)
986  {
987  load(std::forward<T>(x));
988  return *this;
989  }
990 
995  template <typename T>
996  CPP_SERDES_LIB_PACKET_API_INLINE1 packet &operator<<(T &&x)
997  {
998  store(std::forward<T>(x));
999  return *this;
1000  }
1001 
1002  //
1003  // add() SECTION (same as "+", either store or load)
1004  //
1005 
1010  template <typename T>
1011  CPP_SERDES_LIB_PACKET_API_INLINE1 void add(T &&x, size_t bits)
1012  {
1013  if (mode == mode_e::LOADING)
1014  load(std::forward<T>(x), bits);
1015  else if (mode == mode_e::STORING)
1016  store(std::forward<T>(x), bits);
1017  }
1018 
1023  template <typename T, size_t N>
1024  CPP_SERDES_LIB_PACKET_API_INLINE1 void add(T (&x)[N], size_t bits)
1025  {
1026  if (mode == mode_e::LOADING)
1027  for (size_t i = 0; i < N; i++)
1028  load(x[i], bits);
1029  else if (mode == mode_e::STORING)
1030  for (size_t i = 0; i < N; i++)
1031  store(x[i], bits);
1032  }
1033 
1037  template <typename T, typename std::enable_if<
1038  !detail::is_validator<typename detail::remove_cvref_cpp11<T>::type>::value,
1039  int *>::type* = nullptr>
1040  CPP_SERDES_LIB_PACKET_API_INLINE1 void add(T &&x)
1041  {
1042  if (mode == mode_e::LOADING)
1043  load(std::forward<T>(x));
1044  else if (mode == mode_e::STORING)
1045  store(std::forward<T>(x));
1046  }
1047 
1051  template <typename T, size_t N>
1052  CPP_SERDES_LIB_PACKET_API_INLINE1 void add(T (&x)[N])
1053  {
1054  if (mode == mode_e::LOADING)
1055  for (size_t i = 0; i < N; i++)
1056  load(x[i]);
1057  else if (mode == mode_e::STORING)
1058  for (size_t i = 0; i < N; i++)
1059  store(x[i]);
1060  }
1061 
1067  template <typename T, typename F>
1068  CPP_SERDES_LIB_PACKET_API_INLINE1 void add(T &&value, F &&validation)
1069  {
1070  if (status != status_e::NO_ERROR)
1071  return;
1072  if (mode == mode_e::LOADING)
1073  load(std::forward<T>(value));
1074  if (!std::forward<F>(validation)())
1076  else if (mode == mode_e::STORING)
1077  store(std::forward<T>(value));
1078  }
1079 
1089  template <typename T, typename std::enable_if<
1090  detail::is_validator<typename detail::remove_cvref_cpp11<T>::type>::value,
1091  int *>::type* = nullptr>
1092  CPP_SERDES_LIB_PACKET_API_INLINE1 void add(T &&value)
1093  {
1094  add(value.field, value.validation);
1095  }
1096 
1097  //
1098  // "+" steam operator SECTION (same as add(), either store or load)
1099  //
1100 
1101 #if (defined(__GNUC__) && !defined(__clang__))
1102 #pragma GCC diagnostic push
1103 #pragma GCC diagnostic ignored "-Weffc++"
1104 #endif
1105  template <typename T>
1110  CPP_SERDES_LIB_PACKET_API_INLINE1 packet &operator+(T &&value)
1111  {
1112  add(std::forward<T>(value));
1113  return *this;
1114  }
1115 #if (defined(__GNUC__) && !defined(__clang__))
1116 #pragma GCC diagnostic pop
1117 #endif
1118 
1128  {
1129  if (status != status_e::NO_ERROR)
1130  return {buffer, 0u, 0u};
1131  const size_t max_num_bytes = buffer.size * buffer.element_size;
1132  const size_t end_byte_index_plus_one = start.value + size.value;
1133  if (end_byte_index_plus_one >= max_num_bytes)
1134  {
1136  return {buffer, 0u, 0u};
1137  }
1138  return {buffer, start.value, end_byte_index_plus_one};
1139  }
1140 
1149  {
1150  if (status != status_e::NO_ERROR)
1151  return {buffer, 0u, 0u};
1152  const size_t max_num_bytes = bit_offset / 8u;
1153  if (start.value >= max_num_bytes)
1154  {
1156  return {buffer, 0u, 0u};
1157  }
1158  return byte_iterator(start, number_of_bytes{max_num_bytes - start.value});
1159  }
1160 
1168  {
1169  if (status != status_e::NO_ERROR)
1172  }
1173 
1174 #if !defined(configCPP_SERDES_LIB_EXCLUDE_CPP_CRC) && BITCPY_CONSTEXPR_SUPPORTED
1175  template <typename cpp_crc_type>
1182  CPP_SERDES_LIB_PACKET_API_INLINE2 typename cpp_crc_type::type calculate_crc(typename cpp_crc_type::type *crc_field = nullptr)
1183  {
1184  auto crc_calculated = cpp_crc_type::null_crc;
1185  for (auto &segment : previous_bytes())
1186  crc_calculated = cpp_crc_type::calc(segment.bytes, segment.num_bytes, crc_calculated);
1187  if (crc_field != nullptr && mode == serdes::mode_e::STORING)
1188  *crc_field = crc_calculated;
1189  return crc_calculated;
1190  }
1191 #endif
1192 
1193  private:
1196  inline void pad_assuming_no_prior_errors(const size_t bits) noexcept
1197  {
1198  const size_t next_bit_offset = bit_offset + bits;
1199  if (next_bit_offset > bit_capacity)
1200  {
1202  return;
1203  }
1204  bit_offset = next_bit_offset;
1205  }
1206 
1209  inline void align_assuming_no_prior_errors(size_t bits) noexcept
1210  {
1211  const size_t alignment = bit_offset % bits;
1212  if (alignment > 0)
1213  {
1214  const size_t next_bit_offset = bit_offset + bits - alignment;
1215  if (next_bit_offset > bit_capacity)
1216  {
1218  return;
1219  }
1220  bit_offset = next_bit_offset;
1221  }
1222  }
1223 
1225  inline void ensure_load() noexcept
1226  {
1227  if (mode != mode_e::LOADING)
1228  {
1229  if (mode == mode_e::STORING)
1230  reset();
1232  }
1233  }
1234 
1236  inline void ensure_store() noexcept
1237  {
1238  if (mode != mode_e::STORING)
1239  {
1240  if (mode == mode_e::LOADING)
1241  reset();
1243  }
1244  }
1245  };
1246 
1247  template <typename T_array, size_t N>
1248  status_t packet_base::store(T_array (&target_buffer)[N], size_t max_elements, size_t bit_offset)
1249  {
1250  if (N < max_elements)
1251  max_elements = N;
1252  packet pkt_obj(serdes::sized_pointer<T_array>(&target_buffer[0], max_elements), bit_offset, mode_e::STORING);
1253  format(pkt_obj);
1254  return {pkt_obj.status, pkt_obj.bit_offset};
1255  }
1256 
1257  template <typename T_pointer, typename std::enable_if<std::is_pointer<T_pointer>::value, int *>::type>
1258  status_t packet_base::store(T_pointer target_buffer, size_t max_elements, size_t bit_offset)
1259  {
1260  packet pkt_obj(serdes::sized_pointer<typename std::remove_pointer<T_pointer>::type>(target_buffer, max_elements), bit_offset, mode_e::STORING);
1261  format(pkt_obj);
1262  return {pkt_obj.status, pkt_obj.bit_offset};
1263  }
1264 
1265  template <typename T_sized_pointer, typename std::enable_if<serdes::detail::is_sized_pointer<T_sized_pointer>::value, int *>::type>
1266  status_t packet_base::store(T_sized_pointer target_buffer, size_t bit_offset)
1267  {
1268  packet pkt_obj(target_buffer, bit_offset, mode_e::STORING);
1269  format(pkt_obj);
1270  return {pkt_obj.status, pkt_obj.bit_offset};
1271  }
1272  template <typename T_array, size_t N>
1273  status_t packet_base::load(const T_array (&source_buffer)[N], size_t max_elements, size_t bit_offset)
1274  {
1275  if (N < max_elements)
1276  max_elements = N;
1277  packet pkt_obj(serdes::sized_pointer<const T_array>(&source_buffer[0], N), bit_offset, mode_e::LOADING);
1278  format(pkt_obj);
1279  return {pkt_obj.status, pkt_obj.bit_offset};
1280  }
1281  template <typename T_pointer, typename std::enable_if<std::is_pointer<T_pointer>::value, int *>::type>
1282  status_t packet_base::load(const T_pointer source_buffer, size_t max_elements, size_t bit_offset)
1283  {
1284  packet pkt_obj(serdes::sized_pointer<const typename std::remove_pointer<T_pointer>::type>(source_buffer, max_elements), bit_offset, mode_e::LOADING);
1285  format(pkt_obj);
1286  return {pkt_obj.status, pkt_obj.bit_offset};
1287  }
1288  template <typename T_sized_pointer, typename std::enable_if<serdes::detail::is_sized_pointer<T_sized_pointer>::value, int *>::type>
1289  status_t packet_base::load(const T_sized_pointer target_buffer, size_t bit_offset)
1290  {
1291  packet pkt_obj(target_buffer, bit_offset, mode_e::LOADING);
1292  format(pkt_obj);
1293  return {pkt_obj.status, pkt_obj.bit_offset};
1294  }
1295  template <typename T>
1296  CPP_SERDES_LIB_PACKET_API_INLINE1 status_t packet_base::operator>>(T &&value)
1297  {
1298  return store(std::forward<T>(value));
1299  }
1300  template <typename T>
1301  CPP_SERDES_LIB_PACKET_API_INLINE1 status_t packet_base::operator<<(T &&value)
1302  {
1303  return load(std::forward<T>(value));
1304  }
1305 
1309  CONSTEXPR_ABOVE_CPP11_OR_INLINE size_t remaining_bits(const packet &_pkt)
1310  {
1311  const size_t total_buff_bits = _pkt.buffer.size * _pkt.buffer.element_size * 8u;
1312  if (total_buff_bits > _pkt.bit_offset)
1313  return total_buff_bits - _pkt.bit_offset;
1314  return 0u;
1315  }
1316 
1320  CONSTEXPR_ABOVE_CPP11_OR_INLINE size_t remaining_bytes(const packet &_pkt)
1321  {
1322  return remaining_bits(_pkt) / 8u;
1323  }
1324 } // namespace serdes
1325 
1326 // clang-format on
1327 #endif // _SERDES_H_
serdes::status_e
status_e
error status of serialization/deserialization process
Definition: serdes_errors.h:16
serdes::packet::align
void align(size_t bits) noexcept
aligns (increases) the bit offset to a multiple of the specified bits
Definition: serdes.h:131
serdes::packet::mode
mode_e mode
the serdes mode (LOADING, STORING, or UNSPECIFIED)
Definition: serdes.h:58
serdes::status_e::NO_LOAD_TO_RVALUE
@ NO_LOAD_TO_RVALUE
tried to loading data from a serial buffer into a temporary rvalue (causes the serdes process to abor...
serdes::packet::load
CPP_SERDES_LIB_PACKET_API_INLINE1 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:147
serdes::mode_e::LOADING
@ LOADING
(deserializing) loading from serial data into variables
serdes::status_e::START_BYTE_PAST_CURRENT
@ START_BYTE_PAST_CURRENT
a byte_iterator was passed a starting byte that was past the current byte position,...
serdes::byte_iterator_type
allows iteration through the bytes of a buffer, even when the buffer's underlying type is not a byte ...
Definition: serdes_byte_iterator.h:21
serdes::packet::reset
void reset() noexcept
resets the bit offset to 0 and the status to NO_ERROR
Definition: serdes.h:63
serdes::starting_byte_index
explict type for representing a starting byte index (since it's easy to mess up the iterator inputs o...
Definition: serdes_byte_iterator.h:129
serdes::packet_base::store
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
serdes::status_e::NO_ERROR
@ NO_ERROR
no serialization/deserialization errors occurred
serdes::packet::store
void store(const packet_base &value)
[[serialize]] stores a packet_base reference into a serial buffer
Definition: serdes.h:961
serdes::packet::previous_bytes
byte_iterator_type previous_bytes()
Will return an iterator to the raw serial bytes in the packet starting at the beginning of the packet...
Definition: serdes.h:1167
serdes::packet::operator>>
CPP_SERDES_LIB_PACKET_API_INLINE1 packet & operator>>(T &&x)
[[deserialize]] loads serial data into the passed value (same as load)
Definition: serdes.h:985
serdes::delimited_array::delimiter
const elem_type & delimiter
reference to a reserved delimiter value marking the end of the array
Definition: serdes_format_modifiers.h:171
serdes::packet::add
CPP_SERDES_LIB_PACKET_API_INLINE1 void add(T &&x, size_t bits)
adds a referenced field to the serial format for both serialization and deserialization
Definition: serdes.h:1011
serdes::bitpack::bits
const ST & bits
a reference to the number of bits to use when storing/loading the referenced value
Definition: serdes_format_modifiers.h:60
serdes::bitpack
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
serdes::packet_base::operator>>
serdes::status_t operator>>(T &&value)
[[serialize]] stores the packet_base object into the passed serial data (same as store)
serdes::status_e::EXCEEDED_SERIAL_SIZE
@ EXCEEDED_SERIAL_SIZE
during serialization/deserialization the "serial data" boundary was reached (causes the serdes proces...
serdes::mode_e::UNSPECIFIED
@ UNSPECIFIED
not yet configured for storing/loading
serdes_validator.h
defines the serdes::validator class for recording arbitrary validation procedures
serdes_format_modifiers.h
Defines format modification classes: align, pad, bitpack, array, delimited_array.
serdes::sized_pointer< void >
Holds a pointer to a void array (with type information stored as a runtime element size paramenter) w...
Definition: bitcpy_sized_pointer.h:48
serdes::sized_pointer< void >::value
void *const value
the underlying pointer reinterpreted as a void* type
Definition: bitcpy_sized_pointer.h:51
serdes::array::elem_type
typename detail::has_data_and_size< T >::elem_type elem_type
Definition: serdes_format_modifiers.h:92
serdes::packet::buffer
serdes::sized_pointer< void > buffer
underlying buffer to serialize/deserialize to/from
Definition: serdes.h:56
serdes::array::size
const ST & size
a reference to a value that contains the dynamic size of the array for fixed sized arrays (where the ...
Definition: serdes_format_modifiers.h:103
serdes::packet::load
void load(packet_base &value)
[[deserialize]] loads from serial buffer into a packet_base reference
Definition: serdes.h:551
serdes::sized_pointer
Holds a pointer to an array (with its type information) with a constant size.
Definition: bitcpy_sized_pointer.h:19
serdes::sized_pointer< void >::size
const size_t size
size of the array (number of elements in the array)
Definition: bitcpy_sized_pointer.h:54
serdes::delimited_array::value
elem_type * value
pointer to the head of the array
Definition: serdes_format_modifiers.h:168
serdes::packet
a serialization/deserialization helper class, with load, store, and stream operators
Definition: serdes.h:54
serdes::bitpack::value
T & value
a reference to the bitpacked value
Definition: serdes_format_modifiers.h:57
serdes::array
a container for fixed or dynamically sized arrays, with an upper bounds limit for safety
Definition: serdes_format_modifiers.h:87
serdes::status_e::FORMATTER_NOT_SET
@ FORMATTER_NOT_SET
a pure_virtual_formatter (a.k.a "serdes::formatter(nullptr)") was used but not overriden (causes the ...
serdes::packet::operator+
CPP_SERDES_LIB_PACKET_API_INLINE1 packet & operator+(T &&value)
adds a field to the serial format for both serialization and deserialization (same as packet....
Definition: serdes.h:1110
serdes::delimited_array
a container for dynamically sized arrays with their ending marked by a reserved delimiter value
Definition: serdes_format_modifiers.h:160
bitliterals.h
Defines string literals for fixed sized types, useful for serdes definitions. For example: Writting "...
serdes::mode_e
mode_e
the serdes mode of operation
Definition: serdes_errors.h:95
serdes::align
specifies a number of bits to be used to align the bit offset as a multiple of
Definition: serdes_format_modifiers.h:18
serdes::packet::packet
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:89
serdes::delimited_array::elem_type
typename detail::has_data_and_size< T >::elem_type elem_type
Definition: serdes_format_modifiers.h:165
serdes::packet::bit_offset
size_t bit_offset
current bit offset in the serdes process
Definition: serdes.h:57
serdes_errors.h
Defines error and status types: status_e, status_t, mode_e, status2str(status_e)
serdes::array::value
elem_type * value
a pointer to the array head
Definition: serdes_format_modifiers.h:95
serdes::number_of_bytes
explict type for representing the number of bytes to iterate over (since it's easy to mess up the ite...
Definition: serdes_byte_iterator.h:137
serdes::mode_e::STORING
@ STORING
(serializing) storing variables into serial data
serdes::delimited_array::max_size
const size_t max_size
maximum size of the array (used for bounds checking)
Definition: serdes_format_modifiers.h:174
serdes::packet::status
status_e status
the current error status of the serdes process
Definition: serdes.h:59
serdes::pad::value
const ST & value
bit pad reference value
Definition: serdes_format_modifiers.h:38
serdes::custom_type
wrapper construct used to let the user provide custom (de)serialization support for types without mod...
Definition: bitcpy_common.h:118
serdes::packet::packet
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:76
serdes::bitcpy
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
serdes::sized_pointer< void >::bit_capacity
size_t bit_capacity() const noexcept
returns the number of bits in the array
Definition: bitcpy_sized_pointer.h:98
serdes::packet_base
inheritable base class to allow format recording and application with no additional memory storage (e...
Definition: serdes_fwd_declarations.h:45
serdes::packet::packet
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:101
serdes::status_e::ARRAY_SIZE_OVER_MAX
@ ARRAY_SIZE_OVER_MAX
the "serdes::array" object's size exceeded the maximum size of the array when evaluated (causes the s...
serdes::packet::packet
packet(T_array &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 a reference to any container with a data() and size() method For e...
Definition: serdes.h:115
serdes::status_e::DELIMITER_NOT_FOUND
@ DELIMITER_NOT_FOUND
the specified delimiter in a delimited_array object was not found before the end of the array (causes...
serdes::array::max_size
const size_t max_size
maximum size of the array (used for bounds checking)
Definition: serdes_format_modifiers.h:106
serdes::remaining_bytes
CONSTEXPR_ABOVE_CPP11_OR_INLINE size_t remaining_bytes(const packet &_pkt)
Returns the number of bytes remaining in the serdes::packet buffer.
Definition: serdes.h:1320
serdes::packet::pad
void pad(const size_t bits) noexcept
moves the bit offset head the specified bits
Definition: serdes.h:123
serdes::packet_base::operator<<
serdes::status_t operator<<(T &&value)
[[deserialize]] loads packet_base data into the passed serial data (same as load)
serdes::remaining_bits
CONSTEXPR_ABOVE_CPP11_OR_INLINE size_t remaining_bits(const packet &_pkt)
Returns the number of bits remaining in the serdes::packet buffer.
Definition: serdes.h:1309
serdes::packet::operator<<
CPP_SERDES_LIB_PACKET_API_INLINE1 packet & operator<<(T &&x)
[[serialize]] stores the passed value into the serial data (same as store)
Definition: serdes.h:996
serdes::packet::previous_bytes
byte_iterator_type previous_bytes(starting_byte_index start)
Will return an iterator to the raw serial bytes in the packet starting at the specified location and ...
Definition: serdes.h:1148
serdes::status_e::NUM_BYTES_OVER_MAX
@ NUM_BYTES_OVER_MAX
a byte_iterator was passed a starting + number of bytes that was past the end of the buffer
serdes::packet::store
void store(const packet_base &&value)
[[serialize]] stores a packet_base rvalue into a serial buffer
Definition: serdes.h:971
serdes::packet::byte_iterator
byte_iterator_type byte_iterator(starting_byte_index start, number_of_bytes size)
Will return an iterator to the raw serial bytes in the packet over a selected range.
Definition: serdes.h:1127
cppcrc.h
A very small, fast, header-only, C++ library for generating CRCs.
serdes
CppSerdes library namespace.
Definition: bitcpy_common.h:68
serdes::packet_base::format
virtual void format(packet &)=0
override to declare the serdes process used in store() and load()
serdes::packet::store
CPP_SERDES_LIB_PACKET_API_INLINE1 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:578
serdes::packet::load
void load(packet_base &&value)
[[deserialize]] loads from serial buffer into a packet_base rvalue
Definition: serdes.h:561
serdes::status_e::INVALID_FIELD
@ INVALID_FIELD
a fields validation check failed (causes the serdes process to abort)
serdes::packet::bit_capacity
const size_t bit_capacity
buffer.bit_capacity() value
Definition: serdes.h:60
serdes::packet_base::load
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
serdes::align::value
const ST & value
bit alignment reference value
Definition: serdes_format_modifiers.h:21
bitcpy.h
Includes all the bitcpy definitions for serialization and deserialization.
serdes::pad
specifies a number of bits to be used to pad (add to) the current bit offset
Definition: serdes_format_modifiers.h:35
serdes::sized_pointer< void >::element_size
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
serdes_formatter.h
defines the serdes::formatter class for recording arbitrary format lambda procedures
serdes_byte_iterator.h
Defines a iterator for scanning through the bytes of a serdes::packet even when that packet is not co...