brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.1 KiB · e37ab44 Raw
338 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//  A set of routines for testing the comparison operators of a type9//10//      FooOrder<expected-ordering>  All seven comparison operators, requires C++20 or newer.11//      FooComparison                All six pre-C++20 comparison operators12//      FooEquality                  Equality operators operator== and operator!=13//14//      AssertXAreNoexcept           static_asserts that the operations are all noexcept.15//      AssertXReturnBool            static_asserts that the operations return bool.16//      AssertOrderReturn            static_asserts that the pre-C++20 comparison operations17//                                   return bool and operator<=> returns the proper type.18//      AssertXConvertibleToBool     static_asserts that the operations return something convertible to bool.19//      testXValues                  returns the result of the comparison of all operations.20//21//      AssertOrderConvertibleToBool doesn't exist yet. It will be implemented when needed.22 23#ifndef TEST_COMPARISONS_H24#define TEST_COMPARISONS_H25 26#include <cassert>27#include <compare>28#include <concepts>29#include <limits>30#include <type_traits>31#include <utility>32 33#include "test_macros.h"34 35// Test the consistency of the six basic comparison operators for values that are ordered or unordered.36template <class T, class U = T>37TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool38testComparisonsComplete(const T& t1, const U& t2, bool isEqual, bool isLess, bool isGreater) {39    assert(((isEqual ? 1 : 0) + (isLess ? 1 : 0) + (isGreater ? 1 : 0) <= 1) &&40           "at most one of isEqual, isLess, and isGreater can be true");41    if (isEqual) {42        if (!(t1 == t2)) return false;43        if (!(t2 == t1)) return false;44        if ( (t1 != t2)) return false;45        if ( (t2 != t1)) return false;46        if ( (t1  < t2)) return false;47        if ( (t2  < t1)) return false;48        if (!(t1 <= t2)) return false;49        if (!(t2 <= t1)) return false;50        if ( (t1  > t2)) return false;51        if ( (t2  > t1)) return false;52        if (!(t1 >= t2)) return false;53        if (!(t2 >= t1)) return false;54    } else if (isLess) {55        if ( (t1 == t2)) return false;56        if ( (t2 == t1)) return false;57        if (!(t1 != t2)) return false;58        if (!(t2 != t1)) return false;59        if (!(t1  < t2)) return false;60        if ( (t2  < t1)) return false;61        if (!(t1 <= t2)) return false;62        if ( (t2 <= t1)) return false;63        if ( (t1  > t2)) return false;64        if (!(t2  > t1)) return false;65        if ( (t1 >= t2)) return false;66        if (!(t2 >= t1)) return false;67    } else if (isGreater) {68        if ( (t1 == t2)) return false;69        if ( (t2 == t1)) return false;70        if (!(t1 != t2)) return false;71        if (!(t2 != t1)) return false;72        if ( (t1  < t2)) return false;73        if (!(t2  < t1)) return false;74        if ( (t1 <= t2)) return false;75        if (!(t2 <= t1)) return false;76        if (!(t1  > t2)) return false;77        if ( (t2  > t1)) return false;78        if (!(t1 >= t2)) return false;79        if ( (t2 >= t1)) return false;80    } else { // unordered81        if ( (t1 == t2)) return false;82        if ( (t2 == t1)) return false;83        if (!(t1 != t2)) return false;84        if (!(t2 != t1)) return false;85        if ( (t1  < t2)) return false;86        if ( (t2  < t1)) return false;87        if ( (t1 <= t2)) return false;88        if ( (t2 <= t1)) return false;89        if ( (t1  > t2)) return false;90        if ( (t2  > t1)) return false;91        if ( (t1 >= t2)) return false;92        if ( (t2 >= t1)) return false;93    }94 95    return true;96}97 98// Test the six basic comparison operators for ordered values.99template <class T, class U = T>100TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t2, bool isEqual, bool isLess) {101    assert(!(isEqual && isLess) && "isEqual and isLess cannot be both true");102    bool isGreater = !isEqual && !isLess;103    return testComparisonsComplete(t1, t2, isEqual, isLess, isGreater);104}105 106//  Easy call when you can init from something already comparable.107template <class T, class Param>108TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisonsValues(Param val1, Param val2)109{110    const bool isEqual   = val1 == val2;111    const bool isLess    = val1 <  val2;112    const bool isGreater = val1  > val2;113 114    return testComparisonsComplete(T(val1), T(val2), isEqual, isLess, isGreater);115}116 117template <class T, class U = T>118TEST_CONSTEXPR_CXX14 void AssertComparisonsAreNoexcept() {119    ASSERT_NOEXCEPT(std::declval<const T&>() == std::declval<const U&>());120    ASSERT_NOEXCEPT(std::declval<const T&>() != std::declval<const U&>());121    ASSERT_NOEXCEPT(std::declval<const T&>() <  std::declval<const U&>());122    ASSERT_NOEXCEPT(std::declval<const T&>() <= std::declval<const U&>());123    ASSERT_NOEXCEPT(std::declval<const T&>() >  std::declval<const U&>());124    ASSERT_NOEXCEPT(std::declval<const T&>() >= std::declval<const U&>());125}126 127template <class T, class U = T>128TEST_CONSTEXPR_CXX14 void AssertComparisonsReturnBool() {129    ASSERT_SAME_TYPE(decltype(std::declval<const T&>() == std::declval<const U&>()), bool);130    ASSERT_SAME_TYPE(decltype(std::declval<const T&>() != std::declval<const U&>()), bool);131    ASSERT_SAME_TYPE(decltype(std::declval<const T&>() <  std::declval<const U&>()), bool);132    ASSERT_SAME_TYPE(decltype(std::declval<const T&>() <= std::declval<const U&>()), bool);133    ASSERT_SAME_TYPE(decltype(std::declval<const T&>() >  std::declval<const U&>()), bool);134    ASSERT_SAME_TYPE(decltype(std::declval<const T&>() >= std::declval<const U&>()), bool);135}136 137template <class T, class U = T>138void AssertComparisonsConvertibleToBool()139{140    static_assert((std::is_convertible<decltype(std::declval<const T&>() == std::declval<const U&>()), bool>::value), "");141    static_assert((std::is_convertible<decltype(std::declval<const T&>() != std::declval<const U&>()), bool>::value), "");142    static_assert((std::is_convertible<decltype(std::declval<const T&>() <  std::declval<const U&>()), bool>::value), "");143    static_assert((std::is_convertible<decltype(std::declval<const T&>() <= std::declval<const U&>()), bool>::value), "");144    static_assert((std::is_convertible<decltype(std::declval<const T&>() >  std::declval<const U&>()), bool>::value), "");145    static_assert((std::is_convertible<decltype(std::declval<const T&>() >= std::declval<const U&>()), bool>::value), "");146}147 148#if TEST_STD_VER > 17149template <class T, class U = T>150constexpr void AssertOrderAreNoexcept() {151    AssertComparisonsAreNoexcept<T, U>();152    ASSERT_NOEXCEPT(std::declval<const T&>() <=> std::declval<const U&>());153}154 155template <class Order, class T, class U = T>156constexpr void AssertOrderReturn() {157    AssertComparisonsReturnBool<T, U>();158    ASSERT_SAME_TYPE(decltype(std::declval<const T&>() <=> std::declval<const U&>()), Order);159}160 161template <class Order, class T, class U = T>162TEST_NODISCARD constexpr bool testOrder(const T& t1, const U& t2, Order order) {163    bool equal   = order == Order::equivalent;164    bool less    = order == Order::less;165    bool greater = order == Order::greater;166 167    return (t1 <=> t2 == order) && testComparisonsComplete(t1, t2, equal, less, greater);168}169 170template <class T, class Param>171TEST_NODISCARD constexpr bool testOrderValues(Param val1, Param val2) {172  return testOrder(T(val1), T(val2), val1 <=> val2);173}174 175#endif176 177//  Test all two comparison operations for sanity178template <class T, class U = T>179TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testEquality(const T& t1, const U& t2, bool isEqual)180{181    if (isEqual)182        {183        if (!(t1 == t2)) return false;184        if (!(t2 == t1)) return false;185        if ( (t1 != t2)) return false;186        if ( (t2 != t1)) return false;187        }188    else /* not equal */189        {190        if ( (t1 == t2)) return false;191        if ( (t2 == t1)) return false;192        if (!(t1 != t2)) return false;193        if (!(t2 != t1)) return false;194        }195 196    return true;197}198 199//  Easy call when you can init from something already comparable.200template <class T, class Param>201TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testEqualityValues(Param val1, Param val2)202{203    const bool isEqual = val1 == val2;204 205    return testEquality(T(val1), T(val2), isEqual);206}207 208template <class T, class U = T>209void AssertEqualityAreNoexcept()210{211    ASSERT_NOEXCEPT(std::declval<const T&>() == std::declval<const U&>());212    ASSERT_NOEXCEPT(std::declval<const T&>() != std::declval<const U&>());213}214 215template <class T, class U = T>216TEST_CONSTEXPR_CXX14 void AssertEqualityReturnBool() {217  ASSERT_SAME_TYPE(decltype(std::declval<const T&>() == std::declval<const U&>()), bool);218  ASSERT_SAME_TYPE(decltype(std::declval<const T&>() != std::declval<const U&>()), bool);219}220 221template <class T, class U = T>222void AssertEqualityConvertibleToBool()223{224    static_assert((std::is_convertible<decltype(std::declval<const T&>() == std::declval<const U&>()), bool>::value), "");225    static_assert((std::is_convertible<decltype(std::declval<const T&>() != std::declval<const U&>()), bool>::value), "");226}227 228struct LessAndEqComp {229  int value;230 231  TEST_CONSTEXPR_CXX14 LessAndEqComp(int v) : value(v) {}232 233  friend TEST_CONSTEXPR_CXX14 bool operator<(const LessAndEqComp& lhs, const LessAndEqComp& rhs) {234    return lhs.value < rhs.value;235  }236 237  friend TEST_CONSTEXPR_CXX14 bool operator==(const LessAndEqComp& lhs, const LessAndEqComp& rhs) {238    return lhs.value == rhs.value;239  }240};241 242#if TEST_STD_VER >= 20243 244struct StrongOrder {245  int value;246  constexpr StrongOrder(int v) : value(v) {}247  friend std::strong_ordering operator<=>(StrongOrder, StrongOrder) = default;248};249 250struct WeakOrder {251  int value;252  constexpr WeakOrder(int v) : value(v) {}253  friend std::weak_ordering operator<=>(WeakOrder, WeakOrder) = default;254};255 256struct PartialOrder {257  int value;258  constexpr PartialOrder(int v) : value(v) {}259  friend constexpr std::partial_ordering operator<=>(PartialOrder lhs, PartialOrder rhs) {260    if (lhs.value == std::numeric_limits<int>::min() || rhs.value == std::numeric_limits<int>::min())261      return std::partial_ordering::unordered;262    if (lhs.value == std::numeric_limits<int>::max() || rhs.value == std::numeric_limits<int>::max())263      return std::partial_ordering::unordered;264    return lhs.value <=> rhs.value;265  }266  friend constexpr bool operator==(PartialOrder lhs, PartialOrder rhs) {267    return (lhs <=> rhs) == std::partial_ordering::equivalent;268  }269};270 271template <typename T1, typename T2 = T1>272concept HasOperatorEqual = requires(T1 t1, T2 t2) { t1 == t2; };273 274template <typename T1, typename T2 = T1>275concept HasOperatorGreaterThan = requires(T1 t1, T2 t2) { t1 > t2; };276 277template <typename T1, typename T2 = T1>278concept HasOperatorGreaterThanEqual = requires(T1 t1, T2 t2) { t1 >= t2; };279template <typename T1, typename T2 = T1>280concept HasOperatorLessThan = requires(T1 t1, T2 t2) { t1 < t2; };281 282template <typename T1, typename T2 = T1>283concept HasOperatorLessThanEqual = requires(T1 t1, T2 t2) { t1 <= t2; };284 285template <typename T1, typename T2 = T1>286concept HasOperatorNotEqual = requires(T1 t1, T2 t2) { t1 != t2; };287 288template <typename T1, typename T2 = T1>289concept HasOperatorSpaceship = requires(T1 t1, T2 t2) { t1 <=> t2; };290 291struct NonComparable {};292static_assert(!std::equality_comparable<NonComparable>);293static_assert(!HasOperatorEqual<NonComparable>);294static_assert(!HasOperatorGreaterThan<NonComparable>);295static_assert(!HasOperatorGreaterThanEqual<NonComparable>);296static_assert(!HasOperatorLessThan<NonComparable>);297static_assert(!HasOperatorLessThanEqual<NonComparable>);298static_assert(!HasOperatorNotEqual<NonComparable>);299static_assert(!HasOperatorSpaceship<NonComparable>);300 301class EqualityComparable {302public:303  constexpr EqualityComparable(int value) : value_{value} {};304 305  friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default;306 307private:308  int value_;309};310static_assert(std::equality_comparable<EqualityComparable>);311static_assert(HasOperatorEqual<EqualityComparable>);312static_assert(HasOperatorNotEqual<EqualityComparable>);313 314class ThreeWayComparable {315public:316  constexpr ThreeWayComparable(int value) : value_{value} {};317 318  friend constexpr bool operator==(const ThreeWayComparable&, const ThreeWayComparable&) noexcept = default;319  friend constexpr std::strong_ordering320  operator<=>(const ThreeWayComparable&, const ThreeWayComparable&) noexcept = default;321 322private:323  int value_;324};325static_assert(std::equality_comparable<ThreeWayComparable>);326static_assert(std::three_way_comparable<ThreeWayComparable>);327static_assert(HasOperatorEqual<ThreeWayComparable>);328static_assert(HasOperatorGreaterThan<ThreeWayComparable>);329static_assert(HasOperatorGreaterThanEqual<ThreeWayComparable>);330static_assert(HasOperatorLessThan<ThreeWayComparable>);331static_assert(HasOperatorLessThanEqual<ThreeWayComparable>);332static_assert(HasOperatorNotEqual<ThreeWayComparable>);333static_assert(HasOperatorSpaceship<ThreeWayComparable>);334 335#endif // TEST_STD_VER >= 20336 337#endif // TEST_COMPARISONS_H338