2
0
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:
Antony Polukhin
2016-12-28 22:16:22 +03:00
parent bc849f583e
commit 63a41e0256
5 changed files with 107 additions and 103 deletions

View 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

View File

@@ -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.

View File

@@ -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
}
};

View File

@@ -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

View File

@@ -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 ]