1 // Copyright (c) 2016-2020 Antony Polukhin
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 #ifndef BOOST_PFR_DETAIL_FUNCTIONAL_HPP
7 #define BOOST_PFR_DETAIL_FUNCTIONAL_HPP
10 #include <boost/pfr/detail/config.hpp>
14 #include <boost/pfr/detail/sequence_tuple.hpp>
16 namespace boost { namespace pfr { namespace detail {
17 template <std::size_t I, std::size_t N>
19 template <class T, class U>
20 constexpr static bool cmp(const T& v1, const U& v2) noexcept {
21 return ::boost::pfr::detail::sequence_tuple::get<I>(v1) == ::boost::pfr::detail::sequence_tuple::get<I>(v2)
22 && equal_impl<I + 1, N>::cmp(v1, v2);
26 template <std::size_t N>
27 struct equal_impl<N, N> {
28 template <class T, class U>
29 constexpr static bool cmp(const T&, const U&) noexcept {
30 return T::size_v == U::size_v;
34 template <std::size_t I, std::size_t N>
35 struct not_equal_impl {
36 template <class T, class U>
37 constexpr static bool cmp(const T& v1, const U& v2) noexcept {
38 return ::boost::pfr::detail::sequence_tuple::get<I>(v1) != ::boost::pfr::detail::sequence_tuple::get<I>(v2)
39 || not_equal_impl<I + 1, N>::cmp(v1, v2);
43 template <std::size_t N>
44 struct not_equal_impl<N, N> {
45 template <class T, class U>
46 constexpr static bool cmp(const T&, const U&) noexcept {
47 return T::size_v != U::size_v;
51 template <std::size_t I, std::size_t N>
53 template <class T, class U>
54 constexpr static bool cmp(const T& v1, const U& v2) noexcept {
55 return sequence_tuple::get<I>(v1) < sequence_tuple::get<I>(v2)
56 || (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && less_impl<I + 1, N>::cmp(v1, v2));
60 template <std::size_t N>
61 struct less_impl<N, N> {
62 template <class T, class U>
63 constexpr static bool cmp(const T&, const U&) noexcept {
64 return T::size_v < U::size_v;
68 template <std::size_t I, std::size_t N>
69 struct less_equal_impl {
70 template <class T, class U>
71 constexpr static bool cmp(const T& v1, const U& v2) noexcept {
72 return sequence_tuple::get<I>(v1) < sequence_tuple::get<I>(v2)
73 || (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && less_equal_impl<I + 1, N>::cmp(v1, v2));
77 template <std::size_t N>
78 struct less_equal_impl<N, N> {
79 template <class T, class U>
80 constexpr static bool cmp(const T&, const U&) noexcept {
81 return T::size_v <= U::size_v;
85 template <std::size_t I, std::size_t N>
87 template <class T, class U>
88 constexpr static bool cmp(const T& v1, const U& v2) noexcept {
89 return sequence_tuple::get<I>(v1) > sequence_tuple::get<I>(v2)
90 || (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && greater_impl<I + 1, N>::cmp(v1, v2));
94 template <std::size_t N>
95 struct greater_impl<N, N> {
96 template <class T, class U>
97 constexpr static bool cmp(const T&, const U&) noexcept {
98 return T::size_v > U::size_v;
102 template <std::size_t I, std::size_t N>
103 struct greater_equal_impl {
104 template <class T, class U>
105 constexpr static bool cmp(const T& v1, const U& v2) noexcept {
106 return sequence_tuple::get<I>(v1) > sequence_tuple::get<I>(v2)
107 || (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && greater_equal_impl<I + 1, N>::cmp(v1, v2));
111 template <std::size_t N>
112 struct greater_equal_impl<N, N> {
113 template <class T, class U>
114 constexpr static bool cmp(const T&, const U&) noexcept {
115 return T::size_v >= U::size_v;
119 template <typename SizeT>
120 constexpr void hash_combine(SizeT& seed, SizeT value) noexcept {
121 seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
124 template <typename T>
125 auto compute_hash(const T& value, long /*priority*/)
126 -> decltype(std::hash<T>()(value))
128 return std::hash<T>()(value);
131 template <typename T>
132 std::size_t compute_hash(const T& /*value*/, int /*priority*/) {
133 static_assert(sizeof(T) && false, "====================> Boost.PFR: std::hash not specialized for type T");
137 template <std::size_t I, std::size_t N>
140 constexpr static std::size_t compute(const T& val) noexcept {
141 std::size_t h = detail::compute_hash( ::boost::pfr::detail::sequence_tuple::get<I>(val), 1L );
142 detail::hash_combine(h, hash_impl<I + 1, N>::compute(val) );
147 template <std::size_t N>
148 struct hash_impl<N, N> {
150 constexpr static std::size_t compute(const T&) noexcept {
155 ///////////////////// Define min_element and to avoid inclusion of <algorithm>
156 constexpr std::size_t min_size(std::size_t x, std::size_t y) noexcept {
157 return x < y ? x : y;
160 template <template <std::size_t, std::size_t> class Visitor, class T, class U>
161 bool binary_visit(const T& x, const U& y) {
162 constexpr std::size_t fields_count_lhs = detail::fields_count<std::remove_reference_t<T>>();
163 constexpr std::size_t fields_count_rhs = detail::fields_count<std::remove_reference_t<U>>();
164 constexpr std::size_t fields_count_min = detail::min_size(fields_count_lhs, fields_count_rhs);
165 typedef Visitor<0, fields_count_min> visitor_t;
167 #if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
168 return visitor_t::cmp(detail::tie_as_tuple(x), detail::tie_as_tuple(y));
171 ::boost::pfr::detail::for_each_field_dispatcher(
173 [&result, &y](const auto& lhs) {
174 ::boost::pfr::detail::for_each_field_dispatcher(
176 [&result, &lhs](const auto& rhs) {
177 result = visitor_t::cmp(lhs, rhs);
179 detail::make_index_sequence<fields_count_rhs>{}
182 detail::make_index_sequence<fields_count_lhs>{}
189 }}} // namespace boost::pfr::detail
191 #endif // BOOST_PFR_DETAIL_FUNCTIONAL_HPP