mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-19 04:22:13 +00:00
Cleanup code and fix hash functor
This commit is contained in:
78
include/boost/pfr/detail/cast_to_layout_compatible.hpp
Normal file
78
include/boost/pfr/detail/cast_to_layout_compatible.hpp
Normal file
@@ -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 <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
constexpr void static_assert_layout_compatible() noexcept {
|
||||
static_assert(
|
||||
std::alignment_of<T>::value == std::alignment_of<U>::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 <class To, class From>
|
||||
MAY_ALIAS const To& cast_to_layout_compatible(const From& val) noexcept {
|
||||
MAY_ALIAS const To* const t = reinterpret_cast<const To*>( std::addressof(val) );
|
||||
static_assert_layout_compatible<To, From>();
|
||||
return *t;
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
MAY_ALIAS const volatile To& cast_to_layout_compatible(const volatile From& val) noexcept {
|
||||
MAY_ALIAS const volatile To* const t = reinterpret_cast<const volatile To*>( std::addressof(val) );
|
||||
static_assert_layout_compatible<To, From>();
|
||||
return *t;
|
||||
}
|
||||
|
||||
|
||||
template <class To, class From>
|
||||
MAY_ALIAS volatile To& cast_to_layout_compatible(volatile From& val) noexcept {
|
||||
MAY_ALIAS volatile To* const t = reinterpret_cast<volatile To*>( std::addressof(val) );
|
||||
static_assert_layout_compatible<To, From>();
|
||||
return *t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class To, class From>
|
||||
MAY_ALIAS To& cast_to_layout_compatible(From& val) noexcept {
|
||||
MAY_ALIAS To* const t = reinterpret_cast<To*>( std::addressof(val) );
|
||||
static_assert_layout_compatible<To, From>();
|
||||
return *t;
|
||||
}
|
||||
/*
|
||||
template <class To, class From>
|
||||
MAY_ALIAS std::enable_if_t<std::is_rvalue_reference<From&&>::value, To&&> cast_to_layout_compatible(From&& val) noexcept {
|
||||
MAY_ALIAS To* const t = reinterpret_cast<To*>( std::addressof(val) );
|
||||
static_assert_layout_compatible<To, From>();
|
||||
return std::move(*t);
|
||||
}*/
|
||||
|
||||
#undef MAY_ALIAS
|
||||
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_cast_to_layout_compatible_HPP
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/cast_to_layout_compatible.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/for_each_field_impl.hpp>
|
||||
|
||||
@@ -544,25 +545,12 @@ template <class T>
|
||||
constexpr auto internal_tuple_with_same_alignment() noexcept {
|
||||
typedef typename std::remove_cv<T>::type type;
|
||||
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
static_assert(std::is_standard_layout<type>::value, "Not applyable");
|
||||
static_assert(std::is_move_constructible<type>::value || std::is_array<type>::value, "Not applyable");
|
||||
#else
|
||||
static_assert(std::is_pod<type>::value, "Not applyable");
|
||||
#endif
|
||||
|
||||
static_assert(std::is_pod<type>::value, "Type can not be used is flat_ functions, because it's not POD");
|
||||
static_assert(!std::is_reference<type>::value, "Not applyable");
|
||||
constexpr auto res = as_flat_tuple_impl<type>(
|
||||
std::make_index_sequence< decltype(flat_array_of_type_ids<type>())::size() >()
|
||||
);
|
||||
|
||||
static_assert(
|
||||
std::alignment_of<decltype(res)>::value == std::alignment_of<type>::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<I...>) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// @cond
|
||||
#ifdef __GNUC__
|
||||
#define MAY_ALIAS __attribute__((__may_alias__))
|
||||
#else
|
||||
#define MAY_ALIAS
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
template <class T>
|
||||
decltype(auto) tie_as_flat_tuple(const T& val) noexcept {
|
||||
MAY_ALIAS const auto* const t = reinterpret_cast<const internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_<detail::internal_tuple_with_same_alignment_t<T>::size_v>{});
|
||||
decltype(auto) tie_as_flat_tuple(T&& val) noexcept {
|
||||
typedef internal_tuple_with_same_alignment_t<std::remove_reference_t<T>> tuple_type;
|
||||
auto&& t = cast_to_layout_compatible<tuple_type>(std::forward<T>(val));
|
||||
return make_flat_tuple_of_references(std::forward<decltype(t)>(t), size_t_<0>{}, size_t_<tuple_type::size_v>{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) tie_as_flat_tuple(const volatile T& val) noexcept {
|
||||
MAY_ALIAS const volatile auto* const t = reinterpret_cast<const volatile internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_<detail::internal_tuple_with_same_alignment_t<T>::size_v>{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) tie_as_flat_tuple(volatile T& val) noexcept {
|
||||
MAY_ALIAS volatile auto* const t = reinterpret_cast<volatile internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_<detail::internal_tuple_with_same_alignment_t<T>::size_v>{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) tie_as_flat_tuple(T& val) noexcept {
|
||||
MAY_ALIAS auto* const t = reinterpret_cast<internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_<detail::internal_tuple_with_same_alignment_t<T>::size_v>{});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
decltype(auto) as_tuple(const T& val) noexcept {
|
||||
decltype(auto) as_tuple(T&& val) noexcept {
|
||||
static_assert(
|
||||
is_flat_refelectable<T>( std::make_index_sequence<fields_count<T>()>{} ),
|
||||
"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<const internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return *t;
|
||||
return tie_as_flat_tuple(std::forward<T>(val));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) as_tuple(const volatile T& val) noexcept {
|
||||
static_assert(
|
||||
is_flat_refelectable<T>( std::make_index_sequence<fields_count<T>()>{} ),
|
||||
"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<const volatile internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return *t;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) as_tuple(volatile T& val) noexcept {
|
||||
static_assert(
|
||||
is_flat_refelectable<T>( std::make_index_sequence<fields_count<T>()>{} ),
|
||||
"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<volatile internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return *t;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) as_tuple(T& val) noexcept {
|
||||
static_assert(
|
||||
is_flat_refelectable<T>( std::make_index_sequence<fields_count<T>()>{} ),
|
||||
"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<internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return *t;
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
using as_tuple_t = decltype( ::boost::pfr::detail::as_tuple(std::declval<T&>()) );
|
||||
|
||||
@@ -800,22 +725,13 @@ void for_each_field_in_depth(T&& t, F&& f, std::index_sequence<I0, I...>, identi
|
||||
}
|
||||
|
||||
template <class T, class F, class... Fields>
|
||||
void for_each_field_in_depth(const T& t, F&& f, std::index_sequence<>, identity<Fields>...) {
|
||||
MAY_ALIAS const auto* const tuple = reinterpret_cast< ::boost::pfr::detail::sequence_tuple::tuple<Fields...>const *>(std::addressof(t));
|
||||
void for_each_field_in_depth(T&& t, F&& f, std::index_sequence<>, identity<Fields>...) {
|
||||
auto&& tuple = cast_to_layout_compatible< ::boost::pfr::detail::sequence_tuple::tuple<Fields...> >(std::forward<T>(t));
|
||||
std::forward<F>(f)(
|
||||
make_flat_tuple_of_references(*tuple, size_t_<0>{}, size_t_<sizeof...(Fields)>{})
|
||||
make_flat_tuple_of_references(std::forward<decltype(tuple)>(tuple), size_t_<0>{}, size_t_<sizeof...(Fields)>{})
|
||||
);
|
||||
}
|
||||
|
||||
template <class T, class F, class... Fields>
|
||||
void for_each_field_in_depth(T& t, F&& f, std::index_sequence<>, identity<Fields>...) {
|
||||
MAY_ALIAS auto* const tuple = reinterpret_cast< ::boost::pfr::detail::sequence_tuple::tuple<Fields...>*>(std::addressof(t));
|
||||
std::forward<F>(f)(
|
||||
make_flat_tuple_of_references(*tuple, size_t_<0>{}, size_t_<sizeof...(Fields)>{})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template <class T, class F, std::size_t... I>
|
||||
void for_each_field_dispatcher_1(T&& t, F&& f, std::index_sequence<I...>, std::true_type /*is_flat_refelectable*/) {
|
||||
std::forward<F>(f)(
|
||||
@@ -837,7 +753,7 @@ template <class T, class F, std::size_t... I>
|
||||
void for_each_field_dispatcher(T&& t, F&& f, std::index_sequence<I...>) {
|
||||
typedef std::remove_reference_t<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.
|
||||
|
||||
@@ -229,8 +229,22 @@ template <> struct less_equal<void> {
|
||||
/// \brief std::hash like functor
|
||||
template <class T> 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<std::remove_reference_t<T>>() >::compute(detail::as_tuple(x));
|
||||
std::size_t operator()(const T& x) const {
|
||||
constexpr std::size_t fields_count = detail::fields_count<std::remove_reference_t<T>>();
|
||||
#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<fields_count>{}
|
||||
);
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 ]
|
||||
|
||||
Reference in New Issue
Block a user