functional.hpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // Copyright (c) 2016-2025 Antony Polukhin
  2. //
  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)
  5. #ifndef BOOST_PFR_DETAIL_FUNCTIONAL_HPP
  6. #define BOOST_PFR_DETAIL_FUNCTIONAL_HPP
  7. #pragma once
  8. #include <boost/pfr/detail/config.hpp>
  9. #include <boost/pfr/detail/sequence_tuple.hpp>
  10. #if !defined(BOOST_PFR_INTERFACE_UNIT)
  11. #include <cstdint>
  12. #include <functional>
  13. #endif
  14. namespace boost { namespace pfr { namespace detail {
  15. template <std::size_t I, std::size_t N>
  16. struct equal_impl {
  17. template <class T, class U>
  18. constexpr static bool cmp(const T& v1, const U& v2) noexcept {
  19. return ::boost::pfr::detail::sequence_tuple::get<I>(v1) == ::boost::pfr::detail::sequence_tuple::get<I>(v2)
  20. && equal_impl<I + 1, N>::cmp(v1, v2);
  21. }
  22. };
  23. template <std::size_t N>
  24. struct equal_impl<N, N> {
  25. template <class T, class U>
  26. constexpr static bool cmp(const T&, const U&) noexcept {
  27. return T::size_v == U::size_v;
  28. }
  29. };
  30. template <std::size_t I, std::size_t N>
  31. struct not_equal_impl {
  32. template <class T, class U>
  33. constexpr static bool cmp(const T& v1, const U& v2) noexcept {
  34. return ::boost::pfr::detail::sequence_tuple::get<I>(v1) != ::boost::pfr::detail::sequence_tuple::get<I>(v2)
  35. || not_equal_impl<I + 1, N>::cmp(v1, v2);
  36. }
  37. };
  38. template <std::size_t N>
  39. struct not_equal_impl<N, N> {
  40. template <class T, class U>
  41. constexpr static bool cmp(const T&, const U&) noexcept {
  42. return T::size_v != U::size_v;
  43. }
  44. };
  45. template <std::size_t I, std::size_t N>
  46. struct less_impl {
  47. template <class T, class U>
  48. constexpr static bool cmp(const T& v1, const U& v2) noexcept {
  49. return sequence_tuple::get<I>(v1) < sequence_tuple::get<I>(v2)
  50. || (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && less_impl<I + 1, N>::cmp(v1, v2));
  51. }
  52. };
  53. template <std::size_t N>
  54. struct less_impl<N, N> {
  55. template <class T, class U>
  56. constexpr static bool cmp(const T&, const U&) noexcept {
  57. return T::size_v < U::size_v;
  58. }
  59. };
  60. template <std::size_t I, std::size_t N>
  61. struct less_equal_impl {
  62. template <class T, class U>
  63. constexpr static bool cmp(const T& v1, const U& v2) noexcept {
  64. return sequence_tuple::get<I>(v1) < sequence_tuple::get<I>(v2)
  65. || (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && less_equal_impl<I + 1, N>::cmp(v1, v2));
  66. }
  67. };
  68. template <std::size_t N>
  69. struct less_equal_impl<N, N> {
  70. template <class T, class U>
  71. constexpr static bool cmp(const T&, const U&) noexcept {
  72. return T::size_v <= U::size_v;
  73. }
  74. };
  75. template <std::size_t I, std::size_t N>
  76. struct greater_impl {
  77. template <class T, class U>
  78. constexpr static bool cmp(const T& v1, const U& v2) noexcept {
  79. return sequence_tuple::get<I>(v1) > sequence_tuple::get<I>(v2)
  80. || (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && greater_impl<I + 1, N>::cmp(v1, v2));
  81. }
  82. };
  83. template <std::size_t N>
  84. struct greater_impl<N, N> {
  85. template <class T, class U>
  86. constexpr static bool cmp(const T&, const U&) noexcept {
  87. return T::size_v > U::size_v;
  88. }
  89. };
  90. template <std::size_t I, std::size_t N>
  91. struct greater_equal_impl {
  92. template <class T, class U>
  93. constexpr static bool cmp(const T& v1, const U& v2) noexcept {
  94. return sequence_tuple::get<I>(v1) > sequence_tuple::get<I>(v2)
  95. || (sequence_tuple::get<I>(v1) == sequence_tuple::get<I>(v2) && greater_equal_impl<I + 1, N>::cmp(v1, v2));
  96. }
  97. };
  98. template <std::size_t N>
  99. struct greater_equal_impl<N, N> {
  100. template <class T, class U>
  101. constexpr static bool cmp(const T&, const U&) noexcept {
  102. return T::size_v >= U::size_v;
  103. }
  104. };
  105. // Hash combine functions copied from Boost.ContainerHash
  106. // https://github.com/boostorg/container_hash/blob/171c012d4723c5e93cc7cffe42919afdf8b27dfa/include/boost/container_hash/hash.hpp#L311
  107. // that is based on Peter Dimov's proposal
  108. // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
  109. // issue 6.18.
  110. //
  111. // This also contains public domain code from MurmurHash. From the
  112. // MurmurHash header:
  113. //
  114. // MurmurHash3 was written by Austin Appleby, and is placed in the public
  115. // domain. The author hereby disclaims copyright to this source code.
  116. template <typename SizeT>
  117. constexpr void hash_combine(SizeT& seed, SizeT value) noexcept {
  118. seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
  119. }
  120. constexpr auto rotl(std::uint32_t x, std::uint32_t r) noexcept {
  121. return (x << r) | (x >> (32 - r));
  122. }
  123. constexpr void hash_combine(std::uint32_t& h1, std::uint32_t k1) noexcept {
  124. const std::uint32_t c1 = 0xcc9e2d51;
  125. const std::uint32_t c2 = 0x1b873593;
  126. k1 *= c1;
  127. k1 = detail::rotl(k1,15);
  128. k1 *= c2;
  129. h1 ^= k1;
  130. h1 = detail::rotl(h1,13);
  131. h1 = h1*5+0xe6546b64;
  132. }
  133. #if defined(INT64_MIN) && defined(UINT64_MAX)
  134. constexpr void hash_combine(std::uint64_t& h, std::uint64_t k) noexcept {
  135. const std::uint64_t m = 0xc6a4a7935bd1e995ULL;
  136. const int r = 47;
  137. k *= m;
  138. k ^= k >> r;
  139. k *= m;
  140. h ^= k;
  141. h *= m;
  142. // Completely arbitrary number, to prevent 0's
  143. // from hashing to 0.
  144. h += 0xe6546b64;
  145. }
  146. #endif
  147. template <typename T>
  148. auto compute_hash(const T& value, long /*priority*/)
  149. -> decltype(std::hash<T>()(value))
  150. {
  151. return std::hash<T>()(value);
  152. }
  153. template <typename T>
  154. std::size_t compute_hash(const T& /*value*/, int /*priority*/) {
  155. static_assert(sizeof(T) && false, "====================> Boost.PFR: std::hash not specialized for type T");
  156. return 0;
  157. }
  158. template <std::size_t I, std::size_t N>
  159. struct hash_impl {
  160. template <class T>
  161. constexpr static std::size_t compute(const T& val) noexcept {
  162. std::size_t h = detail::compute_hash( ::boost::pfr::detail::sequence_tuple::get<I>(val), 1L );
  163. detail::hash_combine(h, hash_impl<I + 1, N>::compute(val) );
  164. return h;
  165. }
  166. };
  167. template <std::size_t N>
  168. struct hash_impl<N, N> {
  169. template <class T>
  170. constexpr static std::size_t compute(const T&) noexcept {
  171. return 0;
  172. }
  173. };
  174. ///////////////////// Define min_element and to avoid inclusion of <algorithm>
  175. constexpr std::size_t min_size(std::size_t x, std::size_t y) noexcept {
  176. return x < y ? x : y;
  177. }
  178. template <template <std::size_t, std::size_t> class Visitor, class T, class U>
  179. constexpr bool binary_visit(const T& x, const U& y) {
  180. constexpr std::size_t fields_count_lhs = detail::fields_count<std::remove_reference_t<T>>();
  181. constexpr std::size_t fields_count_rhs = detail::fields_count<std::remove_reference_t<U>>();
  182. constexpr std::size_t fields_count_min = detail::min_size(fields_count_lhs, fields_count_rhs);
  183. typedef Visitor<0, fields_count_min> visitor_t;
  184. #if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
  185. return visitor_t::cmp(detail::tie_as_tuple(x), detail::tie_as_tuple(y));
  186. #else
  187. bool result = true;
  188. ::boost::pfr::detail::for_each_field_dispatcher(
  189. x,
  190. [&result, &y](const auto& lhs) {
  191. constexpr std::size_t fields_count_rhs_ = detail::fields_count<std::remove_reference_t<U>>();
  192. ::boost::pfr::detail::for_each_field_dispatcher(
  193. y,
  194. [&result, &lhs](const auto& rhs) {
  195. result = visitor_t::cmp(lhs, rhs);
  196. },
  197. detail::make_index_sequence<fields_count_rhs_>{}
  198. );
  199. },
  200. detail::make_index_sequence<fields_count_lhs>{}
  201. );
  202. return result;
  203. #endif
  204. }
  205. }}} // namespace boost::pfr::detail
  206. #endif // BOOST_PFR_DETAIL_FUNCTIONAL_HPP