зеркало из https://github.com/microsoft/STL.git
add bit_cast and tests (#583)
* add bit_cast and tests Mirror MSVC-PR-228495
This commit is contained in:
Родитель
b8917400a9
Коммит
8a6c278743
10
stl/inc/bit
10
stl/inc/bit
|
@ -25,6 +25,16 @@ _STL_DISABLE_CLANG_WARNINGS
|
||||||
_STD_BEGIN
|
_STD_BEGIN
|
||||||
enum class endian { little = 0, big = 1, native = little };
|
enum class endian { little = 0, big = 1, native = little };
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_bit_cast // TRANSITION, VSO-1041044
|
||||||
|
template <class _To, class _From,
|
||||||
|
enable_if_t<conjunction_v<bool_constant<sizeof(_To) == sizeof(_From)>, is_trivially_copyable<_To>,
|
||||||
|
is_trivially_copyable<_From>>,
|
||||||
|
int> = 0>
|
||||||
|
_NODISCARD constexpr _To bit_cast(const _From& _Val) noexcept {
|
||||||
|
return __builtin_bit_cast(_To, _Val);
|
||||||
|
}
|
||||||
|
#endif // TRANSITION, VSO-1041044
|
||||||
|
|
||||||
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
|
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
|
||||||
template <class _Ty>
|
template <class _Ty>
|
||||||
inline constexpr bool _Is_standard_unsigned_integer =
|
inline constexpr bool _Is_standard_unsigned_integer =
|
||||||
|
|
|
@ -140,6 +140,7 @@
|
||||||
// P0457R2 starts_with()/ends_with() For basic_string/basic_string_view
|
// P0457R2 starts_with()/ends_with() For basic_string/basic_string_view
|
||||||
// P0458R2 contains() For Ordered And Unordered Associative Containers
|
// P0458R2 contains() For Ordered And Unordered Associative Containers
|
||||||
// P0463R1 endian
|
// P0463R1 endian
|
||||||
|
// P0476R2 <bit> bit_cast
|
||||||
// P0482R6 Library Support For char8_t
|
// P0482R6 Library Support For char8_t
|
||||||
// (mbrtoc8 and c8rtomb not yet implemented)
|
// (mbrtoc8 and c8rtomb not yet implemented)
|
||||||
// P0487R1 Fixing operator>>(basic_istream&, CharT*)
|
// P0487R1 Fixing operator>>(basic_istream&, CharT*)
|
||||||
|
@ -1078,6 +1079,10 @@
|
||||||
#define __cpp_lib_atomic_float 201711L
|
#define __cpp_lib_atomic_float 201711L
|
||||||
#define __cpp_lib_bind_front 201907L
|
#define __cpp_lib_bind_front 201907L
|
||||||
|
|
||||||
|
#ifndef __EDG__ // TRANSITION, VSO-1041044
|
||||||
|
#define __cpp_lib_bit_cast 201806L
|
||||||
|
#endif // __EDG__
|
||||||
|
|
||||||
#if defined(__clang__) || defined(__EDG__)
|
#if defined(__clang__) || defined(__EDG__)
|
||||||
#define __cpp_lib_bitops 201907L
|
#define __cpp_lib_bitops 201907L
|
||||||
#else // ^^^ Clang and EDG / MSVC vvv
|
#else // ^^^ Clang and EDG / MSVC vvv
|
||||||
|
|
|
@ -210,6 +210,7 @@ tests\P0357R3_supporting_incomplete_types_in_reference_wrapper
|
||||||
tests\P0414R2_shared_ptr_for_arrays
|
tests\P0414R2_shared_ptr_for_arrays
|
||||||
tests\P0426R1_constexpr_char_traits
|
tests\P0426R1_constexpr_char_traits
|
||||||
tests\P0433R2_deduction_guides
|
tests\P0433R2_deduction_guides
|
||||||
|
tests\P0476R2_bit_cast
|
||||||
tests\P0487R1_fixing_operator_shl_basic_istream_char_pointer
|
tests\P0487R1_fixing_operator_shl_basic_istream_char_pointer
|
||||||
tests\P0513R0_poisoning_the_hash
|
tests\P0513R0_poisoning_the_hash
|
||||||
tests\P0553R4_bit_rotating_and_counting_functions
|
tests\P0553R4_bit_rotating_and_counting_functions
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
RUNALL_INCLUDE ..\usual_latest_matrix.lst
|
|
@ -0,0 +1,266 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
#ifdef __EDG__ // TRANSITION, VSO-1041044
|
||||||
|
int main() {}
|
||||||
|
#else // __EDG__ ^^^ / vvv !__EDG__
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <bit>
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
// structure sizing depends on a packing of 8, which is the default
|
||||||
|
|
||||||
|
union test_union_1 {
|
||||||
|
char a;
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
union test_union_2 {
|
||||||
|
char a;
|
||||||
|
float b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct middle_class_1 {
|
||||||
|
double d;
|
||||||
|
virtual void a_member_function_1() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct middle_class_2 {
|
||||||
|
int a;
|
||||||
|
virtual void a_member_function_2() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct derived_class : middle_class_1, middle_class_2 {
|
||||||
|
virtual void a_member_function_2() override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_struct_1 {
|
||||||
|
char a;
|
||||||
|
// char[3]
|
||||||
|
int b;
|
||||||
|
short c;
|
||||||
|
// char[6]
|
||||||
|
double d;
|
||||||
|
|
||||||
|
void a_member_function() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_struct_2 {
|
||||||
|
short a;
|
||||||
|
// char[2]
|
||||||
|
float b;
|
||||||
|
float c;
|
||||||
|
int d;
|
||||||
|
unsigned int e;
|
||||||
|
char f;
|
||||||
|
// char[1]
|
||||||
|
short g;
|
||||||
|
|
||||||
|
void a_member_function() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_struct_3_member_fn_pointer {
|
||||||
|
char a;
|
||||||
|
// char[3]
|
||||||
|
int b;
|
||||||
|
short c;
|
||||||
|
char d[2];
|
||||||
|
void (test_struct_1::*fn)();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_struct_4_large_member_fn_pointer {
|
||||||
|
char a;
|
||||||
|
// char[3]
|
||||||
|
int b;
|
||||||
|
double c;
|
||||||
|
double d;
|
||||||
|
void (derived_class::*fn)(); // "large" member fn pointers are aligned to 8 on both x64 and x86
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_struct_5_struct {
|
||||||
|
char a;
|
||||||
|
// char[3]
|
||||||
|
int b;
|
||||||
|
double c;
|
||||||
|
double d;
|
||||||
|
void* e;
|
||||||
|
size_t f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_struct_6 {
|
||||||
|
char a;
|
||||||
|
// char[3]
|
||||||
|
int b;
|
||||||
|
int c;
|
||||||
|
// char[4] on x64
|
||||||
|
void* v;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_struct_7_member_fn_pointer {
|
||||||
|
char a;
|
||||||
|
// char[3]
|
||||||
|
int b;
|
||||||
|
int c;
|
||||||
|
void (test_struct_1::*fn)();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_struct_1_not_trivially_copyable {
|
||||||
|
char a;
|
||||||
|
// char[3]
|
||||||
|
int b;
|
||||||
|
short c;
|
||||||
|
// char[2]
|
||||||
|
double d;
|
||||||
|
|
||||||
|
test_struct_1_not_trivially_copyable& operator=(const test_struct_1_not_trivially_copyable&) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct test_struct_1_packed {
|
||||||
|
char a;
|
||||||
|
int b;
|
||||||
|
short c;
|
||||||
|
double d;
|
||||||
|
};
|
||||||
|
struct test_struct_2_packed {
|
||||||
|
short a;
|
||||||
|
float b;
|
||||||
|
float c;
|
||||||
|
int d;
|
||||||
|
unsigned int e;
|
||||||
|
char f;
|
||||||
|
short g;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
static_assert(sizeof(test_struct_1) == sizeof(test_struct_2));
|
||||||
|
|
||||||
|
template <typename To, typename From, typename = void>
|
||||||
|
constexpr bool bit_cast_invocable = false;
|
||||||
|
|
||||||
|
template <typename To, typename From>
|
||||||
|
constexpr bool bit_cast_invocable<To, From, std::void_t<decltype(std::bit_cast<To>(std::declval<From>()))>> = true;
|
||||||
|
|
||||||
|
template <int zero = 0, int = ((void) std::bit_cast<test_union_1>(test_union_2{}), zero)>
|
||||||
|
constexpr bool bit_cast_is_constexpr_union(int) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool bit_cast_is_constexpr_union(long) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int zero = 0, int = ((void) std::bit_cast<float*>(nullptr), zero)>
|
||||||
|
constexpr bool bit_cast_is_constexpr_pointer(int) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool bit_cast_is_constexpr_pointer(long) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int zero = 0,
|
||||||
|
int = ((void) std::bit_cast<void (test_struct_1::*)()>(&test_struct_2::a_member_function), zero)>
|
||||||
|
constexpr bool bit_cast_is_constexpr_member_fn_pointer(int) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool bit_cast_is_constexpr_member_fn_pointer(long) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int zero = 0, int = ((void) std::bit_cast<test_struct_6>(test_struct_3_member_fn_pointer{}), zero)>
|
||||||
|
constexpr bool bit_cast_is_constexpr_pmf_datamember(int) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool bit_cast_is_constexpr_pmf_datamember(long) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int zero = 0,
|
||||||
|
int = ((void) std::bit_cast<test_struct_5_struct>(test_struct_4_large_member_fn_pointer{}), zero)>
|
||||||
|
constexpr bool bit_cast_is_constexpr_large_member_fn_pointer(int) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool bit_cast_is_constexpr_large_member_fn_pointer(long) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename To, typename From>
|
||||||
|
void zero_initialized_round_trip() {
|
||||||
|
From before{};
|
||||||
|
To middle = std::bit_cast<To>(before);
|
||||||
|
assert(memcmp(&before, &middle, sizeof(From)) == 0);
|
||||||
|
From after = std::bit_cast<From>(middle);
|
||||||
|
assert(memcmp(&before, &after, sizeof(From)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool test_float() {
|
||||||
|
unsigned int as_int = std::bit_cast<unsigned int>(0x0.000002p-126f);
|
||||||
|
assert(as_int == 1);
|
||||||
|
assert(std::bit_cast<float>(as_int) == 0x0.000002p-126f);
|
||||||
|
as_int = std::bit_cast<unsigned int>(0x1.1p1f);
|
||||||
|
assert(as_int == 0x40080000);
|
||||||
|
assert(std::bit_cast<float>(as_int) == 0x1.1p1f);
|
||||||
|
as_int = std::bit_cast<unsigned int>(0x0.0p0f);
|
||||||
|
assert(as_int == 0);
|
||||||
|
assert(std::bit_cast<float>(as_int) == 0x0.0p0f);
|
||||||
|
if (!std::is_constant_evaluated()) {
|
||||||
|
assert(std::signbit(std::bit_cast<float>(as_int)) == false);
|
||||||
|
}
|
||||||
|
as_int = std::bit_cast<unsigned int>(-0x0.0p0f);
|
||||||
|
assert(as_int == 0x80000000);
|
||||||
|
assert(std::bit_cast<float>(as_int) == -0x0.0p0f);
|
||||||
|
if (!std::is_constant_evaluated()) {
|
||||||
|
assert(std::signbit(std::bit_cast<float>(as_int)) == true);
|
||||||
|
}
|
||||||
|
// signaling nan
|
||||||
|
as_int = 0x7fc00001;
|
||||||
|
float snan = std::bit_cast<float>(as_int);
|
||||||
|
assert(as_int == std::bit_cast<unsigned int>(snan));
|
||||||
|
as_int = std::bit_cast<unsigned int>(std::numeric_limits<float>::infinity());
|
||||||
|
assert(as_int == 0x7f800000);
|
||||||
|
assert(std::bit_cast<float>(as_int) == std::numeric_limits<float>::infinity());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
static_assert(!bit_cast_invocable<test_struct_2_packed, test_struct_1_packed>);
|
||||||
|
static_assert(!bit_cast_invocable<test_struct_1_not_trivially_copyable, test_struct_1>);
|
||||||
|
static_assert(!bit_cast_invocable<test_struct_1, test_struct_1_not_trivially_copyable>);
|
||||||
|
static_assert(!bit_cast_invocable<test_struct_1_not_trivially_copyable, test_struct_1_not_trivially_copyable>);
|
||||||
|
static_assert(bit_cast_invocable<test_union_1, test_union_2>);
|
||||||
|
static_assert(bit_cast_invocable<ptrdiff_t, void (test_struct_1::*)()>);
|
||||||
|
static_assert(bit_cast_invocable<ptrdiff_t, void (*)()>);
|
||||||
|
static_assert(bit_cast_invocable<test_struct_1, test_struct_2>);
|
||||||
|
static_assert(bit_cast_invocable<test_struct_4_large_member_fn_pointer, test_struct_5_struct>);
|
||||||
|
|
||||||
|
// tests for conditions on constexprness
|
||||||
|
static_assert(!bit_cast_is_constexpr_union(0));
|
||||||
|
static_assert(!bit_cast_is_constexpr_pointer(0));
|
||||||
|
static_assert(!bit_cast_is_constexpr_member_fn_pointer(0));
|
||||||
|
static_assert(!bit_cast_is_constexpr_pmf_datamember(0));
|
||||||
|
static_assert(!bit_cast_is_constexpr_large_member_fn_pointer(0));
|
||||||
|
|
||||||
|
zero_initialized_round_trip<test_struct_1, test_struct_2>();
|
||||||
|
zero_initialized_round_trip<test_struct_3_member_fn_pointer, test_struct_3_member_fn_pointer>();
|
||||||
|
zero_initialized_round_trip<test_struct_3_member_fn_pointer, test_struct_7_member_fn_pointer>();
|
||||||
|
zero_initialized_round_trip<test_struct_4_large_member_fn_pointer, test_struct_5_struct>();
|
||||||
|
zero_initialized_round_trip<test_struct_6, test_struct_3_member_fn_pointer>();
|
||||||
|
zero_initialized_round_trip<float, int>();
|
||||||
|
zero_initialized_round_trip<double, long long>();
|
||||||
|
zero_initialized_round_trip<unsigned int, float>();
|
||||||
|
|
||||||
|
assert(test_float());
|
||||||
|
static_assert(test_float());
|
||||||
|
}
|
||||||
|
#endif // __EDG__
|
|
@ -1513,6 +1513,20 @@ STATIC_ASSERT(__cpp_lib_bind_front == 201907L);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CXX20_MODE && !defined(__EDG__) // TRANSITION, VSO-1041044
|
||||||
|
#ifndef __cpp_lib_bit_cast
|
||||||
|
#error BOOM
|
||||||
|
#elif __cpp_lib_bit_cast != 201806L
|
||||||
|
#error BOOM
|
||||||
|
#else
|
||||||
|
STATIC_ASSERT(__cpp_lib_bit_cast == 201806L);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef __cpp_lib_bit_cast
|
||||||
|
#error BOOM
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CXX20_MODE && (defined(__clang__) || defined(__EDG__)) // TRANSITION, VSO-1020212
|
#if CXX20_MODE && (defined(__clang__) || defined(__EDG__)) // TRANSITION, VSO-1020212
|
||||||
#ifndef __cpp_lib_bitops
|
#ifndef __cpp_lib_bitops
|
||||||
#error BOOM
|
#error BOOM
|
||||||
|
|
Загрузка…
Ссылка в новой задаче