blob: 3da9f39d71a22e32b8f2b6294b5b189c88cc2b7b [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// <utility>
// cmp_equal, cmp_not_equal, cmp_less, cmp_less_equal, cmp_greater,
// cmp_greater_equal, in_range applied to _BitInt(N). Widths span the int,
// long long, and __int128 size boundaries for same-sign, mixed-sign, and
// in_range checks.
#include <cassert>
#include <limits>
#include <utility>
#include "test_macros.h"
#if TEST_HAS_BITINT
template <class T, class U>
constexpr bool test_same_sign() {
// Same signedness: trivial equality/ordering.
static_assert(std::cmp_equal(T(0), U(0)));
static_assert(std::cmp_equal(T(42), U(42)));
static_assert(!std::cmp_equal(T(0), U(1)));
static_assert(std::cmp_less(T(0), U(1)));
static_assert(!std::cmp_less(T(1), U(0)));
static_assert(std::cmp_less_equal(T(1), U(1)));
static_assert(std::cmp_greater_equal(T(1), U(1)));
static_assert(std::cmp_not_equal(T(0), U(1)));
return true;
}
template <class S, class U>
constexpr bool test_mixed_sign() {
// Signed vs unsigned of the SAME width: negative signed values must
// compare less than any unsigned value, regardless of the promotion
// branch chosen.
constexpr auto s_min = std::numeric_limits<S>::min();
constexpr auto u_max = std::numeric_limits<U>::max();
static_assert(std::cmp_less(S(-1), U(0)));
static_assert(!std::cmp_equal(S(-1), U(-1))); // U(-1) wraps to u_max
static_assert(std::cmp_less(s_min, U(0)));
static_assert(std::cmp_greater(u_max, S(0)));
static_assert(std::cmp_greater(u_max, s_min));
static_assert(std::cmp_less_equal(S(-1), U(0)));
static_assert(std::cmp_greater_equal(U(0), S(-1)));
// Equal-value mixed-sign: a non-negative signed value must compare
// equal to the corresponding unsigned value.
static_assert(std::cmp_equal(S(7), U(7)));
static_assert(std::cmp_equal(U(7), S(7)));
return true;
}
template <class S, class U>
constexpr bool test_in_range() {
// in_range relies on numeric_limits<_Tp>::min/max, which requires
// the digits10 fix (#193002) to be correct for odd _BitInt widths.
// Signed target: value in range.
static_assert(std::in_range<S>(S(0)));
static_assert(std::in_range<S>(std::numeric_limits<S>::max()));
static_assert(std::in_range<S>(std::numeric_limits<S>::min()));
// Signed target: value out of range via a wider unsigned source.
static_assert(!std::in_range<S>(std::numeric_limits<U>::max()));
// Unsigned target: negative signed value is out of range.
static_assert(!std::in_range<U>(S(-1)));
// Unsigned target: zero is in range.
static_assert(std::in_range<U>(S(0)));
static_assert(std::in_range<U>(std::numeric_limits<U>::max()));
return true;
}
constexpr bool test() {
// sizeof <= sizeof(int).
test_same_sign<_BitInt(7), _BitInt(7)>();
test_same_sign<unsigned _BitInt(7), unsigned _BitInt(7)>();
test_same_sign<_BitInt(13), _BitInt(13)>();
test_mixed_sign<_BitInt(7), unsigned _BitInt(7)>();
test_mixed_sign<_BitInt(13), unsigned _BitInt(13)>();
test_in_range<_BitInt(7), unsigned _BitInt(7)>();
test_in_range<_BitInt(13), unsigned _BitInt(13)>();
// signed _BitInt(32) fits in int; unsigned _BitInt(32) does not.
test_same_sign<_BitInt(32), _BitInt(32)>();
test_same_sign<unsigned _BitInt(32), unsigned _BitInt(32)>();
test_mixed_sign<_BitInt(32), unsigned _BitInt(32)>();
test_in_range<_BitInt(32), unsigned _BitInt(32)>();
// sizeof <= sizeof(long long).
test_same_sign<_BitInt(33), _BitInt(33)>();
test_same_sign<_BitInt(63), _BitInt(63)>();
test_same_sign<unsigned _BitInt(63), unsigned _BitInt(63)>();
test_mixed_sign<_BitInt(33), unsigned _BitInt(33)>();
test_mixed_sign<_BitInt(63), unsigned _BitInt(63)>();
test_in_range<_BitInt(33), unsigned _BitInt(33)>();
test_in_range<_BitInt(63), unsigned _BitInt(63)>();
// signed _BitInt(64) fits in long long; unsigned _BitInt(64) does not.
test_same_sign<_BitInt(64), _BitInt(64)>();
test_same_sign<unsigned _BitInt(64), unsigned _BitInt(64)>();
test_mixed_sign<_BitInt(64), unsigned _BitInt(64)>();
test_in_range<_BitInt(64), unsigned _BitInt(64)>();
# if __BITINT_MAXWIDTH__ >= 128
// sizeof > sizeof(long long).
test_same_sign<_BitInt(65), _BitInt(65)>();
test_same_sign<_BitInt(128), _BitInt(128)>();
test_same_sign<unsigned _BitInt(128), unsigned _BitInt(128)>();
test_mixed_sign<_BitInt(65), unsigned _BitInt(65)>();
test_mixed_sign<_BitInt(128), unsigned _BitInt(128)>();
test_in_range<_BitInt(65), unsigned _BitInt(65)>();
test_in_range<_BitInt(128), unsigned _BitInt(128)>();
# endif
# if __BITINT_MAXWIDTH__ >= 200
// Beyond __int128: widths with no builtin integer mapping.
test_same_sign<_BitInt(200), _BitInt(200)>();
test_same_sign<unsigned _BitInt(200), unsigned _BitInt(200)>();
test_mixed_sign<_BitInt(200), unsigned _BitInt(200)>();
test_in_range<_BitInt(200), unsigned _BitInt(200)>();
# endif
// Cross-width: narrow signed _BitInt vs wide unsigned builtin.
// Negative source must be reported as less than any non-negative target.
static_assert(std::cmp_less(_BitInt(7)(-1), 0ull));
static_assert(std::cmp_less(_BitInt(13)(-1), 0u));
static_assert(std::cmp_less(_BitInt(63)(-1), 0ull));
// Cross-type round-trip equality.
static_assert(std::cmp_equal(_BitInt(13)(42), 42));
static_assert(std::cmp_equal(42, _BitInt(13)(42)));
static_assert(std::cmp_equal(static_cast<unsigned _BitInt(13)>(42), 42u));
return true;
}
#endif // TEST_HAS_BITINT
int main(int, char**) {
#if TEST_HAS_BITINT
test();
static_assert(test());
#endif
return 0;
}