ops_fields.hpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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_OPS_FIELDS_HPP
  6. #define BOOST_PFR_OPS_FIELDS_HPP
  7. #pragma once
  8. #include <boost/pfr/detail/config.hpp>
  9. #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
  10. #include <boost/pfr/core.hpp>
  11. #include <boost/pfr/detail/functional.hpp>
  12. /// \file boost/pfr/ops_fields.hpp
  13. /// Contains field-by-fields comparison and hash functions.
  14. ///
  15. /// \b Example:
  16. /// \code
  17. /// #include <boost/pfr/ops_fields.hpp>
  18. /// struct comparable_struct { // No operators defined for that structure
  19. /// int i; short s;
  20. /// };
  21. /// // ...
  22. ///
  23. /// comparable_struct s1 {0, 1};
  24. /// comparable_struct s2 {0, 2};
  25. /// assert(boost::pfr::lt_fields(s1, s2));
  26. /// \endcode
  27. ///
  28. /// \podops for other ways to define operators and more details.
  29. ///
  30. /// \b Synopsis:
  31. namespace boost { namespace pfr {
  32. BOOST_PFR_BEGIN_MODULE_EXPORT
  33. /// Does a field-by-field equality comparison.
  34. ///
  35. /// \returns `L == R && tuple_size_v<T> == tuple_size_v<U>`, where `L` and
  36. /// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
  37. // `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
  38. template <class T, class U>
  39. constexpr bool eq_fields(const T& lhs, const U& rhs) noexcept {
  40. return detail::binary_visit<detail::equal_impl>(lhs, rhs);
  41. }
  42. /// Does a field-by-field inequality comparison.
  43. ///
  44. /// \returns `L != R || tuple_size_v<T> != tuple_size_v<U>`, where `L` and
  45. /// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
  46. // `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
  47. template <class T, class U>
  48. constexpr bool ne_fields(const T& lhs, const U& rhs) noexcept {
  49. return detail::binary_visit<detail::not_equal_impl>(lhs, rhs);
  50. }
  51. /// Does a field-by-field greter comparison.
  52. ///
  53. /// \returns `L > R || (L == R && tuple_size_v<T> > tuple_size_v<U>)`, where `L` and
  54. /// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
  55. // `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
  56. template <class T, class U>
  57. constexpr bool gt_fields(const T& lhs, const U& rhs) noexcept {
  58. return detail::binary_visit<detail::greater_impl>(lhs, rhs);
  59. }
  60. /// Does a field-by-field less comparison.
  61. ///
  62. /// \returns `L < R || (L == R && tuple_size_v<T> < tuple_size_v<U>)`, where `L` and
  63. /// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
  64. // `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
  65. template <class T, class U>
  66. constexpr bool lt_fields(const T& lhs, const U& rhs) noexcept {
  67. return detail::binary_visit<detail::less_impl>(lhs, rhs);
  68. }
  69. /// Does a field-by-field greater equal comparison.
  70. ///
  71. /// \returns `L > R || (L == R && tuple_size_v<T> >= tuple_size_v<U>)`, where `L` and
  72. /// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
  73. // `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
  74. template <class T, class U>
  75. constexpr bool ge_fields(const T& lhs, const U& rhs) noexcept {
  76. return detail::binary_visit<detail::greater_equal_impl>(lhs, rhs);
  77. }
  78. /// Does a field-by-field less equal comparison.
  79. ///
  80. /// \returns `L < R || (L == R && tuple_size_v<T> <= tuple_size_v<U>)`, where `L` and
  81. /// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
  82. // `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
  83. template <class T, class U>
  84. constexpr bool le_fields(const T& lhs, const U& rhs) noexcept {
  85. return detail::binary_visit<detail::less_equal_impl>(lhs, rhs);
  86. }
  87. /// Does a field-by-field hashing.
  88. ///
  89. /// \returns combined hash of all the fields
  90. template <class T>
  91. std::size_t hash_fields(const T& x) {
  92. constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
  93. #if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
  94. return detail::hash_impl<0, fields_count_val>::compute(detail::tie_as_tuple(x));
  95. #else
  96. std::size_t result = 0;
  97. ::boost::pfr::detail::for_each_field_dispatcher(
  98. x,
  99. [&result](const auto& lhs) {
  100. // We can not reuse `fields_count_val` in lambda because compilers had issues with
  101. // passing constexpr variables into lambdas. Computing is again is the most portable solution.
  102. constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
  103. result = detail::hash_impl<0, fields_count_val_lambda>::compute(lhs);
  104. },
  105. detail::make_index_sequence<fields_count_val>{}
  106. );
  107. return result;
  108. #endif
  109. }
  110. BOOST_PFR_END_MODULE_EXPORT
  111. }} // namespace boost::pfr
  112. #endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_PFR_INTERFACE_UNIT)
  113. #endif // BOOST_PFR_OPS_HPP