1// Copyright (c) 2016-2024 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
6#ifndef BOOST_PFR_OPS_HPP
7#define BOOST_PFR_OPS_HPP
8#pragma once
9
10#include <boost/pfr/detail/config.hpp>
11
12#include <boost/pfr/detail/detectors.hpp>
13#include <boost/pfr/ops_fields.hpp>
14
15/// \file boost/pfr/ops.hpp
16/// Contains comparison and hashing functions.
17/// If type is comparable using its own operator or its conversion operator, then the types operator is used. Otherwise
18/// the operation is done via corresponding function from boost/pfr/ops.hpp header.
19///
20/// \b Example:
21/// \code
22/// #include <boost/pfr/ops.hpp>
23/// struct comparable_struct { // No operators defined for that structure
24/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
25/// };
26/// // ...
27///
28/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
29/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
30/// assert(boost::pfr::lt(s1, s2));
31/// \endcode
32///
33/// \podops for other ways to define operators and more details.
34///
35/// \b Synopsis:
36namespace boost { namespace pfr {
37
38namespace detail {
39
40///////////////////// Helper typedefs that are used by all the ops
41 template <template <class, class> class Detector, class T, class U>
42 using enable_not_comp_base_t = std::enable_if_t<
43 not_appliable<Detector, T const&, U const&>::value,
44 bool
45 >;
46
47 template <template <class, class> class Detector, class T, class U>
48 using enable_comp_base_t = std::enable_if_t<
49 !not_appliable<Detector, T const&, U const&>::value,
50 bool
51 >;
52///////////////////// std::enable_if_t like functions that enable only if types do not support operation
53
54 template <class T, class U> using enable_not_eq_comp_t = enable_not_comp_base_t<comp_eq_detector, T, U>;
55 template <class T, class U> using enable_not_ne_comp_t = enable_not_comp_base_t<comp_ne_detector, T, U>;
56 template <class T, class U> using enable_not_lt_comp_t = enable_not_comp_base_t<comp_lt_detector, T, U>;
57 template <class T, class U> using enable_not_le_comp_t = enable_not_comp_base_t<comp_le_detector, T, U>;
58 template <class T, class U> using enable_not_gt_comp_t = enable_not_comp_base_t<comp_gt_detector, T, U>;
59 template <class T, class U> using enable_not_ge_comp_t = enable_not_comp_base_t<comp_ge_detector, T, U>;
60
61 template <class T> using enable_not_hashable_t = std::enable_if_t<
62 not_appliable<hash_detector, const T&, const T&>::value,
63 std::size_t
64 >;
65///////////////////// std::enable_if_t like functions that enable only if types do support operation
66
67 template <class T, class U> using enable_eq_comp_t = enable_comp_base_t<comp_eq_detector, T, U>;
68 template <class T, class U> using enable_ne_comp_t = enable_comp_base_t<comp_ne_detector, T, U>;
69 template <class T, class U> using enable_lt_comp_t = enable_comp_base_t<comp_lt_detector, T, U>;
70 template <class T, class U> using enable_le_comp_t = enable_comp_base_t<comp_le_detector, T, U>;
71 template <class T, class U> using enable_gt_comp_t = enable_comp_base_t<comp_gt_detector, T, U>;
72 template <class T, class U> using enable_ge_comp_t = enable_comp_base_t<comp_ge_detector, T, U>;
73
74 template <class T> using enable_hashable_t = std::enable_if_t<
75 !not_appliable<hash_detector, const T&, const T&>::value,
76 std::size_t
77 >;
78} // namespace detail
79
80
81/// \brief Compares lhs and rhs for equality using their own comparison and conversion operators; if no operators available returns \forcedlink{eq_fields}(lhs, rhs).
82///
83/// \returns true if lhs is equal to rhs; false otherwise
84template <class T, class U>
85constexpr detail::enable_not_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) noexcept {
86 return boost::pfr::eq_fields(lhs, rhs);
87}
88
89/// \overload eq
90template <class T, class U>
91constexpr detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
92 return lhs == rhs;
93}
94
95
96/// \brief Compares lhs and rhs for inequality using their own comparison and conversion operators; if no operators available returns \forcedlink{ne_fields}(lhs, rhs).
97///
98/// \returns true if lhs is not equal to rhs; false otherwise
99template <class T, class U>
100constexpr detail::enable_not_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) noexcept {
101 return boost::pfr::ne_fields(lhs, rhs);
102}
103
104/// \overload ne
105template <class T, class U>
106constexpr detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
107 return lhs != rhs;
108}
109
110
111/// \brief Compares lhs and rhs for less-than using their own comparison and conversion operators; if no operators available returns \forcedlink{lt_fields}(lhs, rhs).
112///
113/// \returns true if lhs is less than rhs; false otherwise
114template <class T, class U>
115constexpr detail::enable_not_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) noexcept {
116 return boost::pfr::lt_fields(lhs, rhs);
117}
118
119/// \overload lt
120template <class T, class U>
121constexpr detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
122 return lhs < rhs;
123}
124
125
126/// \brief Compares lhs and rhs for greater-than using their own comparison and conversion operators; if no operators available returns \forcedlink{lt_fields}(lhs, rhs).
127///
128/// \returns true if lhs is greater than rhs; false otherwise
129template <class T, class U>
130constexpr detail::enable_not_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) noexcept {
131 return boost::pfr::gt_fields(lhs, rhs);
132}
133
134/// \overload gt
135template <class T, class U>
136constexpr detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
137 return lhs > rhs;
138}
139
140
141/// \brief Compares lhs and rhs for less-equal using their own comparison and conversion operators; if no operators available returns \forcedlink{le_fields}(lhs, rhs).
142///
143/// \returns true if lhs is less or equal to rhs; false otherwise
144template <class T, class U>
145constexpr detail::enable_not_le_comp_t<T, U> le(const T& lhs, const U& rhs) noexcept {
146 return boost::pfr::le_fields(lhs, rhs);
147}
148
149/// \overload le
150template <class T, class U>
151constexpr detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
152 return lhs <= rhs;
153}
154
155
156/// \brief Compares lhs and rhs for greater-equal using their own comparison and conversion operators; if no operators available returns \forcedlink{ge_fields}(lhs, rhs).
157///
158/// \returns true if lhs is greater or equal to rhs; false otherwise
159template <class T, class U>
160constexpr detail::enable_not_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) noexcept {
161 return boost::pfr::ge_fields(lhs, rhs);
162}
163
164/// \overload ge
165template <class T, class U>
166constexpr detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
167 return lhs >= rhs;
168}
169
170
171/// \brief Hashes value using its own std::hash specialization; if no std::hash specialization available returns \forcedlink{hash_fields}(value).
172///
173/// \returns std::size_t with hash of the value
174template <class T>
175constexpr detail::enable_not_hashable_t<T> hash_value(const T& value) noexcept {
176 return boost::pfr::hash_fields(value);
177}
178
179/// \overload hash_value
180template <class T>
181constexpr detail::enable_hashable_t<T> hash_value(const T& value) {
182 return std::hash<T>{}(value);
183}
184
185}} // namespace boost::pfr
186
187#endif // BOOST_PFR_OPS_HPP
188

source code of boost/libs/pfr/include/boost/pfr/ops.hpp