diff --git a/include/utils/unaligned.h b/include/utils/unaligned.h index 626275b..8bff10d 100644 --- a/include/utils/unaligned.h +++ b/include/utils/unaligned.h @@ -62,12 +62,17 @@ namespace detail [[nodiscard, gnu::always_inline]] inline constexpr output_type unaligned_load(iterator it) noexcept { - using tmp_value_type = iterator_value_type_t; - static_assert(sizeof(tmp_value_type) == 1); + using input_value_type = std::iter_value_t; + static_assert(sizeof(input_value_type) == 1); - std::aligned_storage_t tmp_store; - std::copy_n(it, sizeof(output_type), std::launder(reinterpret_cast(&tmp_store))); - return *std::launder(reinterpret_cast(&tmp_store)); + struct value_buffer_type + { + std::array buffer; + }; + + value_buffer_type store; + std::copy_n(it, sizeof(output_type), store.buffer.begin()); + return cxx20::bit_cast(store); } ///\brief loads value from any untyped pointer memory location @@ -81,7 +86,7 @@ namespace detail //--------------------------------------------------------------------------------------------------- ///\brief loads value from any forward iterator or unaligned memory location -template +template [[nodiscard, gnu::always_inline]] inline constexpr output_type unaligned_load(iterator it) noexcept { @@ -92,7 +97,7 @@ inline constexpr output_type unaligned_load(iterator it) noexcept ///\details specifing expected_storage_size prevents unintended breaking changes with IO to trivially_copyable /// underlaing type template - requires(!detail::arithmetic_or_bool && expected_storage_size == sizeof(output_type)) + requires(expected_storage_size == sizeof(output_type)) [[nodiscard, gnu::always_inline]] inline constexpr output_type unaligned_load(iterator it) noexcept { @@ -104,7 +109,7 @@ inline constexpr output_type unaligned_load(iterator it) noexcept /// size of output_type and forwards the \ref it by the size was read \warning be aware that this function is prone to /// bugs when used in context of order of evaluation is unspecified, dont use it as function arguments, constructors /// because \ref it is modified when evaluated -template +template [[nodiscard, gnu::always_inline]] inline constexpr output_type unaligned_load_fwd(iterator & it) noexcept { @@ -128,17 +133,38 @@ inline constexpr output_type unaligned_load_fwd(iterator & it) noexcept } //--------------------------------------------------------------------------------------------------- +namespace detail + { + template< + detail::trivially_copyable store_type, + detail::output_iterator_to_byte iterator, + detail::trivially_copyable input_type> + requires(std::same_as) + [[gnu::always_inline]] + inline constexpr iterator unaligned_store(iterator it, input_type value) noexcept + { + using output_range_type = std::iter_value_t; + + struct value_buffer_type + { + std::array buffer; + }; + + value_buffer_type store = cxx20::bit_cast(value); + return std::copy(store.buffer.begin(), store.buffer.end(), it); + } + } // namespace detail + ///\brief stores \param value at \param it location, input value type must match requested storage type template< - detail::arithmetic_or_bool store_type, + detail::trivially_copyable store_type, detail::output_iterator_to_byte iterator, - detail::arithmetic_or_bool input_type> + detail::trivially_copyable input_type> requires(std::same_as) [[gnu::always_inline]] inline constexpr iterator unaligned_store(iterator it, input_type value) noexcept { - using output_range_type = std::iter_value_t; - return std::copy_n(std::launder(reinterpret_cast(&value)), sizeof(store_type), it); + return detail::unaligned_store(it, value); } ///\brief stores \param value at \param it location, input value type must match requested storage type @@ -147,12 +173,11 @@ template< std::size_t expected_storage_size, detail::output_iterator_to_byte iterator, detail::trivially_copyable input_type> - requires(std::same_as && expected_storage_size == sizeof(store_type) && !detail::arithmetic_or_bool) + requires(std::same_as && expected_storage_size == sizeof(store_type)) [[gnu::always_inline]] inline constexpr iterator unaligned_store(iterator it, input_type value) noexcept { - using output_range_type = std::iter_value_t; - return std::copy_n(std::launder(reinterpret_cast(&value)), sizeof(store_type), it); + return detail::unaligned_store(it, value); } //--------------------------------------------------------------------------------------------------- diff --git a/unit_tests/unaligned_ut.cc b/unit_tests/unaligned_ut.cc index cf876f1..452cb4f 100644 --- a/unit_tests/unaligned_ut.cc +++ b/unit_tests/unaligned_ut.cc @@ -13,7 +13,7 @@ int main() metatests::test_result result; - "test int"_test = [&] + "test_int"_test = [&] { auto fn_tmpl = [](value_type const *) -> metatests::test_result { @@ -27,6 +27,7 @@ int main() return {}; }; result |= run_constexpr_test(fn_tmpl); + result |= run_consteval_test(fn_tmpl); }; "test double"_test = [&] @@ -38,10 +39,11 @@ int main() type testv = 0.45671974353; unaligned_store(&store[1], testv); type r = unaligned_load(&store[1]); - expect(r == testv); + constexpr_test(r == testv); return {}; }; result |= run_constexpr_test(fn_tmpl); + result |= run_consteval_test(fn_tmpl); }; "test int64_t"_test = [&] @@ -54,30 +56,41 @@ int main() unaligned_store(&store[1], testv); type r = unaligned_load(&store[1]); - expect(r == testv); + constexpr_test(r == testv); return {}; }; result |= run_constexpr_test(fn_tmpl); + result |= run_consteval_test(fn_tmpl); }; "test enum"_test = [&] { + enum struct test_enum : uint16_t + { + one, + two, + three + }; auto fn_tmpl = [](value_type const *) -> metatests::test_result { value_type store[128]; - enum struct test_enum : uint16_t - { - one, - two, - three - }; + using type = test_enum; - type testv = test_enum::two; - unaligned_store(&store[3], testv); - type r = unaligned_load(&store[3]); - expect(r == testv); + { + type testv = test_enum::three; + unaligned_store(&store[3], testv); + type r = unaligned_load(&store[3]); + constexpr_test(r == testv); + } + { + type testv = test_enum::two; + unaligned_store(&store[3], testv); + type r = unaligned_load(&store[3]); + constexpr_test(r == testv); + } return {}; }; result |= run_constexpr_test(fn_tmpl); + result |= run_consteval_test(fn_tmpl); }; }