CppSerdes  1.0
A serialization/deserialization library designed with embedded systems in mind
bitcpy_to_array.h
Go to the documentation of this file.
1 #ifndef _BITCPY_TO_ARRAY_H_
9 #define _BITCPY_TO_ARRAY_H_
10 
11 #include "bitcpy_common.h"
12 
14 namespace serdes
15 {
26  template <typename T_array, typename T_val, detail::requires_unsigned_type<T_val> * = nullptr>
27  CONSTEXPR_ABOVE_CPP11 size_t bitcpy(T_array *const dest, const T_val source, const size_t bit_offset = 0, const size_t bits = detail::default_bitsize<T_val>::value) noexcept
28  {
29  constexpr size_t bits_per_T_array = sizeof(T_array) * 8u;
30  constexpr size_t bits_per_T_array_minus_one = bits_per_T_array - 1u;
31  size_t array_write_index = bit_offset / bits_per_T_array;
32  const size_t bit_offset_from_start_index = bit_offset & bits_per_T_array_minus_one; // same as (bit_offset % sizeof(T_array)*8)
33 
34  // shortcut 1: handle exact bit size and offset match
35  if (bits == bits_per_T_array && bit_offset_from_start_index == 0)
36  {
37  dest[array_write_index] = source;
38  return bits;
39  }
40 
41  // shortcut 2: if the write doesn't need to be split across array elements
42  const size_t number_of_bits_after_index = bit_offset_from_start_index + bits;
43  if (number_of_bits_after_index <= bits_per_T_array)
44  {
45  if (bits == 0) // unlikely. so we reduce the chances of needing to do this check until the last moment
46  return bits;
47  const T_array unaligned_mask = detail::bitmask<T_array>(bits);
48  const size_t alignment_shift = bits_per_T_array - number_of_bits_after_index;
49  T_array &dest_array_element = dest[array_write_index];
50 
51  // zero out intended destination bits only in the mask's range
52  dest_array_element &= ~(unaligned_mask << alignment_shift);
53 
54  // fill in with the new bits from the source
55  dest_array_element |= static_cast<T_array>(source & unaligned_mask) << alignment_shift;
56  return bits;
57  }
58 
59  // if the write DOES need to be split across > 1 array elements
60  const size_t num_array_elements_touched = (number_of_bits_after_index + bits_per_T_array - 1u) / bits_per_T_array;
61  const size_t bits_in_first_element = bits_per_T_array - bit_offset_from_start_index;
62  size_t bits_remaining = bits - bits_in_first_element;
63  {
64  const T_array aligned_mask = detail::bitmask<T_array>(bits_in_first_element);
65  T_array &dest_array_first_element = dest[array_write_index];
66  dest_array_first_element &= ~aligned_mask;
67  dest_array_first_element |= static_cast<T_array>(source >> bits_remaining) & aligned_mask;
68  }
69  for (size_t i = 1u; i < num_array_elements_touched - 1u; i++)
70  {
71  ++array_write_index;
72  bits_remaining -= bits_per_T_array;
73  dest[array_write_index] = static_cast<T_array>(source >> bits_remaining);
74  }
75  {
76  ++array_write_index;
77  const size_t alignment_shift = bits_per_T_array - bits_remaining;
78  const T_array aligned_mask = detail::bitmask<T_array>(bits_remaining) << alignment_shift;
79  T_array &dest_array_last_element = dest[array_write_index];
80  dest_array_last_element &= ~aligned_mask;
81  dest_array_last_element |= (static_cast<T_array>(source) << alignment_shift) & aligned_mask;
82  }
83  return bits;
84  }
85 
96  template <typename T_array, typename T_val, detail::requires_bool_type<T_val> * = nullptr>
97  CONSTEXPR_ABOVE_CPP11 size_t bitcpy(T_array *const dest, const T_val source, const size_t bit_offset = 0, const size_t bits = detail::default_bitsize<T_val>::value) noexcept
98  {
99  if (bits == 1)
100  {
101  constexpr size_t bits_per_T_array = sizeof(T_array) * 8u;
102  constexpr size_t bits_per_T_array_minus_one = bits_per_T_array - 1u;
103  const T_array bit_mask = static_cast<T_array>(1u) << (bits_per_T_array_minus_one - (bit_offset & bits_per_T_array_minus_one));
104  const size_t array_index = bit_offset / bits_per_T_array;
105  if (source)
106  dest[array_index] |= bit_mask;
107  else
108  dest[array_index] &= ~bit_mask;
109  return bits;
110  }
111  const uint_fast8_t bool_as_uint = static_cast<uint_fast8_t>(source) & static_cast<uint_fast8_t>(1u);
112  return bitcpy(dest, bool_as_uint, bit_offset, bits);
113  }
114 
125  template <typename T_array, typename T_val, detail::requires_small_non_integral_type<T_val> * = nullptr>
126  CONSTEXPR_ABOVE_CPP11 size_t bitcpy(T_array *const dest, const T_val source, const size_t bit_offset = 0, const size_t bits = detail::default_bitsize<T_val>::value) noexcept
127  {
128  return bitcpy(dest, detail::reinterpret_as_unsigned(source), bit_offset, bits);
129  }
130 
141  template <typename T_array, typename T_val, detail::requires_signed_type<T_val> * = nullptr>
142  CONSTEXPR_ABOVE_CPP11 size_t bitcpy(T_array *const dest, const T_val source, const size_t bit_offset = 0, const size_t bits = detail::default_bitsize<T_val>::value) noexcept
143  {
144  return bitcpy(dest, detail::reinterpret_as_unsigned(source), bit_offset, bits);
145  }
146 
158  template <typename T_array, typename T_val, detail::requires_unsigned_type<T_val> * = nullptr>
159  CONSTEXPR_ABOVE_CPP11 size_t bitcpy(T_array *const dest, const sized_pointer<const T_val> &source, const size_t bit_offset, const size_t bits) noexcept
160  {
161  constexpr size_t bits_per_T_val = sizeof(T_val) * 8;
162  const size_t total_bits_T_val = bits_per_T_val * source.size;
163  if (bits == total_bits_T_val)
164  {
165  for (size_t i = 0; i < source.size; i++)
166  bitcpy(dest, source.value[i], bit_offset + i * bits_per_T_val, bits_per_T_val);
167  }
168  else if (bits < total_bits_T_val)
169  {
170  const size_t bit_difference = total_bits_T_val - bits;
171  const size_t starting_source_word = bit_difference / bits_per_T_val;
172  const size_t last_bit_index = source.size - 1u;
173  const size_t last_bit_suboffset = bits_per_T_val * last_bit_index - bit_difference;
174  const size_t remainder_bits = bits - last_bit_suboffset;
175  const std::make_signed<size_t>::type offset_per_loop = bit_offset - bit_difference;
176  for (size_t i = starting_source_word; i < source.size - 1u; i++)
177  bitcpy(dest, source.value[i], offset_per_loop + i * bits_per_T_val, bits_per_T_val);
178  bitcpy(dest, source.value[last_bit_index], bit_offset + last_bit_suboffset, remainder_bits);
179  }
180  else
181  {
182  size_t bit_difference = bits - total_bits_T_val;
183  bitcpy(dest, source.value[0], bit_offset, bits_per_T_val + bit_difference);
184  bit_difference += bit_offset;
185  for (size_t i = 1; i < source.size; i++)
186  {
187  bit_difference += bits_per_T_val;
188  bitcpy(dest, source.value[i], bit_difference, bits_per_T_val);
189  }
190  }
191  return bits;
192  }
193 
203  template <typename T_array, typename T_val, detail::requires_unsigned_type<T_val> * = nullptr>
204  CONSTEXPR_ABOVE_CPP11 size_t bitcpy(T_array *const dest, const sized_pointer<const T_val> &source, const size_t bit_offset = 0) noexcept
205  {
206  return bitcpy(dest, source, bit_offset, source.bit_capacity());
207  }
208 
219  template <typename T_array, typename T_val, detail::requires_large_non_integral_type<T_val> * = nullptr>
220  CONSTEXPR_ABOVE_CPP11_AND_NON_LITERAL_STORAGE size_t bitcpy(T_array *const dest, const T_val &source, const size_t bit_offset = 0, const size_t bits = detail::default_bitsize<T_val>::value) noexcept
221  {
222  const sized_pointer<const uint8_t> source_array(reinterpret_cast<const uint8_t *const>(&source), sizeof(T_val));
223  return bitcpy(dest, source_array, bit_offset, bits);
224  }
225 
235  template <typename T_array = void, typename T_val = void>
236  CONSTEXPR_ABOVE_CPP11 size_t bitcpy(sized_pointer<T_array> dest, const T_val &source, const size_t bit_offset = 0, const size_t bits = detail::default_bitsize<T_val>::value) noexcept
237  {
238  if (dest.bit_capacity() < (bits + bit_offset))
239  return 0;
240  return bitcpy(dest.value, source, bit_offset, bits);
241  }
242 
253  template <typename T_array, typename T_val>
254  size_t bitcpy(T_array *const dest, const std::atomic<T_val> &source, const size_t bit_offset = 0, const size_t bits = detail::default_bitsize<T_val>::value) noexcept
255  {
256  return bitcpy(dest, source.load(), bit_offset, bits);
257  }
258 
269  template <typename T_val>
270  CONSTEXPR_ABOVE_CPP11 size_t bitcpy(sized_pointer<void> &dest, const T_val &source, const size_t bit_offset = 0, const size_t bits = detail::default_bitsize<T_val>::value) noexcept
271  {
272  if (dest.bit_capacity() < (bits + bit_offset))
273  return 0;
274  switch (dest.element_size)
275  {
276  case 1:
277  return bitcpy(reinterpret_cast<uint8_t *>(dest.value), source, bit_offset, bits);
278  case 2:
279  return bitcpy(reinterpret_cast<uint16_t *>(dest.value), source, bit_offset, bits);
280  case 4:
281  return bitcpy(reinterpret_cast<uint32_t *>(dest.value), source, bit_offset, bits);
282  case 8:
283  return bitcpy(reinterpret_cast<uint64_t *>(dest.value), source, bit_offset, bits);
284  default:
285  break;
286  }
287  return 0;
288  }
289 }
290 
291 #endif // _BITCPY_TO_ARRAY_H_
Defines common bitcpy details as well as a info::version number, and bit_length function.
CppSerdes library namespace.
Definition: bitcpy_common.h:69
T_array *const value
the underlying pointer
Definition: bitcpy_sized_pointer.h:22
size_t bit_capacity() const noexcept
returns the number of bits in the array
Definition: bitcpy_sized_pointer.h:76
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
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
void *const value
the underlying pointer reinterpreted as a void* type
Definition: bitcpy_sized_pointer.h:51
size_t bit_capacity() const noexcept
returns the number of bits in the array
Definition: bitcpy_sized_pointer.h:39
Holds a pointer to an array (with its type information) with a constant size.
Definition: bitcpy_sized_pointer.h:19
Holds a pointer to a void array (with type information stored as a runtime element size paramenter) w...
Definition: bitcpy_sized_pointer.h:48
#define CONSTEXPR_ABOVE_CPP11
resolves automatically to "constexpr" if C++14 or greater
Definition: bitcpy_common.h:31
#define CONSTEXPR_ABOVE_CPP11_AND_NON_LITERAL_STORAGE
resolves automatically to "constexpr" if C++14 or greater
Definition: bitcpy_common.h:47