forked from OSchip/llvm-project
[libc++] Implement C++20's P0476R2: std::bit_cast
Thanks to Arthur O'Dwyer for fixing up some of the tests. Differential Revision: https://reviews.llvm.org/D75960
This commit is contained in:
parent
8b58ab8ccd
commit
b1fb3d75c9
|
@ -190,7 +190,7 @@ Status
|
|||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_bind_front`` ``201907L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_bit_cast`` *unimplemented*
|
||||
``__cpp_lib_bit_cast`` ``201806L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_bitops`` *unimplemented*
|
||||
------------------------------------------------- -----------------
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
"`P0019R8 <https://wg21.link/P0019R8>`__","LWG","Atomic Ref","Rapperswil","",""
|
||||
"`P0458R2 <https://wg21.link/P0458R2>`__","LWG","Checking for Existence of an Element in Associative Containers","Rapperswil","|Complete|","13.0"
|
||||
"`P0475R1 <https://wg21.link/P0475R1>`__","LWG","LWG 2511: guaranteed copy elision for piecewise construction","Rapperswil","|Complete|",""
|
||||
"`P0476R2 <https://wg21.link/P0476R2>`__","LWG","Bit-casting object representations","Rapperswil","",""
|
||||
"`P0476R2 <https://wg21.link/P0476R2>`__","LWG","Bit-casting object representations","Rapperswil","|Complete|","14.0"
|
||||
"`P0528R3 <https://wg21.link/P0528R3>`__","CWG","The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange","Rapperswil","",""
|
||||
"`P0542R5 <https://wg21.link/P0542R5>`__","CWG","Support for contract based programming in C++","Rapperswil","*Removed in Cologne*","n/a"
|
||||
"`P0556R3 <https://wg21.link/P0556R3>`__","LWG","Integral power-of-2 operations","Rapperswil","|Complete|","9.0"
|
||||
|
|
|
|
@ -338,6 +338,7 @@ which no dialect declares as such (See the second form described above).
|
|||
* ``upper_bound``
|
||||
* ``lock_guard``'s constructors
|
||||
* ``as_const``
|
||||
* ``bit_cast``
|
||||
* ``forward``
|
||||
* ``move``
|
||||
* ``move_if_noexcept``
|
||||
|
|
|
@ -94,6 +94,7 @@ set(files
|
|||
__algorithm/upper_bound.h
|
||||
__availability
|
||||
__bit_reference
|
||||
__bit/bit_cast.h
|
||||
__bits
|
||||
__bsd_locale_defaults.h
|
||||
__bsd_locale_fallbacks.h
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___BIT_BIT_CAST_H
|
||||
#define _LIBCPP___BIT_BIT_CAST_H
|
||||
|
||||
#include <__config>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
|
||||
template<class _ToType, class _FromType, class = enable_if_t<
|
||||
sizeof(_ToType) == sizeof(_FromType) &&
|
||||
is_trivially_copyable_v<_ToType> &&
|
||||
is_trivially_copyable_v<_FromType>
|
||||
>>
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr _ToType bit_cast(_FromType const& __from) noexcept {
|
||||
return __builtin_bit_cast(_ToType, __from);
|
||||
}
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 17
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___BIT_BIT_CAST_H
|
|
@ -14,6 +14,9 @@
|
|||
bit synopsis
|
||||
|
||||
namespace std {
|
||||
// [bit.cast], bit_cast
|
||||
template<class To, class From>
|
||||
constexpr To bit_cast(const From& from) noexcept; // C++20
|
||||
|
||||
// [bit.pow.two], integral powers of 2
|
||||
template <class T>
|
||||
|
@ -54,8 +57,9 @@ namespace std {
|
|||
|
||||
*/
|
||||
|
||||
#include <__config>
|
||||
#include <__bit/bit_cast.h>
|
||||
#include <__bits> // __libcpp_clz
|
||||
#include <__config>
|
||||
#include <__debug>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
|
|
@ -335,6 +335,10 @@ module std [system] {
|
|||
module bit {
|
||||
header "bit"
|
||||
export *
|
||||
|
||||
module __bit {
|
||||
module bit_cast { private header "__bit/bit_cast.h" }
|
||||
}
|
||||
}
|
||||
module bitset {
|
||||
header "bitset"
|
||||
|
|
|
@ -286,7 +286,7 @@ __cpp_lib_void_t 201411L <type_traits>
|
|||
# define __cpp_lib_barrier 201907L
|
||||
# endif
|
||||
# define __cpp_lib_bind_front 201907L
|
||||
// # define __cpp_lib_bit_cast 201806L
|
||||
# define __cpp_lib_bit_cast 201806L
|
||||
// # define __cpp_lib_bitops 201907L
|
||||
# define __cpp_lib_bounded_array_traits 201902L
|
||||
# if !defined(_LIBCPP_HAS_NO_CHAR8_T)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: modules-build
|
||||
|
||||
// WARNING: This test was generated by 'generate_private_header_tests.py'
|
||||
// and should not be edited manually.
|
||||
|
||||
// expected-error@*:* {{use of private header from outside its module: '__bit/bit_cast.h'}}
|
||||
#include <__bit/bit_cast.h>
|
|
@ -18,6 +18,7 @@
|
|||
// be listed in `UsingLibcxx.rst` in the documentation for the extension.
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit> // bit_cast
|
||||
#include <cstddef> // to_integer
|
||||
#include <functional> // identity
|
||||
#include <iterator>
|
||||
|
@ -165,13 +166,13 @@ void test_template_cast_wrappers(LV&& lv, RV&& rv) {
|
|||
|
||||
void test_nontemplate_cast_wrappers()
|
||||
{
|
||||
#if TEST_STD_VER >= 17
|
||||
#if TEST_STD_VER > 14
|
||||
std::byte b{42};
|
||||
std::to_integer<int>(b);
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER >= 20
|
||||
// std::bit_cast<unsigned int>(42);
|
||||
#if TEST_STD_VER > 17
|
||||
std::bit_cast<unsigned int>(42);
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER > 20
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_NODISCARD
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit> // bit_cast
|
||||
#include <cstddef> // to_integer
|
||||
#include <functional> // identity
|
||||
#include <iterator>
|
||||
|
@ -323,14 +324,15 @@ void test_template_cast_wrappers(LV&& lv, RV&& rv) {
|
|||
|
||||
void test_nontemplate_cast_wrappers()
|
||||
{
|
||||
#if TEST_STD_VER >= 17
|
||||
#if TEST_STD_VER > 14
|
||||
std::byte b{42};
|
||||
// expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}}
|
||||
std::to_integer<int>(b);
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER >= 20
|
||||
// std::bit_cast<unsigned int>(42);
|
||||
#if TEST_STD_VER > 17
|
||||
// expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}}
|
||||
std::bit_cast<unsigned int>(42);
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER > 20
|
||||
|
|
|
@ -81,17 +81,11 @@
|
|||
|
||||
#elif TEST_STD_VER == 20
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should be defined in c++20"
|
||||
# endif
|
||||
# if __cpp_lib_bit_cast != 201806L
|
||||
# error "__cpp_lib_bit_cast should have the value 201806L in c++20"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should be defined in c++20"
|
||||
# endif
|
||||
# if __cpp_lib_bit_cast != 201806L
|
||||
# error "__cpp_lib_bit_cast should have the value 201806L in c++20"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
|
@ -123,17 +117,11 @@
|
|||
|
||||
#elif TEST_STD_VER > 20
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_bit_cast != 201806L
|
||||
# error "__cpp_lib_bit_cast should have the value 201806L in c++2b"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_bit_cast != 201806L
|
||||
# error "__cpp_lib_bit_cast should have the value 201806L in c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
|
|
|
@ -2264,17 +2264,11 @@
|
|||
# error "__cpp_lib_bind_front should have the value 201907L in c++20"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should be defined in c++20"
|
||||
# endif
|
||||
# if __cpp_lib_bit_cast != 201806L
|
||||
# error "__cpp_lib_bit_cast should have the value 201806L in c++20"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should be defined in c++20"
|
||||
# endif
|
||||
# if __cpp_lib_bit_cast != 201806L
|
||||
# error "__cpp_lib_bit_cast should have the value 201806L in c++20"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
|
@ -3421,17 +3415,11 @@
|
|||
# error "__cpp_lib_bind_front should have the value 201907L in c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_bit_cast != 201806L
|
||||
# error "__cpp_lib_bit_cast should have the value 201806L in c++2b"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_bit_cast
|
||||
# error "__cpp_lib_bit_cast should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_bit_cast != 201806L
|
||||
# error "__cpp_lib_bit_cast should have the value 201806L in c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// <bit>
|
||||
//
|
||||
// template<class To, class From>
|
||||
// constexpr To bit_cast(const From& from) noexcept; // C++20
|
||||
|
||||
// This test makes sure that std::bit_cast fails when any of the following
|
||||
// constraints are violated:
|
||||
//
|
||||
// (1.1) sizeof(To) == sizeof(From) is true;
|
||||
// (1.2) is_trivially_copyable_v<To> is true;
|
||||
// (1.3) is_trivially_copyable_v<From> is true.
|
||||
//
|
||||
// Also check that it's ill-formed when the return type would be
|
||||
// ill-formed, even though that is not explicitly mentioned in the
|
||||
// specification (but it can be inferred from the synopsis).
|
||||
|
||||
#include <bit>
|
||||
#include <concepts>
|
||||
|
||||
template<class To, class From>
|
||||
concept bit_cast_is_valid = requires(From from) {
|
||||
{ std::bit_cast<To>(from) } -> std::same_as<To>;
|
||||
};
|
||||
|
||||
// Types are not the same size
|
||||
namespace ns1 {
|
||||
struct To { char a; };
|
||||
struct From { char a; char b; };
|
||||
static_assert(!bit_cast_is_valid<To, From>);
|
||||
static_assert(!bit_cast_is_valid<From&, From>);
|
||||
}
|
||||
|
||||
// To is not trivially copyable
|
||||
namespace ns2 {
|
||||
struct To { char a; To(To const&); };
|
||||
struct From { char a; };
|
||||
static_assert(!bit_cast_is_valid<To, From>);
|
||||
}
|
||||
|
||||
// From is not trivially copyable
|
||||
namespace ns3 {
|
||||
struct To { char a; };
|
||||
struct From { char a; From(From const&); };
|
||||
static_assert(!bit_cast_is_valid<To, From>);
|
||||
}
|
||||
|
||||
// The return type is ill-formed
|
||||
namespace ns4 {
|
||||
struct From { char a; char b; };
|
||||
static_assert(!bit_cast_is_valid<char[2], From>);
|
||||
static_assert(!bit_cast_is_valid<int(), From>);
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
|
||||
// <bit>
|
||||
//
|
||||
// template<class To, class From>
|
||||
// constexpr To bit_cast(const From& from) noexcept; // C++20
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
// std::bit_cast does not preserve padding bits, so if T has padding bits,
|
||||
// the results might not memcmp cleanly.
|
||||
template<bool HasUniqueObjectRepresentations = true, typename T>
|
||||
void test_roundtrip_through_buffer(T from) {
|
||||
struct Buffer { char buffer[sizeof(T)]; };
|
||||
Buffer middle = std::bit_cast<Buffer>(from);
|
||||
T to = std::bit_cast<T>(middle);
|
||||
Buffer middle2 = std::bit_cast<Buffer>(to);
|
||||
|
||||
assert((from == to) == (from == from)); // because NaN
|
||||
|
||||
if constexpr (HasUniqueObjectRepresentations) {
|
||||
assert(std::memcmp(&from, &middle, sizeof(T)) == 0);
|
||||
assert(std::memcmp(&to, &middle, sizeof(T)) == 0);
|
||||
assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool HasUniqueObjectRepresentations = true, typename T>
|
||||
void test_roundtrip_through_nested_T(T from) {
|
||||
struct Nested { T x; };
|
||||
static_assert(sizeof(Nested) == sizeof(T));
|
||||
|
||||
Nested middle = std::bit_cast<Nested>(from);
|
||||
T to = std::bit_cast<T>(middle);
|
||||
Nested middle2 = std::bit_cast<Nested>(to);
|
||||
|
||||
assert((from == to) == (from == from)); // because NaN
|
||||
|
||||
if constexpr (HasUniqueObjectRepresentations) {
|
||||
assert(std::memcmp(&from, &middle, sizeof(T)) == 0);
|
||||
assert(std::memcmp(&to, &middle, sizeof(T)) == 0);
|
||||
assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Intermediate, bool HasUniqueObjectRepresentations = true, typename T>
|
||||
void test_roundtrip_through(T from) {
|
||||
static_assert(sizeof(Intermediate) == sizeof(T));
|
||||
|
||||
Intermediate middle = std::bit_cast<Intermediate>(from);
|
||||
T to = std::bit_cast<T>(middle);
|
||||
Intermediate middle2 = std::bit_cast<Intermediate>(to);
|
||||
|
||||
assert((from == to) == (from == from)); // because NaN
|
||||
|
||||
if constexpr (HasUniqueObjectRepresentations) {
|
||||
assert(std::memcmp(&from, &middle, sizeof(T)) == 0);
|
||||
assert(std::memcmp(&to, &middle, sizeof(T)) == 0);
|
||||
assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr std::array<T, 10> generate_signed_integral_values() {
|
||||
return {std::numeric_limits<T>::min(),
|
||||
std::numeric_limits<T>::min() + 1,
|
||||
static_cast<T>(-2), static_cast<T>(-1),
|
||||
static_cast<T>(0), static_cast<T>(1),
|
||||
static_cast<T>(2), static_cast<T>(3),
|
||||
std::numeric_limits<T>::max() - 1,
|
||||
std::numeric_limits<T>::max()};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr std::array<T, 6> generate_unsigned_integral_values() {
|
||||
return {static_cast<T>(0), static_cast<T>(1),
|
||||
static_cast<T>(2), static_cast<T>(3),
|
||||
std::numeric_limits<T>::max() - 1,
|
||||
std::numeric_limits<T>::max()};
|
||||
}
|
||||
|
||||
bool tests() {
|
||||
for (bool b : {false, true}) {
|
||||
test_roundtrip_through_nested_T(b);
|
||||
test_roundtrip_through_buffer(b);
|
||||
test_roundtrip_through<char>(b);
|
||||
}
|
||||
|
||||
for (char c : {'\0', 'a', 'b', 'c', 'd'}) {
|
||||
test_roundtrip_through_nested_T(c);
|
||||
test_roundtrip_through_buffer(c);
|
||||
}
|
||||
|
||||
// Fundamental signed integer types
|
||||
for (signed char i : generate_signed_integral_values<signed char>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
}
|
||||
|
||||
for (short i : generate_signed_integral_values<short>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
}
|
||||
|
||||
for (int i : generate_signed_integral_values<int>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<float>(i);
|
||||
}
|
||||
|
||||
for (long i : generate_signed_integral_values<long>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
}
|
||||
|
||||
for (long long i : generate_signed_integral_values<long long>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<double>(i);
|
||||
}
|
||||
|
||||
// Fundamental unsigned integer types
|
||||
for (unsigned char i : generate_unsigned_integral_values<unsigned char>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
}
|
||||
|
||||
for (unsigned short i : generate_unsigned_integral_values<unsigned short>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
}
|
||||
|
||||
for (unsigned int i : generate_unsigned_integral_values<unsigned int>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<float>(i);
|
||||
}
|
||||
|
||||
for (unsigned long i : generate_unsigned_integral_values<unsigned long>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
}
|
||||
|
||||
for (unsigned long long i : generate_unsigned_integral_values<unsigned long long>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<double>(i);
|
||||
}
|
||||
|
||||
// Fixed width signed integer types
|
||||
for (std::int32_t i : generate_signed_integral_values<std::int32_t>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<int>(i);
|
||||
test_roundtrip_through<std::uint32_t>(i);
|
||||
test_roundtrip_through<float>(i);
|
||||
}
|
||||
|
||||
for (std::int64_t i : generate_signed_integral_values<std::int64_t>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<long long>(i);
|
||||
test_roundtrip_through<std::uint64_t>(i);
|
||||
test_roundtrip_through<double>(i);
|
||||
}
|
||||
|
||||
// Fixed width unsigned integer types
|
||||
for (std::uint32_t i : generate_unsigned_integral_values<std::uint32_t>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<int>(i);
|
||||
test_roundtrip_through<std::int32_t>(i);
|
||||
test_roundtrip_through<float>(i);
|
||||
}
|
||||
|
||||
for (std::uint64_t i : generate_unsigned_integral_values<std::uint64_t>()) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<long long>(i);
|
||||
test_roundtrip_through<std::int64_t>(i);
|
||||
test_roundtrip_through<double>(i);
|
||||
}
|
||||
|
||||
// Floating point types
|
||||
for (float i : {0.0f, 1.0f, -1.0f, 10.0f, -10.0f, 1e10f, 1e-10f, 1e20f, 1e-20f, 2.71828f, 3.14159f,
|
||||
std::nanf(""),
|
||||
__builtin_nanf("0x55550001"), // NaN with a payload
|
||||
std::numeric_limits<float>::signaling_NaN(),
|
||||
std::numeric_limits<float>::quiet_NaN()}) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<int>(i);
|
||||
}
|
||||
|
||||
for (double i : {0.0, 1.0, -1.0, 10.0, -10.0, 1e10, 1e-10, 1e100, 1e-100,
|
||||
2.718281828459045,
|
||||
3.141592653589793238462643383279502884197169399375105820974944,
|
||||
std::nan(""),
|
||||
std::numeric_limits<double>::signaling_NaN(),
|
||||
std::numeric_limits<double>::quiet_NaN()}) {
|
||||
test_roundtrip_through_nested_T(i);
|
||||
test_roundtrip_through_buffer(i);
|
||||
test_roundtrip_through<long long>(i);
|
||||
}
|
||||
|
||||
for (long double i : {0.0l, 1.0l, -1.0l, 10.0l, -10.0l, 1e10l, 1e-10l, 1e100l, 1e-100l,
|
||||
2.718281828459045l,
|
||||
3.141592653589793238462643383279502884197169399375105820974944l,
|
||||
std::nanl(""),
|
||||
std::numeric_limits<long double>::signaling_NaN(),
|
||||
std::numeric_limits<long double>::quiet_NaN()}) {
|
||||
// Note that x86's `long double` has 80 value bits and 48 padding bits.
|
||||
test_roundtrip_through_nested_T<false>(i);
|
||||
test_roundtrip_through_buffer<false>(i);
|
||||
|
||||
// On arm64 on Apple platforms, long double is just double, so we don't
|
||||
// test against int128, but instead against double itself. Otherwise,
|
||||
// we test against int128 if we have those types available.
|
||||
#if defined(__aarch64__) && defined(__APPLE__)
|
||||
# define LONG_DOUBLE_IS_DOUBLE
|
||||
#endif
|
||||
|
||||
#if defined(LONG_DOUBLE_IS_DOUBLE)
|
||||
test_roundtrip_through<double, false>(i);
|
||||
#elif !defined(_LIBCPP_HAS_NO_INT128)
|
||||
test_roundtrip_through<__int128_t, false>(i);
|
||||
test_roundtrip_through<__uint128_t, false>(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: There doesn't seem to be a way to perform non-trivial correctness
|
||||
// tests inside constexpr.
|
||||
constexpr bool basic_constexpr_test() {
|
||||
struct Nested { char buffer[sizeof(int)]; };
|
||||
int from = 3;
|
||||
Nested middle = std::bit_cast<Nested>(from);
|
||||
int to = std::bit_cast<int>(middle);
|
||||
assert(from == to);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(basic_constexpr_test());
|
||||
return 0;
|
||||
}
|
|
@ -156,7 +156,6 @@ feature_test_macros = [ add_version_header(x) for x in [
|
|||
"name": "__cpp_lib_bit_cast",
|
||||
"values": { "c++20": 201806 },
|
||||
"headers": ["bit"],
|
||||
"unimplemented": True,
|
||||
}, {
|
||||
"name": "__cpp_lib_bitops",
|
||||
"values": { "c++20": 201907 },
|
||||
|
|
Loading…
Reference in New Issue