1 // Copyright (c) 2016-2020 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: 36 namespace boost { namespace pfr { 37 38 namespace 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 avalable returns \forcedlink{eq_fields}(lhs, rhs). 82 /// 83 /// \returns true if lhs is equal to rhs; false otherwise 84 template <class T, class U> 85 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 90 template <class T, class U> 91 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 avalable returns \forcedlink{ne_fields}(lhs, rhs). 97 /// 98 /// \returns true if lhs is not equal to rhs; false otherwise 99 template <class T, class U> 100 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 105 template <class T, class U> 106 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 avalable returns \forcedlink{lt_fields}(lhs, rhs). 112 /// 113 /// \returns true if lhs is less than rhs; false otherwise 114 template <class T, class U> 115 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 120 template <class T, class U> 121 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 avalable returns \forcedlink{lt_fields}(lhs, rhs). 127 /// 128 /// \returns true if lhs is greater than rhs; false otherwise 129 template <class T, class U> 130 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 135 template <class T, class U> 136 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 avalable returns \forcedlink{le_fields}(lhs, rhs). 142 /// 143 /// \returns true if lhs is less or equal to rhs; false otherwise 144 template <class T, class U> 145 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 150 template <class T, class U> 151 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 avalable returns \forcedlink{ge_fields}(lhs, rhs). 157 /// 158 /// \returns true if lhs is greater or equal to rhs; false otherwise 159 template <class T, class U> 160 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 165 template <class T, class U> 166 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 avalable returns \forcedlink{hash_fields}(value). 172 /// 173 /// \returns std::size_t with hash of the value 174 template <class T> 175 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 180 template <class T> 181 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