From patchwork Wed Nov 13 16:26:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1194377 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-513276-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="kFUvwlUW"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="dSKYJtgF"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47CqkW2jDQz9sPh for ; Thu, 14 Nov 2019 03:26:41 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=g3p1bCXGb9N5sbfyJFcVKFP14ddvPwoWyQGvVHzuWGGcmlqPhNrGE VMQbJNs0wPHh6P5l67fmTClDe05s3qM48TigDBdO2cE0Qq3QZuSPCxZSEDIdnM41 L53hyJ8Gp0jolLdYjO3TSAHTW10tU0K2brsactRrMBf3H2juWJW7Fk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=ehEQ966pqGyaOTCfCK/Zuq94XQQ=; b=kFUvwlUW7CijDh6JKckz LLh5RZ4zbp00Nc+t92Z1CY/FAXvvwwB3LSUcWT7tmm6/oLI6ErWtpQi3ChxVAUX3 I6enuCAO97+OvdKAFQe1F16RDmUfF9OTbypYla6nG8CBV5brw4c7TMSF2w78MdyK XyEHixe40Dd6bh0merHZnPE= Received: (qmail 124964 invoked by alias); 13 Nov 2019 16:26:21 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 124901 invoked by uid 89); 13 Nov 2019 16:26:21 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-16.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_NUMSUBJECT, KAM_SHORT autolearn=unavailable version=3.3.1 spammy=customization, sk:jwakely, HTo:U*libstdc, NaN X-HELO: us-smtp-delivery-1.mimecast.com Received: from us-smtp-2.mimecast.com (HELO us-smtp-delivery-1.mimecast.com) (205.139.110.61) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 13 Nov 2019 16:26:17 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573662375; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=TU62v5GbVqfZ9dnriUrhsjzRxndBs8DLLks0UuCp0sw=; b=dSKYJtgFmkyg6eDSJ/MckiNIhEcMxG5e/zSTaN5wgIe0gDQjlVZKBdH4js2aq2Nynn7uK9 3HAyQ7dEBZe+5dgV3ly/JCxFOOGMmHm9Wc4Fv6CKmayxTwmbTphgvHFLmq2O95Ng2F/1nz oZZECquh7vwfXME0Vfhw/UsoXaLNpjc= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-112-OemvjC7gMf-Y9tJo0mVZfQ-1; Wed, 13 Nov 2019 11:26:12 -0500 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 7C35194DDD; Wed, 13 Nov 2019 16:26:11 +0000 (UTC) Received: from localhost (unknown [10.33.36.17]) by smtp.corp.redhat.com (Postfix) with ESMTP id E406910C9EF6; Wed, 13 Nov 2019 16:26:10 +0000 (UTC) Date: Wed, 13 Nov 2019 16:26:11 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] libsupc++: Implement comparison algorithms for C++20 Message-ID: <20191113162611.GA22189@redhat.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.12.1 (2019-06-15) X-Mimecast-Spam-Score: 0 Content-Disposition: inline This is incomplete because std::strong_order doesn't support floating-point types. The partial_order and weak_order tests use VERIFY instead of static_assert because of PR 92431. * libsupc++/compare (strong_order, weak_order, partial_order) (compare_strong_order_fallback, compare_weak_order_fallback) (compare_partial_order_fallback): Define customization point objects for C++20. * testsuite/18_support/comparisons/algorithms/partial_order.cc: New test. * testsuite/18_support/comparisons/algorithms/strong_order.cc: New test. * testsuite/18_support/comparisons/algorithms/weak_order.cc: New test. Tested powerpc64le-linux, committed to trunk. commit e4dc0c07ed229d6efca300b42753fcd365db0085 Author: Jonathan Wakely Date: Thu Nov 7 21:58:46 2019 +0000 libsupc++: Implement comparison algorithms for C++20 This is incomplete because std::strong_order doesn't support floating-point types. The partial_order and weak_order tests use VERIFY instead of static_assert because of PR 92431. * libsupc++/compare (strong_order, weak_order, partial_order) (compare_strong_order_fallback, compare_weak_order_fallback) (compare_partial_order_fallback): Define customization point objects for C++20. * testsuite/18_support/comparisons/algorithms/partial_order.cc: New test. * testsuite/18_support/comparisons/algorithms/strong_order.cc: New test. * testsuite/18_support/comparisons/algorithms/weak_order.cc: New test. diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare index 94728e29de8..289145dea56 100644 --- a/libstdc++-v3/libsupc++/compare +++ b/libstdc++-v3/libsupc++/compare @@ -576,20 +576,346 @@ namespace std using is_transparent = void; }; + namespace __cmp_cust + { + template + constexpr weak_ordering + __fp_weak_ordering(_Tp __e, _Tp __f) + { + // Returns an integer with the same sign as the argument, and magnitude + // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5 + auto __cat = [](_Tp __fp) -> int { + const int __sign = __builtin_signbit(__fp) ? -1 : 1; + if (__builtin_isnormal(__fp)) + return (__fp == 0 ? 1 : 3) * __sign; + if (__builtin_isnan(__fp)) + return 5 * __sign; + if (int __inf = __builtin_isinf_sign(__fp)) + return 4 * __inf; + return 2 * __sign; + }; + + auto __po = __e <=> __f; + if (is_lt(__po)) + return weak_ordering::less; + else if (is_gt(__po)) + return weak_ordering::greater; + else if (__po == partial_ordering::equivalent) + return weak_ordering::equivalent; + else // unordered, at least one argument is NaN + { + // return -1 for negative nan, +1 for positive nan, 0 otherwise. + auto __isnan_sign = [](_Tp __fp) -> int { + return __builtin_isnan(__fp) + ? __builtin_signbit(__fp) ? -1 : 1 + : 0; + }; + auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f); + if (is_eq(__ord)) + return weak_ordering::equivalent; + else if (is_lt(__ord)) + return weak_ordering::less; + else + return weak_ordering::greater; + } + } + + template + concept __adl_strong = requires(_Tp&& __t, _Up&& __u) + { + strong_ordering(strong_order(static_cast<_Tp&&>(__t), + static_cast<_Up&&>(__u))); + }; + + template + concept __adl_weak = requires(_Tp&& __t, _Up&& __u) + { + weak_ordering(weak_order(static_cast<_Tp&&>(__t), + static_cast<_Up&&>(__u))); + }; + + template + concept __adl_partial = requires(_Tp&& __t, _Up&& __u) + { + partial_ordering(partial_order(static_cast<_Tp&&>(__t), + static_cast<_Up&&>(__u))); + }; + + template + concept __op_cmp = requires(_Tp&& __t, _Up&& __u) + { + _Ord(static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u)); + }; + + template + concept __strongly_ordered + = __adl_strong<_Tp, _Up> + // FIXME: || floating_point> + || __op_cmp; + + class _Strong_order + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (floating_point>) + return true; + else if constexpr (__adl_strong<_Tp, _Up>) + return noexcept(strong_ordering(strong_order(std::declval<_Tp>(), + std::declval<_Up>()))); + else if constexpr (__op_cmp) + return noexcept(std::declval<_Tp>() <=> std::declval<_Up>()); + } + + friend class _Weak_order; + friend class _Strong_fallback; + + public: + template + requires __strongly_ordered<_Tp, _Up> + constexpr strong_ordering + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + /* FIXME: + if constexpr (floating_point>) + return __cmp_cust::__fp_strong_order(__e, __f); + else */ if constexpr (__adl_strong<_Tp, _Up>) + return strong_ordering(strong_order(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f))); + else if constexpr (__op_cmp) + return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f); + } + }; + + template + concept __weakly_ordered + = floating_point> + || __adl_weak<_Tp, _Up> + || __op_cmp + || __strongly_ordered<_Tp, _Up>; + + class _Weak_order + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (floating_point>) + return true; + else if constexpr (__adl_weak<_Tp, _Up>) + return noexcept(weak_ordering(weak_order(std::declval<_Tp>(), + std::declval<_Up>()))); + else if constexpr (__op_cmp) + return noexcept(std::declval<_Tp>() <=> std::declval<_Up>()); + else if constexpr (__strongly_ordered<_Tp, _Up>) + return _Strong_order::_S_noexcept<_Tp, _Up>(); + } + + friend class _Partial_order; + friend class _Weak_fallback; + + public: + template + requires __weakly_ordered<_Tp, _Up> + constexpr weak_ordering + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (floating_point>) + return __cmp_cust::__fp_weak_ordering(__e, __f); + else if constexpr (__adl_weak<_Tp, _Up>) + return weak_ordering(weak_order(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f))); + else if constexpr (__op_cmp) + return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f); + else if constexpr (__strongly_ordered<_Tp, _Up>) + return _Strong_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + } + }; + + template + concept __partially_ordered + = __adl_partial<_Tp, _Up> + || __op_cmp + || __weakly_ordered<_Tp, _Up>; + + class _Partial_order + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (__adl_partial<_Tp, _Up>) + return noexcept(partial_ordering(partial_order(std::declval<_Tp>(), + std::declval<_Up>()))); + else if constexpr (__op_cmp) + return noexcept(std::declval<_Tp>() <=> std::declval<_Up>()); + else if constexpr (__weakly_ordered<_Tp, _Up>) + return _Weak_order::_S_noexcept<_Tp, _Up>(); + } + + friend class _Partial_fallback; + + public: + template + requires __partially_ordered<_Tp, _Up> + constexpr partial_ordering + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (__adl_partial<_Tp, _Up>) + return partial_ordering(partial_order(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f))); + else if constexpr (__op_cmp) + return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f); + else if constexpr (__weakly_ordered<_Tp, _Up>) + return _Weak_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + } + }; + + template + concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u) + { + { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) } + -> convertible_to; + { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) } + -> convertible_to; + }; + + class _Strong_fallback + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (__strongly_ordered<_Tp, _Up>) + return _Strong_order::_S_noexcept<_Tp, _Up>(); + else + return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) + && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); + } + + public: + template + requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> + constexpr decltype(auto) + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (__strongly_ordered<_Tp, _Up>) + return _Strong_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + else if constexpr (__op_eq_lt<_Tp, _Up>) + return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) + ? strong_ordering::equal + : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) + ? strong_ordering::less + : strong_ordering::greater; + } + }; + + class _Weak_fallback + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (__weakly_ordered<_Tp, _Up>) + return _Weak_order::_S_noexcept<_Tp, _Up>(); + else + return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) + && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); + } + + public: + template + requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> + constexpr decltype(auto) + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (__weakly_ordered<_Tp, _Up>) + return _Weak_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + else if constexpr (__op_eq_lt<_Tp, _Up>) + return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) + ? weak_ordering::equivalent + : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) + ? weak_ordering::less + : weak_ordering::greater; + } + }; + + class _Partial_fallback + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (__partially_ordered<_Tp, _Up>) + return _Partial_order::_S_noexcept<_Tp, _Up>(); + else + return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) + && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); + } + + public: + template + requires __partially_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> + constexpr decltype(auto) + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (__partially_ordered<_Tp, _Up>) + return _Partial_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + else if constexpr (__op_eq_lt<_Tp, _Up>) + return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) + ? partial_ordering::equivalent + : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) + ? partial_ordering::less + : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e) + ? partial_ordering::greater + : partial_ordering::unordered; + } + }; + } // namespace __cmp_cust + // [cmp.alg], comparison algorithms inline namespace __cmp_alg { - // TODO -#if 0 - inline constexpr unspecified strong_order = unspecified; - inline constexpr unspecified weak_order = unspecified; - inline constexpr unspecified partial_order = unspecified; - inline constexpr unspecified compare_strong_order_fallback = unspecified; - inline constexpr unspecified compare_weak_order_fallback = unspecified; - inline constexpr unspecified compare_partial_order_fallback = unspecified; -#endif + inline constexpr __cmp_cust::_Strong_order strong_order{}; + + inline constexpr __cmp_cust::_Weak_order weak_order{}; + + inline constexpr __cmp_cust::_Partial_order partial_order{}; + + inline constexpr __cmp_cust::_Strong_fallback + compare_strong_order_fallback{}; + + inline constexpr __cmp_cust::_Weak_fallback + compare_weak_order_fallback{}; + + inline constexpr __cmp_cust::_Partial_fallback + compare_partial_order_fallback{}; } -#endif +#endif // concepts } // namespace std #pragma GCC visibility pop diff --git a/libstdc++-v3/testsuite/18_support/comparisons/algorithms/partial_order.cc b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/partial_order.cc new file mode 100644 index 00000000000..ec85996e16d --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/partial_order.cc @@ -0,0 +1,118 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +using std::partial_order; +using std::partial_ordering; + +void +test01() +{ + int one = 1, two = 2; + + VERIFY( partial_order(one, two) == partial_ordering::less ); + VERIFY( partial_order(one, one) == partial_ordering::equivalent ); + VERIFY( partial_order(two, one) == partial_ordering::greater ); + static_assert( noexcept(partial_order(1, 1)) ); +} + +constexpr partial_ordering different_cv_quals(int i, const int j) +{ + return partial_order(i, j); +} + +void +test02() +{ + int fortytwo = 42, nines = 999, lots = 1000; + VERIFY( different_cv_quals(fortytwo, nines) == partial_ordering::less ); + VERIFY( different_cv_quals(-nines, -nines) == partial_ordering::equivalent ); + VERIFY( different_cv_quals(-nines, -lots) == partial_ordering::greater ); +} + +void +test03() +{ + double zero = 0.0; + VERIFY( partial_order(zero, zero) == partial_ordering::equivalent ); + VERIFY( partial_order(-zero, -zero) == partial_ordering::equivalent ); + VERIFY( partial_order(-zero, zero) == partial_ordering::equivalent ); + VERIFY( partial_order(zero, -zero) == partial_ordering::equivalent ); + static_assert( noexcept(partial_order(zero, 1.0)) ); + static_assert( partial_order(0.0, 1.0) == std::partial_ordering::less ); + + double min = std::numeric_limits::lowest(); + double max = std::numeric_limits::max(); + double nan = std::numeric_limits::quiet_NaN(); + double inf = std::numeric_limits::infinity(); + double denorm = std::numeric_limits::denorm_min(); + double smallest = std::numeric_limits::min(); + double epsilon = std::numeric_limits::epsilon(); + VERIFY( partial_order(denorm, smallest) == partial_ordering::less ); + VERIFY( partial_order(denorm, 0.0) == partial_ordering::greater ); + VERIFY( partial_order(0.0, nan) == partial_ordering::unordered ); + VERIFY( partial_order(nan, nan) == partial_ordering::unordered ); + VERIFY( partial_order(nan, 0.0) == partial_ordering::unordered ); + VERIFY( partial_order(-nan, 0.0) == partial_ordering::unordered ); + VERIFY( partial_order(-nan, min) == partial_ordering::unordered ); + VERIFY( partial_order(-inf, min) == partial_ordering::less ); + VERIFY( partial_order(-nan, -inf) == partial_ordering::unordered ); + VERIFY( partial_order(-inf, -nan) == partial_ordering::unordered ); + VERIFY( partial_order(max, inf) == partial_ordering::less ); + VERIFY( partial_order(inf, max) == partial_ordering::greater ); + VERIFY( partial_order(inf, nan) == partial_ordering::unordered ); + VERIFY( partial_order(1.0, 1.0+epsilon) == partial_ordering::less ); +} + +namespace N +{ + struct X { int i; }; + + constexpr partial_ordering operator<=>(X l, X r) + { + if (l.i < 0 && r.i < 0) + return partial_ordering::equivalent; + return r.i <=> l.i; + } +} + +void +test04() +{ + using N::X; + X one{1}; + X negone{-1}; + + VERIFY( partial_order(one, X{1}) == partial_ordering::equivalent ); + VERIFY( partial_order(negone, X{-2}) == partial_ordering::equivalent ); + VERIFY( partial_order(one, X{2}) == partial_ordering::greater ); + static_assert( !noexcept(partial_order(X{1}, X{2})) ); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/18_support/comparisons/algorithms/strong_order.cc b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/strong_order.cc new file mode 100644 index 00000000000..2c813494ce7 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/strong_order.cc @@ -0,0 +1,56 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include +#include + +using std::strong_order; +using std::strong_ordering; + +static_assert( strong_order(1, 2) == strong_ordering::less ); +static_assert( strong_order(1, 1) == strong_ordering::equal ); +static_assert( strong_order(2, 1) == strong_ordering::greater ); +static_assert( noexcept(strong_order(1, 1)) ); + +constexpr strong_ordering different_cv_quals(int i, const int j) +{ + return strong_order(i, j); +} +static_assert( different_cv_quals(42, 999) == strong_ordering::less ); +static_assert( different_cv_quals(-999, -999) == strong_ordering::equal ); +static_assert( different_cv_quals(-99, -111) == strong_ordering::greater ); + +namespace N +{ + struct X { int i; }; + + constexpr strong_ordering operator<=>(X l, X r) + { + if (l.i < 0 && r.i < 0) + return strong_ordering::equivalent; + return r.i <=> l.i; + } +} +using N::X; + +static_assert( strong_order(X{1}, X{1}) == strong_ordering::equal ); +static_assert( strong_order(X{-1}, X{-2}) == strong_ordering::equivalent ); +static_assert( strong_order(X{1}, X{2}) == strong_ordering::greater ); +static_assert( !noexcept(strong_order(X{1}, X{2})) ); diff --git a/libstdc++-v3/testsuite/18_support/comparisons/algorithms/weak_order.cc b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/weak_order.cc new file mode 100644 index 00000000000..03a162b86d5 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/weak_order.cc @@ -0,0 +1,119 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +using std::weak_order; +using std::weak_ordering; + +void +test01() +{ + int one = 1, two = 2; + + VERIFY( weak_order(one, two) == weak_ordering::less ); + VERIFY( weak_order(one, one) == weak_ordering::equivalent ); + VERIFY( weak_order(two, one) == weak_ordering::greater ); + static_assert( noexcept(weak_order(1, 1)) ); +} + +constexpr weak_ordering different_cv_quals(int i, const int j) +{ + return weak_order(i, j); +} + +void +test02() +{ + int fortytwo = 42, nines = 999, lots = 1000; + + VERIFY( different_cv_quals(fortytwo, nines) == weak_ordering::less ); + VERIFY( different_cv_quals(-nines, -nines) == weak_ordering::equivalent ); + VERIFY( different_cv_quals(-nines, -lots) == weak_ordering::greater ); +} + +void +test03() +{ + double zero = 0.0; + VERIFY( weak_order(zero, zero) == weak_ordering::equivalent ); + VERIFY( weak_order(-zero, -zero) == weak_ordering::equivalent ); + VERIFY( weak_order(-zero, zero) == weak_ordering::equivalent ); + VERIFY( weak_order(zero, -zero) == weak_ordering::equivalent ); + + double min = std::numeric_limits::lowest(); + double max = std::numeric_limits::max(); + double nan = std::numeric_limits::quiet_NaN(); + double inf = std::numeric_limits::infinity(); + double denorm = std::numeric_limits::denorm_min(); + double smallest = std::numeric_limits::min(); + double epsilon = std::numeric_limits::epsilon(); + VERIFY( weak_order(denorm, smallest) == weak_ordering::less ); + VERIFY( weak_order(denorm, 0.0) == weak_ordering::greater ); + VERIFY( weak_order(0.0, nan) == weak_ordering::less ); + VERIFY( weak_order(nan, nan) == weak_ordering::equivalent ); + VERIFY( weak_order(nan, -nan) == weak_ordering::greater ); + VERIFY( weak_order(-nan, nan) == weak_ordering::less ); + VERIFY( weak_order(nan, 0.0) == weak_ordering::greater ); + VERIFY( weak_order(-nan, 0.0) == weak_ordering::less ); + VERIFY( weak_order(-nan, min) == weak_ordering::less ); + VERIFY( weak_order(-inf, min) == weak_ordering::less ); + VERIFY( weak_order(-nan, -inf) == weak_ordering::less ); + VERIFY( weak_order(-inf, -nan) == weak_ordering::greater ); + VERIFY( weak_order(max, inf) == weak_ordering::less ); + VERIFY( weak_order(inf, max) == weak_ordering::greater ); + VERIFY( weak_order(inf, nan) == weak_ordering::less ); + VERIFY( weak_order(1.0, 1.0+epsilon) == weak_ordering::less ); +} + +namespace N +{ + struct X { int i; }; + + constexpr weak_ordering operator<=>(X l, X r) + { + if (l.i < 0 && r.i < 0) + return weak_ordering::equivalent; + return r.i <=> l.i; + } +} + +void +test04() +{ + using N::X; + X one{1}; + X negone{-1}; + + VERIFY( weak_order(one, X{1}) == weak_ordering::equivalent ); + VERIFY( weak_order(negone, X{-2}) == weak_ordering::equivalent ); + VERIFY( weak_order(one, X{2}) == weak_ordering::greater ); + static_assert( !noexcept(weak_order(X{1}, X{2})) ); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); +}