compare.h
Go to the documentation of this file.
00001 // Copyright 2018 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 //
00015 // -----------------------------------------------------------------------------
00016 // compare.h
00017 // -----------------------------------------------------------------------------
00018 //
00019 // This header file defines the `absl::weak_equality`, `absl::strong_equality`,
00020 // `absl::partial_ordering`, `absl::weak_ordering`, and `absl::strong_ordering`
00021 // types for storing the results of three way comparisons.
00022 //
00023 // Example:
00024 //   absl::weak_ordering compare(const std::string& a, const std::string& b);
00025 //
00026 // These are C++11 compatible versions of the C++20 corresponding types
00027 // (`std::weak_equality`, etc.) and are designed to be drop-in replacements
00028 // for code compliant with C++20.
00029 
00030 #ifndef ABSL_TYPES_COMPARE_H_
00031 #define ABSL_TYPES_COMPARE_H_
00032 
00033 #include <cstddef>
00034 #include <cstdint>
00035 #include <cstdlib>
00036 #include <type_traits>
00037 
00038 #include "absl/base/attributes.h"
00039 #include "absl/meta/type_traits.h"
00040 
00041 namespace absl {
00042 namespace compare_internal {
00043 
00044 using value_type = int8_t;
00045 
00046 template <typename T>
00047 struct Fail {
00048   static_assert(sizeof(T) < 0, "Only literal `0` is allowed.");
00049 };
00050 
00051 // We need the NullPtrT template to avoid triggering the modernize-use-nullptr
00052 // ClangTidy warning in user code.
00053 template <typename NullPtrT = std::nullptr_t>
00054 struct OnlyLiteralZero {
00055   constexpr OnlyLiteralZero(NullPtrT) noexcept {}  // NOLINT
00056 
00057   // Fails compilation when `nullptr` or integral type arguments other than
00058   // `int` are passed. This constructor doesn't accept `int` because literal `0`
00059   // has type `int`. Literal `0` arguments will be implicitly converted to
00060   // `std::nullptr_t` and accepted by the above constructor, while other `int`
00061   // arguments will fail to be converted and cause compilation failure.
00062   template <
00063       typename T,
00064       typename = typename std::enable_if<
00065           std::is_same<T, std::nullptr_t>::value ||
00066           (std::is_integral<T>::value && !std::is_same<T, int>::value)>::type,
00067       typename = typename Fail<T>::type>
00068   OnlyLiteralZero(T);  // NOLINT
00069 };
00070 
00071 enum class eq : value_type {
00072   equal = 0,
00073   equivalent = equal,
00074   nonequal = 1,
00075   nonequivalent = nonequal,
00076 };
00077 
00078 enum class ord : value_type { less = -1, greater = 1 };
00079 
00080 enum class ncmp : value_type { unordered = -127 };
00081 
00082 // These template base classes allow for defining the values of the constants
00083 // in the header file (for performance) without using inline variables (which
00084 // aren't available in C++11).
00085 template <typename T>
00086 struct weak_equality_base {
00087   ABSL_CONST_INIT static const T equivalent;
00088   ABSL_CONST_INIT static const T nonequivalent;
00089 };
00090 template <typename T>
00091 const T weak_equality_base<T>::equivalent(eq::equivalent);
00092 template <typename T>
00093 const T weak_equality_base<T>::nonequivalent(eq::nonequivalent);
00094 
00095 template <typename T>
00096 struct strong_equality_base {
00097   ABSL_CONST_INIT static const T equal;
00098   ABSL_CONST_INIT static const T nonequal;
00099   ABSL_CONST_INIT static const T equivalent;
00100   ABSL_CONST_INIT static const T nonequivalent;
00101 };
00102 template <typename T>
00103 const T strong_equality_base<T>::equal(eq::equal);
00104 template <typename T>
00105 const T strong_equality_base<T>::nonequal(eq::nonequal);
00106 template <typename T>
00107 const T strong_equality_base<T>::equivalent(eq::equivalent);
00108 template <typename T>
00109 const T strong_equality_base<T>::nonequivalent(eq::nonequivalent);
00110 
00111 template <typename T>
00112 struct partial_ordering_base {
00113   ABSL_CONST_INIT static const T less;
00114   ABSL_CONST_INIT static const T equivalent;
00115   ABSL_CONST_INIT static const T greater;
00116   ABSL_CONST_INIT static const T unordered;
00117 };
00118 template <typename T>
00119 const T partial_ordering_base<T>::less(ord::less);
00120 template <typename T>
00121 const T partial_ordering_base<T>::equivalent(eq::equivalent);
00122 template <typename T>
00123 const T partial_ordering_base<T>::greater(ord::greater);
00124 template <typename T>
00125 const T partial_ordering_base<T>::unordered(ncmp::unordered);
00126 
00127 template <typename T>
00128 struct weak_ordering_base {
00129   ABSL_CONST_INIT static const T less;
00130   ABSL_CONST_INIT static const T equivalent;
00131   ABSL_CONST_INIT static const T greater;
00132 };
00133 template <typename T>
00134 const T weak_ordering_base<T>::less(ord::less);
00135 template <typename T>
00136 const T weak_ordering_base<T>::equivalent(eq::equivalent);
00137 template <typename T>
00138 const T weak_ordering_base<T>::greater(ord::greater);
00139 
00140 template <typename T>
00141 struct strong_ordering_base {
00142   ABSL_CONST_INIT static const T less;
00143   ABSL_CONST_INIT static const T equal;
00144   ABSL_CONST_INIT static const T equivalent;
00145   ABSL_CONST_INIT static const T greater;
00146 };
00147 template <typename T>
00148 const T strong_ordering_base<T>::less(ord::less);
00149 template <typename T>
00150 const T strong_ordering_base<T>::equal(eq::equal);
00151 template <typename T>
00152 const T strong_ordering_base<T>::equivalent(eq::equivalent);
00153 template <typename T>
00154 const T strong_ordering_base<T>::greater(ord::greater);
00155 
00156 }  // namespace compare_internal
00157 
00158 class weak_equality
00159     : public compare_internal::weak_equality_base<weak_equality> {
00160   explicit constexpr weak_equality(compare_internal::eq v) noexcept
00161       : value_(static_cast<compare_internal::value_type>(v)) {}
00162   friend struct compare_internal::weak_equality_base<weak_equality>;
00163 
00164  public:
00165   // Comparisons
00166   friend constexpr bool operator==(
00167       weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
00168     return v.value_ == 0;
00169   }
00170   friend constexpr bool operator!=(
00171       weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
00172     return v.value_ != 0;
00173   }
00174   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
00175                                    weak_equality v) noexcept {
00176     return 0 == v.value_;
00177   }
00178   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
00179                                    weak_equality v) noexcept {
00180     return 0 != v.value_;
00181   }
00182 
00183  private:
00184   compare_internal::value_type value_;
00185 };
00186 
00187 class strong_equality
00188     : public compare_internal::strong_equality_base<strong_equality> {
00189   explicit constexpr strong_equality(compare_internal::eq v) noexcept
00190       : value_(static_cast<compare_internal::value_type>(v)) {}
00191   friend struct compare_internal::strong_equality_base<strong_equality>;
00192 
00193  public:
00194   // Conversion
00195   constexpr operator weak_equality() const noexcept {  // NOLINT
00196     return value_ == 0 ? weak_equality::equivalent
00197                        : weak_equality::nonequivalent;
00198   }
00199   // Comparisons
00200   friend constexpr bool operator==(
00201       strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
00202     return v.value_ == 0;
00203   }
00204   friend constexpr bool operator!=(
00205       strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
00206     return v.value_ != 0;
00207   }
00208   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
00209                                    strong_equality v) noexcept {
00210     return 0 == v.value_;
00211   }
00212   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
00213                                    strong_equality v) noexcept {
00214     return 0 != v.value_;
00215   }
00216 
00217  private:
00218   compare_internal::value_type value_;
00219 };
00220 
00221 class partial_ordering
00222     : public compare_internal::partial_ordering_base<partial_ordering> {
00223   explicit constexpr partial_ordering(compare_internal::eq v) noexcept
00224       : value_(static_cast<compare_internal::value_type>(v)) {}
00225   explicit constexpr partial_ordering(compare_internal::ord v) noexcept
00226       : value_(static_cast<compare_internal::value_type>(v)) {}
00227   explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept
00228       : value_(static_cast<compare_internal::value_type>(v)) {}
00229   friend struct compare_internal::partial_ordering_base<partial_ordering>;
00230 
00231   constexpr bool is_ordered() const noexcept {
00232     return value_ !=
00233            compare_internal::value_type(compare_internal::ncmp::unordered);
00234   }
00235 
00236  public:
00237   // Conversion
00238   constexpr operator weak_equality() const noexcept {  // NOLINT
00239     return value_ == 0 ? weak_equality::equivalent
00240                        : weak_equality::nonequivalent;
00241   }
00242   // Comparisons
00243   friend constexpr bool operator==(
00244       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00245     return v.is_ordered() && v.value_ == 0;
00246   }
00247   friend constexpr bool operator!=(
00248       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00249     return !v.is_ordered() || v.value_ != 0;
00250   }
00251   friend constexpr bool operator<(
00252       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00253     return v.is_ordered() && v.value_ < 0;
00254   }
00255   friend constexpr bool operator<=(
00256       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00257     return v.is_ordered() && v.value_ <= 0;
00258   }
00259   friend constexpr bool operator>(
00260       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00261     return v.is_ordered() && v.value_ > 0;
00262   }
00263   friend constexpr bool operator>=(
00264       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00265     return v.is_ordered() && v.value_ >= 0;
00266   }
00267   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
00268                                    partial_ordering v) noexcept {
00269     return v.is_ordered() && 0 == v.value_;
00270   }
00271   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
00272                                    partial_ordering v) noexcept {
00273     return !v.is_ordered() || 0 != v.value_;
00274   }
00275   friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
00276                                   partial_ordering v) noexcept {
00277     return v.is_ordered() && 0 < v.value_;
00278   }
00279   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
00280                                    partial_ordering v) noexcept {
00281     return v.is_ordered() && 0 <= v.value_;
00282   }
00283   friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
00284                                   partial_ordering v) noexcept {
00285     return v.is_ordered() && 0 > v.value_;
00286   }
00287   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
00288                                    partial_ordering v) noexcept {
00289     return v.is_ordered() && 0 >= v.value_;
00290   }
00291 
00292  private:
00293   compare_internal::value_type value_;
00294 };
00295 
00296 class weak_ordering
00297     : public compare_internal::weak_ordering_base<weak_ordering> {
00298   explicit constexpr weak_ordering(compare_internal::eq v) noexcept
00299       : value_(static_cast<compare_internal::value_type>(v)) {}
00300   explicit constexpr weak_ordering(compare_internal::ord v) noexcept
00301       : value_(static_cast<compare_internal::value_type>(v)) {}
00302   friend struct compare_internal::weak_ordering_base<weak_ordering>;
00303 
00304  public:
00305   // Conversions
00306   constexpr operator weak_equality() const noexcept {  // NOLINT
00307     return value_ == 0 ? weak_equality::equivalent
00308                        : weak_equality::nonequivalent;
00309   }
00310   constexpr operator partial_ordering() const noexcept {  // NOLINT
00311     return value_ == 0 ? partial_ordering::equivalent
00312                        : (value_ < 0 ? partial_ordering::less
00313                                      : partial_ordering::greater);
00314   }
00315   // Comparisons
00316   friend constexpr bool operator==(
00317       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00318     return v.value_ == 0;
00319   }
00320   friend constexpr bool operator!=(
00321       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00322     return v.value_ != 0;
00323   }
00324   friend constexpr bool operator<(
00325       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00326     return v.value_ < 0;
00327   }
00328   friend constexpr bool operator<=(
00329       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00330     return v.value_ <= 0;
00331   }
00332   friend constexpr bool operator>(
00333       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00334     return v.value_ > 0;
00335   }
00336   friend constexpr bool operator>=(
00337       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00338     return v.value_ >= 0;
00339   }
00340   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
00341                                    weak_ordering v) noexcept {
00342     return 0 == v.value_;
00343   }
00344   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
00345                                    weak_ordering v) noexcept {
00346     return 0 != v.value_;
00347   }
00348   friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
00349                                   weak_ordering v) noexcept {
00350     return 0 < v.value_;
00351   }
00352   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
00353                                    weak_ordering v) noexcept {
00354     return 0 <= v.value_;
00355   }
00356   friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
00357                                   weak_ordering v) noexcept {
00358     return 0 > v.value_;
00359   }
00360   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
00361                                    weak_ordering v) noexcept {
00362     return 0 >= v.value_;
00363   }
00364 
00365  private:
00366   compare_internal::value_type value_;
00367 };
00368 
00369 class strong_ordering
00370     : public compare_internal::strong_ordering_base<strong_ordering> {
00371   explicit constexpr strong_ordering(compare_internal::eq v) noexcept
00372       : value_(static_cast<compare_internal::value_type>(v)) {}
00373   explicit constexpr strong_ordering(compare_internal::ord v) noexcept
00374       : value_(static_cast<compare_internal::value_type>(v)) {}
00375   friend struct compare_internal::strong_ordering_base<strong_ordering>;
00376 
00377  public:
00378   // Conversions
00379   constexpr operator weak_equality() const noexcept {  // NOLINT
00380     return value_ == 0 ? weak_equality::equivalent
00381                        : weak_equality::nonequivalent;
00382   }
00383   constexpr operator strong_equality() const noexcept {  // NOLINT
00384     return value_ == 0 ? strong_equality::equal : strong_equality::nonequal;
00385   }
00386   constexpr operator partial_ordering() const noexcept {  // NOLINT
00387     return value_ == 0 ? partial_ordering::equivalent
00388                        : (value_ < 0 ? partial_ordering::less
00389                                      : partial_ordering::greater);
00390   }
00391   constexpr operator weak_ordering() const noexcept {  // NOLINT
00392     return value_ == 0
00393                ? weak_ordering::equivalent
00394                : (value_ < 0 ? weak_ordering::less : weak_ordering::greater);
00395   }
00396   // Comparisons
00397   friend constexpr bool operator==(
00398       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00399     return v.value_ == 0;
00400   }
00401   friend constexpr bool operator!=(
00402       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00403     return v.value_ != 0;
00404   }
00405   friend constexpr bool operator<(
00406       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00407     return v.value_ < 0;
00408   }
00409   friend constexpr bool operator<=(
00410       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00411     return v.value_ <= 0;
00412   }
00413   friend constexpr bool operator>(
00414       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00415     return v.value_ > 0;
00416   }
00417   friend constexpr bool operator>=(
00418       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
00419     return v.value_ >= 0;
00420   }
00421   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
00422                                    strong_ordering v) noexcept {
00423     return 0 == v.value_;
00424   }
00425   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
00426                                    strong_ordering v) noexcept {
00427     return 0 != v.value_;
00428   }
00429   friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
00430                                   strong_ordering v) noexcept {
00431     return 0 < v.value_;
00432   }
00433   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
00434                                    strong_ordering v) noexcept {
00435     return 0 <= v.value_;
00436   }
00437   friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
00438                                   strong_ordering v) noexcept {
00439     return 0 > v.value_;
00440   }
00441   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
00442                                    strong_ordering v) noexcept {
00443     return 0 >= v.value_;
00444   }
00445 
00446  private:
00447   compare_internal::value_type value_;
00448 };
00449 
00450 namespace compare_internal {
00451 // We also provide these comparator adapter functions for internal absl use.
00452 
00453 // Helper functions to do a boolean comparison of two keys given a boolean
00454 // or three-way comparator.
00455 // SFINAE prevents implicit conversions to bool (such as from int).
00456 template <typename Bool,
00457           absl::enable_if_t<std::is_same<bool, Bool>::value, int> = 0>
00458 constexpr bool compare_result_as_less_than(const Bool r) { return r; }
00459 constexpr bool compare_result_as_less_than(const absl::weak_ordering r) {
00460   return r < 0;
00461 }
00462 
00463 template <typename Compare, typename K, typename LK>
00464 constexpr bool do_less_than_comparison(const Compare &compare, const K &x,
00465                                        const LK &y) {
00466   return compare_result_as_less_than(compare(x, y));
00467 }
00468 
00469 // Helper functions to do a three-way comparison of two keys given a boolean or
00470 // three-way comparator.
00471 // SFINAE prevents implicit conversions to int (such as from bool).
00472 template <typename Int,
00473           absl::enable_if_t<std::is_same<int, Int>::value, int> = 0>
00474 constexpr absl::weak_ordering compare_result_as_ordering(const Int c) {
00475   return c < 0 ? absl::weak_ordering::less
00476                : c == 0 ? absl::weak_ordering::equivalent
00477                         : absl::weak_ordering::greater;
00478 }
00479 constexpr absl::weak_ordering compare_result_as_ordering(
00480     const absl::weak_ordering c) {
00481   return c;
00482 }
00483 
00484 template <
00485     typename Compare, typename K, typename LK,
00486     absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare(
00487                                               const K &, const LK &)>>::value,
00488                       int> = 0>
00489 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
00490                                                       const K &x, const LK &y) {
00491   return compare_result_as_ordering(compare(x, y));
00492 }
00493 template <
00494     typename Compare, typename K, typename LK,
00495     absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare(
00496                                              const K &, const LK &)>>::value,
00497                       int> = 0>
00498 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
00499                                                       const K &x, const LK &y) {
00500   return compare(x, y) ? absl::weak_ordering::less
00501                        : compare(y, x) ? absl::weak_ordering::greater
00502                                        : absl::weak_ordering::equivalent;
00503 }
00504 
00505 }  // namespace compare_internal
00506 }  // namespace absl
00507 
00508 #endif  // ABSL_TYPES_COMPARE_H_


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:14