CppSerdes  1.0
A serialization/deserialization library designed with embedded systems in mind
bitprint.h
Go to the documentation of this file.
1 #ifndef _BITPRINT_H_
8 #define _BITPRINT_H_
9 
10 // clang-format off
11 #include <stdint.h>
12 #include <cstddef>
13 #include <stdio.h>
14 #include <type_traits>
15 #include <inttypes.h>
16 
17 #ifdef __SIZEOF_INT128__
18 #define BITCPY_INT128_CONDITIONAL_DEFINE(...) __VA_ARGS__
20 #define BITCPY_INT128_CONDITIONAL_DEFINE_C(...) __VA_ARGS__ static_assert(true, "")
22 #else
23 #define BITCPY_INT128_CONDITIONAL_DEFINE(...)
25 #define BITCPY_INT128_CONDITIONAL_DEFINE_C(...) static_assert(true, "")
27 #endif
28 
30 namespace serdes
31 {
32  namespace bitprint_detail
33  {
34  template <typename T>
35  struct make_signed
36  {
37  using type = typename std::make_signed<T>::type;
38  };
39  BITCPY_INT128_CONDITIONAL_DEFINE_C(
40  template <>
41  struct make_signed<__uint128_t> {
42  using type = __int128_t;
43  };);
44  template <typename T>
45  struct make_unsigned
46  {
47  using type = typename std::make_unsigned<T>::type;
48  };
49  BITCPY_INT128_CONDITIONAL_DEFINE_C(
50  template <>
51  struct make_unsigned<__uint128_t> {
52  using type = __uint128_t;
53  };
54  template <>
55  struct make_unsigned<__int128_t> {
56  using type = __uint128_t;
57  };);
58  template <>
59  struct make_unsigned<float>
60  {
61  using type = uint32_t;
62  };
63  template <>
64  struct make_unsigned<double>
65  {
66  using type = uint64_t;
67  };
68  template <bool use_brackets>
69  void print_bracket_newline(const bool add_newline)
70  {
71  if (use_brackets)
72  printf((add_newline ? "}\n" : "}"));
73  else if (add_newline)
74  printf("\n");
75  }
76  }
77 
81  inline void printhex(const uint8_t data, const bool add_newline = true)
82  {
83  if (add_newline)
84  printf("0x%02" PRIX8 "\n", data);
85  else
86  printf("0x%02" PRIX8, data);
87  }
88 
92  inline void printhex(const uint16_t data, const bool add_newline = true)
93  {
94  if (add_newline)
95  printf("0x%04" PRIX16 "\n", data);
96  else
97  printf("0x%04" PRIX16, data);
98  }
99 
103  inline void printhex(const uint32_t data, const bool add_newline = true)
104  {
105  if (add_newline)
106  printf("0x%08" PRIX32 "\n", data);
107  else
108  printf("0x%08" PRIX32, data);
109  }
110 
114  inline void printhex(const uint64_t data, const bool add_newline = true)
115  {
116  if (add_newline)
117  printf("0x%08" PRIX32 "%08" PRIX32 "\n",
118  static_cast<uint32_t>(data >> 32),
119  static_cast<uint32_t>(data));
120  else
121  printf("0x%08" PRIX32 "%08" PRIX32,
122  static_cast<uint32_t>(data >> 32),
123  static_cast<uint32_t>(data));
124  }
125  BITCPY_INT128_CONDITIONAL_DEFINE_C(
126 
128  inline void printhex(const __uint128_t data, const bool add_newline = true)
129  {
130  if (add_newline)
131  printf("0x%08" PRIX32 "%08" PRIX32 "%08" PRIX32 "%08" PRIX32 "\n",
132  static_cast<uint32_t>(data >> 32 * 3),
133  static_cast<uint32_t>(data >> 32 * 2),
134  static_cast<uint32_t>(data >> 32 * 1),
135  static_cast<uint32_t>(data));
136  else
137  printf("0x%08" PRIX32 "%08" PRIX32 "%08" PRIX32 "%08" PRIX32,
138  static_cast<uint32_t>(data >> 32 * 3),
139  static_cast<uint32_t>(data >> 32 * 2),
140  static_cast<uint32_t>(data >> 32 * 1),
141  static_cast<uint32_t>(data));
142  });
143 
147  inline void printhex(const bool data, const bool add_newline = true)
148  {
149  printhex(uint8_t(data), add_newline);
150  }
151 
155  template <typename T = void,
156  typename std::enable_if<
157  std::is_enum<T>::value
158  || std::is_signed<T>::value
159  BITCPY_INT128_CONDITIONAL_DEFINE(|| std::is_same<T, __int128_t>::value),
160  T>::type * = nullptr>
161  void printhex(const T data, const bool add_newline = true)
162  {
163  typedef typename bitprint_detail::make_unsigned<T>::type data_as_unsigned_type;
164  union
165  {
166  T original_value;
167  data_as_unsigned_type unsigned_value;
168  } punned_data;
169  punned_data.original_value = data;
170  printhex(punned_data.unsigned_value, add_newline);
171  }
172 
177  template <bool use_brackets = true, typename T = void, size_t N = 0u>
178  void printhex(const T (&data)[N], const bool add_newline = true)
179  {
180  if (use_brackets)
181  printf("{");
182  for (size_t i = 0; i < N; i++)
183  {
184  printhex(data[i], false);
185  printf("%s", (i + 1u < N ? ", " : ""));
186  }
187  bitprint_detail::print_bracket_newline<use_brackets>(add_newline);
188  }
189 
190  namespace bitprint_detail
191  {
193  template <typename...>
194  using void_t_test = void;
195 
197  template <typename T, typename = void>
198  struct has_data_and_size : std::false_type
199  {
200  };
201  template <typename T>
202  struct has_data_and_size<
203  T, void_t_test<
204  decltype(std::declval<typename std::remove_cv<typename std::remove_reference<T>::type>::type>().data()),
205  decltype(std::declval<typename std::remove_cv<typename std::remove_reference<T>::type>::type>().size())>>
206  : std::true_type
207  {
208  };
209  } // namespace bitprint_detail
210 
215  template <bool use_brackets = true, typename T = void,
216  typename std::enable_if<bitprint_detail::has_data_and_size<T>::value, int>::type * = nullptr>
217  void printhex(const T& data, const bool add_newline = true)
218  {
219  if (use_brackets)
220  printf("{");
221  const size_t N = data.size();
222  for (size_t i = 0; i < N; i++)
223  {
224  printhex(data[i], false);
225  printf("%s", (i + 1u < N ? ", " : ""));
226  }
227  bitprint_detail::print_bracket_newline<use_brackets>(add_newline);
228  }
229 
235  template <bool use_brackets = true, typename T = void, size_t N = 0u>
236  void printhex(const T (&data)[N], size_t size, const bool add_newline = true)
237  {
238  if (use_brackets)
239  printf("{");
240  if (size > N)
241  size = N;
242  for (size_t i = 0; i < size; i++)
243  {
244  printhex(data[i], false);
245  printf("%s", (i + 1u < size ? ", " : ""));
246  }
247  bitprint_detail::print_bracket_newline<use_brackets>(add_newline);
248  }
249 
254  template <bool use_brackets = true, typename T = void, size_t N = 0u>
255  void printbin(const T (&data)[N], const bool add_newline = true)
256  {
257  if (use_brackets)
258  printf("{");
259  for (size_t i = 0; i < N; i++)
260  {
261  for (size_t ii = 0; ii < sizeof(T); ii++)
262  {
263  const uint8_t data_element = static_cast<uint8_t>(
264  (data[i] >> (sizeof(T) * 8 - (ii + 1) * 8)) & 0xFFu);
265  printf("%c%c%c%c%c%c%c%c",
266  ((data_element & 0x80u) ? '1' : '0'),
267  ((data_element & 0x40u) ? '1' : '0'),
268  ((data_element & 0x20u) ? '1' : '0'),
269  ((data_element & 0x10u) ? '1' : '0'),
270  ((data_element & 0x08u) ? '1' : '0'),
271  ((data_element & 0x04u) ? '1' : '0'),
272  ((data_element & 0x02u) ? '1' : '0'),
273  ((data_element & 0x01u) ? '1' : '0'));
274  }
275  printf("%s", (i + 1u < N ? ", " : ""));
276  }
277  bitprint_detail::print_bracket_newline<use_brackets>(add_newline);
278  }
279 
283  template <typename T, typename std::enable_if<!std::is_array<T>::value && !std::is_same<T, bool>::value, T>::type * = nullptr>
284  void printbin(const T data, const bool add_newline = true)
285  {
286  typedef const T data_as_array_type[1];
287  printbin<false>(*reinterpret_cast<data_as_array_type *>(&data), add_newline);
288  }
289 
293  inline void printbin(const bool data, const bool add_newline = true)
294  {
295  printbin(uint8_t(data), add_newline);
296  }
297 }
298 
299 // clang-format on
300 #endif // _BITPRINT_H_
serdes::printhex
void printhex(const uint8_t data, const bool add_newline=true)
prints uint8_t value in hex format
Definition: bitprint.h:81
serdes::printbin
void printbin(const T(&data)[N], const bool add_newline=true)
prints an array in binary format
Definition: bitprint.h:255
serdes
CppSerdes library namespace.
Definition: bitcpy_common.h:68