1 #ifndef _BITCPY_TO_ARRAY_H_
9 #define _BITCPY_TO_ARRAY_H_
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
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;
35 if (bits == bits_per_T_array && bit_offset_from_start_index == 0)
37 dest[array_write_index] = source;
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)
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];
52 dest_array_element &= ~(unaligned_mask << alignment_shift);
55 dest_array_element |=
static_cast<T_array
>(source & unaligned_mask) << alignment_shift;
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;
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;
69 for (
size_t i = 1u; i < num_array_elements_touched - 1u; i++)
72 bits_remaining -= bits_per_T_array;
73 dest[array_write_index] =
static_cast<T_array
>(source >> bits_remaining);
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;
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
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;
106 dest[array_index] |= bit_mask;
108 dest[array_index] &= ~bit_mask;
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);
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
128 #ifdef configCPP_SERDES_ALLOW_REINTERPRET_BUILTINS_UB
129 return bitcpy(dest, detail::reinterpret_as_unsigned(source), bit_offset, bits);
131 typename detail::unsigned_type_sizeof<
sizeof(T_val)>::type source_copy;
132 std::memcpy(&source_copy, &source,
sizeof(T_val));
133 return bitcpy(dest, source_copy, bit_offset, bits);
147 template <
typename T_array,
typename T_val, detail::requires_
signed_type<T_val> * =
nullptr>
148 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
150 #ifdef configCPP_SERDES_ALLOW_REINTERPRET_BUILTINS_UB
151 return bitcpy(dest, detail::reinterpret_as_unsigned(source), bit_offset, bits);
153 typename detail::unsigned_type_sizeof<
sizeof(T_val)>::type source_copy;
154 std::memcpy(&source_copy, &source,
sizeof(T_val));
155 return bitcpy(dest, source_copy, bit_offset, bits);
170 template <
typename T_array,
typename T_val, detail::requires_
unsigned_type<T_val> * =
nullptr>
173 constexpr
size_t bits_per_T_val =
sizeof(T_val) * 8;
174 const size_t total_bits_T_val = bits_per_T_val * source.size;
175 if (bits == total_bits_T_val)
177 for (
size_t i = 0; i < source.size; i++)
178 bitcpy(dest, source.value[i], bit_offset + i * bits_per_T_val, bits_per_T_val);
180 else if (bits < total_bits_T_val)
182 const size_t bit_difference = total_bits_T_val - bits;
183 const size_t starting_source_word = bit_difference / bits_per_T_val;
184 const size_t last_bit_index = source.size - 1u;
185 const size_t last_bit_suboffset = bits_per_T_val * last_bit_index - bit_difference;
186 const size_t remainder_bits = bits - last_bit_suboffset;
187 const std::make_signed<size_t>::type offset_per_loop = bit_offset - bit_difference;
188 for (
size_t i = starting_source_word; i < source.size - 1u; i++)
189 bitcpy(dest, source.value[i], offset_per_loop + i * bits_per_T_val, bits_per_T_val);
190 bitcpy(dest, source.value[last_bit_index], bit_offset + last_bit_suboffset, remainder_bits);
194 size_t bit_difference = bits - total_bits_T_val;
195 bitcpy(dest, source.value[0], bit_offset, bits_per_T_val + bit_difference);
196 bit_difference += bit_offset;
197 for (
size_t i = 1; i < source.size; i++)
199 bit_difference += bits_per_T_val;
200 bitcpy(dest, source.value[i], bit_difference, bits_per_T_val);
215 template <
typename T_array,
typename T_val, detail::requires_
unsigned_type<T_val> * =
nullptr>
231 template <
typename T_array,
typename T_val, detail::requires_large_non_
integral_type<T_val> * =
nullptr>
235 return bitcpy(dest, source_array, bit_offset, bits);
247 template <
typename T_array =
void,
typename T_val =
void>
250 if (dest.bit_capacity() < (bits + bit_offset))
252 return bitcpy(dest.value, source, bit_offset, bits);
267 template <
typename T_array,
typename T_val,
template<
typename>
class T_wrap, detail::requires_load_and_store_of_builtin<T_wrap<T_val>> * =
nullptr>
268 size_t bitcpy(T_array *
const dest,
const T_wrap<T_val> &source,
const size_t bit_offset = 0,
const size_t bits = detail::default_bitsize<T_val>::value) noexcept
270 return bitcpy(dest, source.load(), bit_offset, bits);
283 template <
typename T_val>
286 if (dest.bit_capacity() < (bits + bit_offset))
288 switch (dest.element_size)
291 return bitcpy(
reinterpret_cast<uint8_t *
>(dest.value), source, bit_offset, bits);
293 return bitcpy(
reinterpret_cast<uint16_t *
>(dest.value), source, bit_offset, bits);
295 return bitcpy(
reinterpret_cast<uint32_t *
>(dest.value), source, bit_offset, bits);
297 return bitcpy(
reinterpret_cast<uint64_t *
>(dest.value), source, bit_offset, bits);
305 #endif // _BITCPY_TO_ARRAY_H_