From 63a41e02565c8dd93f1bcb73466dbb1461d604a8 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 28 Dec 2016 22:16:22 +0300 Subject: [PATCH] Cleanup code and fix hash functor --- .../pfr/detail/cast_to_layout_compatible.hpp | 78 +++++++++++++ include/boost/pfr/detail/core14.hpp | 108 ++---------------- include/boost/pfr/precise/functors.hpp | 18 ++- misc/generate_single.sh | 4 - test/Jamfile.v2 | 2 +- 5 files changed, 107 insertions(+), 103 deletions(-) create mode 100644 include/boost/pfr/detail/cast_to_layout_compatible.hpp delete mode 100644 misc/generate_single.sh diff --git a/include/boost/pfr/detail/cast_to_layout_compatible.hpp b/include/boost/pfr/detail/cast_to_layout_compatible.hpp new file mode 100644 index 0000000..fb92f04 --- /dev/null +++ b/include/boost/pfr/detail/cast_to_layout_compatible.hpp @@ -0,0 +1,78 @@ +// Copyright (c) 2016 Antony Polukhin +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PFR_DETAIL_cast_to_layout_compatible_HPP +#define BOOST_PFR_DETAIL_cast_to_layout_compatible_HPP + +#if __cplusplus < 201402L +# error C++14 is required for this header. +#endif + +#include +#include // metaprogramming stuff + +namespace boost { namespace pfr { namespace detail { + +template +constexpr void static_assert_layout_compatible() noexcept { + static_assert( + std::alignment_of::value == std::alignment_of::value, + "Alignment check failed, probably your structure has user-defined alignment for the whole structure or for some of the fields." + ); + static_assert(sizeof(T) == sizeof(U), "Size check failed, probably your structure has bitfields or user-defined alignment."); +} + +/// @cond +#ifdef __GNUC__ +#define MAY_ALIAS __attribute__((__may_alias__)) +#else +#define MAY_ALIAS +#endif +/// @endcond + +template +MAY_ALIAS const To& cast_to_layout_compatible(const From& val) noexcept { + MAY_ALIAS const To* const t = reinterpret_cast( std::addressof(val) ); + static_assert_layout_compatible(); + return *t; +} + +template +MAY_ALIAS const volatile To& cast_to_layout_compatible(const volatile From& val) noexcept { + MAY_ALIAS const volatile To* const t = reinterpret_cast( std::addressof(val) ); + static_assert_layout_compatible(); + return *t; +} + + +template +MAY_ALIAS volatile To& cast_to_layout_compatible(volatile From& val) noexcept { + MAY_ALIAS volatile To* const t = reinterpret_cast( std::addressof(val) ); + static_assert_layout_compatible(); + return *t; +} + + + +template +MAY_ALIAS To& cast_to_layout_compatible(From& val) noexcept { + MAY_ALIAS To* const t = reinterpret_cast( std::addressof(val) ); + static_assert_layout_compatible(); + return *t; +} +/* +template +MAY_ALIAS std::enable_if_t::value, To&&> cast_to_layout_compatible(From&& val) noexcept { + MAY_ALIAS To* const t = reinterpret_cast( std::addressof(val) ); + static_assert_layout_compatible(); + return std::move(*t); +}*/ + +#undef MAY_ALIAS + + +}}} // namespace boost::pfr::detail + +#endif // BOOST_PFR_DETAIL_cast_to_layout_compatible_HPP diff --git a/include/boost/pfr/detail/core14.hpp b/include/boost/pfr/detail/core14.hpp index 7b1b979..ba7bb98 100644 --- a/include/boost/pfr/detail/core14.hpp +++ b/include/boost/pfr/detail/core14.hpp @@ -14,6 +14,7 @@ #include // metaprogramming stuff #include +#include #include #include @@ -544,25 +545,12 @@ template constexpr auto internal_tuple_with_same_alignment() noexcept { typedef typename std::remove_cv::type type; - -#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT - static_assert(std::is_standard_layout::value, "Not applyable"); - static_assert(std::is_move_constructible::value || std::is_array::value, "Not applyable"); -#else - static_assert(std::is_pod::value, "Not applyable"); -#endif - + static_assert(std::is_pod::value, "Type can not be used is flat_ functions, because it's not POD"); static_assert(!std::is_reference::value, "Not applyable"); constexpr auto res = as_flat_tuple_impl( std::make_index_sequence< decltype(flat_array_of_type_ids())::size() >() ); - static_assert( - std::alignment_of::value == std::alignment_of::value, - "Alignment check failed, probably your structure has user-defined alignment for the whole structure or for some of the fields." - ); - static_assert(sizeof(res) == sizeof(type), "Size check failed, probably your structure has bitfields or user-defined alignment."); - return res; } @@ -658,85 +646,22 @@ constexpr bool is_flat_refelectable(std::index_sequence) noexcept { return true; } - -/// @cond -#ifdef __GNUC__ -#define MAY_ALIAS __attribute__((__may_alias__)) -#else -#define MAY_ALIAS -#endif -/// @endcond - template -decltype(auto) tie_as_flat_tuple(const T& val) noexcept { - MAY_ALIAS const auto* const t = reinterpret_cast*>( std::addressof(val) ); - return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_::size_v>{}); +decltype(auto) tie_as_flat_tuple(T&& val) noexcept { + typedef internal_tuple_with_same_alignment_t> tuple_type; + auto&& t = cast_to_layout_compatible(std::forward(val)); + return make_flat_tuple_of_references(std::forward(t), size_t_<0>{}, size_t_{}); } template -decltype(auto) tie_as_flat_tuple(const volatile T& val) noexcept { - MAY_ALIAS const volatile auto* const t = reinterpret_cast*>( std::addressof(val) ); - return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_::size_v>{}); -} - -template -decltype(auto) tie_as_flat_tuple(volatile T& val) noexcept { - MAY_ALIAS volatile auto* const t = reinterpret_cast*>( std::addressof(val) ); - return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_::size_v>{}); -} - -template -decltype(auto) tie_as_flat_tuple(T& val) noexcept { - MAY_ALIAS auto* const t = reinterpret_cast*>( std::addressof(val) ); - return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_::size_v>{}); -} - - - - - - -template -decltype(auto) as_tuple(const T& val) noexcept { +decltype(auto) as_tuple(T&& val) noexcept { static_assert( is_flat_refelectable( std::make_index_sequence()>{} ), "Not possible in C++14 to represent that type without loosing information. Use flat_ version or change type definition" ); - MAY_ALIAS const auto* const t = reinterpret_cast*>( std::addressof(val) ); - return *t; + return tie_as_flat_tuple(std::forward(val)); } -template -decltype(auto) as_tuple(const volatile T& val) noexcept { - static_assert( - is_flat_refelectable( std::make_index_sequence()>{} ), - "Not possible in C++14 to represent that type without loosing information. Use flat_ version or change type definition" - ); - MAY_ALIAS const volatile auto* const t = reinterpret_cast*>( std::addressof(val) ); - return *t; -} - -template -decltype(auto) as_tuple(volatile T& val) noexcept { - static_assert( - is_flat_refelectable( std::make_index_sequence()>{} ), - "Not possible in C++14 to represent that type without loosing information. Use flat_ version or change type definition" - ); - MAY_ALIAS volatile auto* const t = reinterpret_cast*>( std::addressof(val) ); - return *t; -} - -template -decltype(auto) as_tuple(T& val) noexcept { - static_assert( - is_flat_refelectable( std::make_index_sequence()>{} ), - "Not possible in C++14 to represent that type without loosing information. Use flat_ version or change type definition" - ); - MAY_ALIAS auto* const t = reinterpret_cast*>( std::addressof(val) ); - return *t; -} - - template using as_tuple_t = decltype( ::boost::pfr::detail::as_tuple(std::declval()) ); @@ -800,22 +725,13 @@ void for_each_field_in_depth(T&& t, F&& f, std::index_sequence, identi } template -void for_each_field_in_depth(const T& t, F&& f, std::index_sequence<>, identity...) { - MAY_ALIAS const auto* const tuple = reinterpret_cast< ::boost::pfr::detail::sequence_tuple::tupleconst *>(std::addressof(t)); +void for_each_field_in_depth(T&& t, F&& f, std::index_sequence<>, identity...) { + auto&& tuple = cast_to_layout_compatible< ::boost::pfr::detail::sequence_tuple::tuple >(std::forward(t)); std::forward(f)( - make_flat_tuple_of_references(*tuple, size_t_<0>{}, size_t_{}) + make_flat_tuple_of_references(std::forward(tuple), size_t_<0>{}, size_t_{}) ); } -template -void for_each_field_in_depth(T& t, F&& f, std::index_sequence<>, identity...) { - MAY_ALIAS auto* const tuple = reinterpret_cast< ::boost::pfr::detail::sequence_tuple::tuple*>(std::addressof(t)); - std::forward(f)( - make_flat_tuple_of_references(*tuple, size_t_<0>{}, size_t_{}) - ); -} - - template void for_each_field_dispatcher_1(T&& t, F&& f, std::index_sequence, std::true_type /*is_flat_refelectable*/) { std::forward(f)( @@ -837,7 +753,7 @@ template void for_each_field_dispatcher(T&& t, F&& f, std::index_sequence) { typedef std::remove_reference_t type; - /// Compile time error at this point means that you have called `for_each_field` for a + /// Compile time error at this point means that you have called `for_each_field` or some other non-flat function or operator for a /// type that is not constexpr aggregate initializable. /// /// Make sure that all the fields of your type have constexpr default construtors and trivial destructors. diff --git a/include/boost/pfr/precise/functors.hpp b/include/boost/pfr/precise/functors.hpp index d497010..9af2e48 100644 --- a/include/boost/pfr/precise/functors.hpp +++ b/include/boost/pfr/precise/functors.hpp @@ -229,8 +229,22 @@ template <> struct less_equal { /// \brief std::hash like functor template struct hash { /// \return hash value of \b x - std::size_t operator()(const T& x) const noexcept { - return detail::hash_impl<0, detail::fields_count>() >::compute(detail::as_tuple(x)); + std::size_t operator()(const T& x) const { + constexpr std::size_t fields_count = detail::fields_count>(); +#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */ + return detail::hash_impl<0, fields_count>::compute(detail::as_tuple(x)); +#else + std::size_t result = 0; + ::boost::pfr::detail::for_each_field_dispatcher( + x, + [&result](const auto& lhs) { + result = detail::hash_impl<0, fields_count>::compute(lhs); + }, + std::make_index_sequence{} + ); + + return result; +#endif } }; diff --git a/misc/generate_single.sh b/misc/generate_single.sh deleted file mode 100644 index f87105a..0000000 --- a/misc/generate_single.sh +++ /dev/null @@ -1,4 +0,0 @@ -cat ../include/boost/pfr/core.hpp -sed -e '1,/boost\/pfr/d' ../include/boost/pfr/functors.hpp -sed -e '1,/boost\/pfr/d' ../include/boost/pfr/flat_functions_for.hpp -sed -e '1,/boost\/pfr/d' ../include/boost/pfr/flat_ops.hpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 624557a..946c3ab 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -31,7 +31,7 @@ test-suite pfr [ run precise/tuple_size.cpp : : : : precise_tuple_size ] [ run precise/bitfields.cpp : : : : precise_tuple_size_on_bitfields ] [ run precise/for_each_field.cpp : : : : precise_for_each_field ] - #[ run precise/motivating_example.cpp : : : : precise_motivating_example ] + [ run precise/motivating_example.cpp : : : : precise_motivating_example ] [ compile-fail precise/non_aggregate.cpp : : precise_non_aggregate ] [ run ../example/examples.cpp ]