brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.4 KiB · 697d0c0 Raw
369 lines · cpp
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 9// <tuple>10 11// template <class... Types> class tuple;12 13// template<class... TTypes, class... UTypes>14//   auto15//   operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u);16// template<tuple-like UTuple>17//   friend constexpr auto operator<=>(const tuple& t, const UTuple& u); // since C++2318 19// UNSUPPORTED: c++03, c++11, c++14, c++1720 21#include "test_macros.h"22 23TEST_CLANG_DIAGNOSTIC_IGNORED("-Wsign-compare")24TEST_GCC_DIAGNOSTIC_IGNORED("-Wsign-compare")25TEST_MSVC_DIAGNOSTIC_IGNORED(4242 4244)26 27#include <array>28#include <cassert>29#include <compare>30#include <complex>31#include <limits>32#include <ranges>33#include <tuple>34#include <type_traits> // std::is_constant_evaluated35#include <utility>36 37// A custom three-way result type38struct CustomEquality {39  friend constexpr bool operator==(const CustomEquality&, int) noexcept { return true; }40  friend constexpr bool operator<(const CustomEquality&, int) noexcept { return false; }41  friend constexpr bool operator<(int, const CustomEquality&) noexcept { return false; }42};43 44constexpr bool test() {45  struct WeakSpaceship {46    constexpr bool operator==(const WeakSpaceship&) const { return true; }47    constexpr std::weak_ordering operator<=>(const WeakSpaceship&) const { return std::weak_ordering::equivalent; }48  };49 50  // Empty tuple51  {52    typedef std::tuple<> T0;53    // No member types yields strong ordering (all are equal).54    ASSERT_SAME_TYPE(decltype(T0() <=> T0()), std::strong_ordering);55    assert((T0() <=> T0()) == std::strong_ordering::equal);56  }57  // Mixed types with integers, which compare strongly ordered58  {59    typedef std::tuple<long> T1;60    typedef std::tuple<short> T2;61    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering);62    assert((T1(1) <=> T2(1)) == std::strong_ordering::equal);63    assert((T1(1) <=> T2(0)) == std::strong_ordering::greater);64    assert((T1(1) <=> T2(2)) == std::strong_ordering::less);65  }66  {67    typedef std::tuple<long, unsigned int> T1;68    typedef std::tuple<short, unsigned long> T2;69    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering);70    assert((T1(1, 2) <=> T2(1, 2)) == std::strong_ordering::equal);71    assert((T1(1, 2) <=> T2(0, 2)) == std::strong_ordering::greater);72    assert((T1(1, 2) <=> T2(2, 2)) == std::strong_ordering::less);73    assert((T1(1, 2) <=> T2(1, 1)) == std::strong_ordering::greater);74    assert((T1(1, 2) <=> T2(1, 3)) == std::strong_ordering::less);75  }76  {77    typedef std::tuple<long, int, unsigned short> T1;78    typedef std::tuple<short, long, unsigned int> T2;79    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering);80    assert((T1(1, 2, 3) <=> T2(1, 2, 3)) == std::strong_ordering::equal);81    assert((T1(1, 2, 3) <=> T2(0, 2, 3)) == std::strong_ordering::greater);82    assert((T1(1, 2, 3) <=> T2(2, 2, 3)) == std::strong_ordering::less);83    assert((T1(1, 2, 3) <=> T2(1, 1, 3)) == std::strong_ordering::greater);84    assert((T1(1, 2, 3) <=> T2(1, 3, 3)) == std::strong_ordering::less);85    assert((T1(1, 2, 3) <=> T2(1, 2, 2)) == std::strong_ordering::greater);86    assert((T1(1, 2, 3) <=> T2(1, 2, 4)) == std::strong_ordering::less);87  }88  // Mixed types with floating point, which compare partially ordered89  {90    typedef std::tuple<long> T1;91    typedef std::tuple<double> T2;92    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);93    assert((T1(1) <=> T2(1)) == std::partial_ordering::equivalent);94    assert((T1(1) <=> T2(0.9)) == std::partial_ordering::greater);95    assert((T1(1) <=> T2(1.1)) == std::partial_ordering::less);96  }97  {98    typedef std::tuple<long, float> T1;99    typedef std::tuple<double, unsigned int> T2;100    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);101    assert((T1(1, 2) <=> T2(1, 2)) == std::partial_ordering::equivalent);102    assert((T1(1, 2) <=> T2(0.9, 2)) == std::partial_ordering::greater);103    assert((T1(1, 2) <=> T2(1.1, 2)) == std::partial_ordering::less);104    assert((T1(1, 2) <=> T2(1, 1)) == std::partial_ordering::greater);105    assert((T1(1, 2) <=> T2(1, 3)) == std::partial_ordering::less);106  }107  {108    typedef std::tuple<short, float, double> T1;109    typedef std::tuple<double, long, unsigned int> T2;110    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);111    assert((T1(1, 2, 3) <=> T2(1, 2, 3)) == std::partial_ordering::equivalent);112    assert((T1(1, 2, 3) <=> T2(0.9, 2, 3)) == std::partial_ordering::greater);113    assert((T1(1, 2, 3) <=> T2(1.1, 2, 3)) == std::partial_ordering::less);114    assert((T1(1, 2, 3) <=> T2(1, 1, 3)) == std::partial_ordering::greater);115    assert((T1(1, 2, 3) <=> T2(1, 3, 3)) == std::partial_ordering::less);116    assert((T1(1, 2, 3) <=> T2(1, 2, 2)) == std::partial_ordering::greater);117    assert((T1(1, 2, 3) <=> T2(1, 2, 4)) == std::partial_ordering::less);118  }119  {120    typedef std::tuple<float> T1;121    typedef std::tuple<double> T2;122    constexpr double nan = std::numeric_limits<double>::quiet_NaN();123    // Comparisons with NaN and non-NaN are non-constexpr in GCC, so both sides must be NaN124    assert((T1(nan) <=> T2(nan)) == std::partial_ordering::unordered);125  }126  {127    typedef std::tuple<double, double> T1;128    typedef std::tuple<float, float> T2;129    constexpr double nan = std::numeric_limits<double>::quiet_NaN();130    assert((T1(nan, 2) <=> T2(nan, 2)) == std::partial_ordering::unordered);131    assert((T1(1, nan) <=> T2(1, nan)) == std::partial_ordering::unordered);132  }133  {134    typedef std::tuple<double, float, float> T1;135    typedef std::tuple<double, double, float> T2;136    constexpr double nan = std::numeric_limits<double>::quiet_NaN();137    assert((T1(nan, 2, 3) <=> T2(nan, 2, 3)) == std::partial_ordering::unordered);138    assert((T1(1, nan, 3) <=> T2(1, nan, 3)) == std::partial_ordering::unordered);139    assert((T1(1, 2, nan) <=> T2(1, 2, nan)) == std::partial_ordering::unordered);140  }141  // Ordering classes and synthesized three way comparison142  {143    typedef std::tuple<long, int, unsigned int> T1;144    typedef std::tuple<int, long, unsigned short> T2;145    // All strongly ordered members yields strong ordering.146    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering);147  }148  {149    typedef std::tuple<int, unsigned int, WeakSpaceship> T1;150    typedef std::tuple<int, unsigned long, WeakSpaceship> T2;151    // Strongly ordered members and a weakly ordered member yields weak ordering.152    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);153  }154  {155    typedef std::tuple<unsigned int, int, WeakSpaceship> T1;156    typedef std::tuple<double, long, WeakSpaceship> T2;157    // Doubles are partially ordered, so one partial, one strong, and one weak ordering158    // yields partial ordering.159    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);160  }161  {162    struct NoSpaceship {163      constexpr bool operator==(const NoSpaceship&) const { return true; }164      constexpr bool operator<(const NoSpaceship&) const { return false; }165    };166    typedef std::tuple<int, unsigned int, NoSpaceship> T1;167    typedef std::tuple<int, unsigned long, NoSpaceship> T2;168    // Strongly ordered members and a weakly ordered member (synthesized) yields weak ordering.169    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);170  }171  {172    struct SpaceshipNoEquals {173      constexpr std::strong_ordering operator<=>(const SpaceshipNoEquals&) const { return std::strong_ordering::equal; }174      constexpr bool operator<(const SpaceshipNoEquals&) const { return false; }175    };176    typedef std::tuple<int, unsigned int, SpaceshipNoEquals> T1;177    typedef std::tuple<int, unsigned long, SpaceshipNoEquals> T2;178    // Spaceship operator with no == operator falls back on the < operator and weak ordering.179    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);180  }181  {182    struct CustomSpaceship {183      constexpr CustomEquality operator<=>(const CustomSpaceship&) const { return CustomEquality(); }184    };185    typedef std::tuple<int, unsigned int, CustomSpaceship> T1;186    typedef std::tuple<short, unsigned long, CustomSpaceship> T2;187    typedef std::tuple<CustomSpaceship> T3;188    // Custom three way return types cannot be used in synthesized three way comparison,189    // but they can be used for (rewritten) operator< when synthesizing a weak ordering.190    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);191    ASSERT_SAME_TYPE(decltype(T3() <=> T3()), std::weak_ordering);192  }193  {194    typedef std::tuple<long, int> T1;195    typedef std::tuple<long, unsigned int> T2;196    // Even with the warning suppressed (-Wno-sign-compare) there should still be no <=> operator197    // between signed and unsigned types, so we should end up with a synthesized weak ordering.198    ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);199  }200 201#ifdef TEST_COMPILER_GCC202  // GCC cannot evaluate NaN @ non-NaN constexpr, so test that runtime-only.203  if (!std::is_constant_evaluated())204#endif205  {206    {207      typedef std::tuple<double> T1;208      typedef std::tuple<int> T2;209      constexpr double nan = std::numeric_limits<double>::quiet_NaN();210      ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);211      assert((T1(nan) <=> T2(1)) == std::partial_ordering::unordered);212    }213    {214      typedef std::tuple<double, double> T1;215      typedef std::tuple<int, int> T2;216      constexpr double nan = std::numeric_limits<double>::quiet_NaN();217      ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);218      assert((T1(nan, 2) <=> T2(1, 2)) == std::partial_ordering::unordered);219      assert((T1(1, nan) <=> T2(1, 2)) == std::partial_ordering::unordered);220    }221    {222      typedef std::tuple<double, double, double> T1;223      typedef std::tuple<int, int, int> T2;224      constexpr double nan = std::numeric_limits<double>::quiet_NaN();225      ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);226      assert((T1(nan, 2, 3) <=> T2(1, 2, 3)) == std::partial_ordering::unordered);227      assert((T1(1, nan, 3) <=> T2(1, 2, 3)) == std::partial_ordering::unordered);228      assert((T1(1, 2, nan) <=> T2(1, 2, 3)) == std::partial_ordering::unordered);229    }230  }231 232// Heterogeneous comparisons enabled by P2165R4.233#if TEST_STD_VER >= 23234  {235    using T1 = std::tuple<long, int>;236    using T2 = std::pair<int, long>;237    constexpr T1 t1{1, 2};238    constexpr T2 t2{1, 2};239    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);240    assert((t1 <=> t2) == std::strong_ordering::equal);241  }242  {243    using T1 = std::tuple<long, int>;244    using T2 = std::pair<int, long>;245    constexpr T1 t1{1, 2};246    constexpr T2 t2{1, 0};247    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);248    assert((t1 <=> t2) == std::strong_ordering::greater);249  }250  {251    using T1 = std::tuple<long, int>;252    using T2 = std::pair<double, long>;253    constexpr T1 t1{1, 2};254    constexpr T2 t2{1.1, 3};255    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);256    assert((t1 <=> t2) == std::partial_ordering::less);257  }258  {259    using T1 = std::tuple<long, int>;260    using T2 = std::pair<double, long>;261    constexpr T1 t1{1, 2};262    constexpr T2 t2{1.0, 2};263    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);264    assert((t1 <=> t2) == std::partial_ordering::equivalent);265  }266  {267    using T1 = std::tuple<long, int>;268    using T2 = std::pair<double, long>;269    constexpr T1 t1{1, 2};270    constexpr T2 t2{1.1, 3};271    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);272    assert((t1 <=> t2) == std::partial_ordering::less);273  }274  {275    using T1 = std::tuple<long, int>;276    using T2 = std::array<double, 2>;277    constexpr T1 t1{1, 2};278    constexpr T2 t2{1.0, 2.0};279    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);280    assert((t1 <=> t2) == std::partial_ordering::equivalent);281  }282  {283    using T1 = std::tuple<long, int>;284    using T2 = std::array<double, 2>;285    constexpr T1 t1{1, 2};286    constexpr T2 t2{1.1, 3.0};287    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);288    assert((t1 <=> t2) == std::partial_ordering::less);289  }290  {291    using T1 = std::tuple<const int*, const int*>;292    using T2 = std::ranges::subrange<const int*>;293 294    int arr[1]{};295    T1 t1{arr, arr + 1};296    T2 t2{arr};297    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);298    assert((t1 <=> t2) == std::strong_ordering::equal);299  }300  {301    using T1 = std::tuple<const int*, const int*>;302    using T2 = std::ranges::subrange<const int*>;303 304    int arr[1]{};305    T1 t1{arr + 1, arr + 1};306    T2 t2{arr};307    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);308    assert((t1 <=> t2) == std::strong_ordering::greater);309  }310  {311    constexpr std::tuple<WeakSpaceship, WeakSpaceship> t1{};312    constexpr std::pair<WeakSpaceship, WeakSpaceship> t2{};313    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::weak_ordering);314    assert((t1 <=> t2) == std::weak_ordering::equivalent);315  }316  {317    constexpr std::tuple<WeakSpaceship, WeakSpaceship> t1{};318    constexpr std::array<WeakSpaceship, 2> t2{};319    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::weak_ordering);320    assert((t1 <=> t2) == std::weak_ordering::equivalent);321  }322  {323    constexpr std::tuple<> t1{};324    constexpr std::array<int*, 0> t2{};325    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);326    assert((t1 <=> t2) == std::strong_ordering::equal);327  }328  {329    constexpr std::tuple<> t1{};330    constexpr std::array<double, 0> t2{};331    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);332    assert((t1 <=> t2) == std::strong_ordering::equal);333  }334  {335    constexpr std::tuple<> t1{};336    constexpr std::array<WeakSpaceship, 0> t2{};337    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);338    assert((t1 <=> t2) == std::strong_ordering::equal);339  }340#endif341#if TEST_STD_VER >= 26342  {343    using T1 = std::tuple<long, int>;344    using T2 = std::complex<double>;345    constexpr T1 t1{1, 2};346    constexpr T2 t2{1.0, 2.0};347    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);348    assert((t1 <=> t2) == std::partial_ordering::equivalent);349  }350  {351    using T1 = std::tuple<long, int>;352    using T2 = std::complex<double>;353    constexpr T1 t1{1, 2};354    constexpr T2 t2{1.1, 3.0};355    ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);356    assert((t1 <=> t2) == std::partial_ordering::less);357  }358#endif359 360  return true;361}362 363int main(int, char**) {364  test();365  static_assert(test());366 367  return 0;368}369