From a4c658c3c800639f466a3d6bb5925eea4f8570ab Mon Sep 17 00:00:00 2001 From: neargye Date: Tue, 10 Dec 2019 17:49:04 +0500 Subject: [PATCH 01/17] fix #190 --- stl/inc/complex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 01986df49ea..0fb3cacd12e 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -531,12 +531,12 @@ public: constexpr _Complex_base(const _Ty& _Realval, const _Ty& _Imagval) : _Valbase{{_Realval, _Imagval}} {} - _Ty real(const _Ty& _Right) { // set real component - return this->_Val[_RE] = _Right; + void real(const _Ty& _Right) { // set real component + this->_Val[_RE] = _Right; } - _Ty imag(const _Ty& _Right) { // set imaginary component - return this->_Val[_IM] = _Right; + void imag(const _Ty& _Right) { // set imaginary component + this->_Val[_IM] = _Right; } _NODISCARD constexpr _Ty real() const { // return real component From 73433f7d4e71ce5e640085467ac66a85be3eacb4 Mon Sep 17 00:00:00 2001 From: neargye Date: Tue, 10 Dec 2019 18:10:26 +0500 Subject: [PATCH 02/17] Mark constexpr: * operator+ * operator- * operator* * operator/ (partially) * norm * conj * real * imag * operator= * operator+= * operator-= * operator-= * operator*= * operator/= (partially) --- stl/inc/complex | 139 +++++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 71 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 0fb3cacd12e..89f9923093d 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -531,11 +531,11 @@ public: constexpr _Complex_base(const _Ty& _Realval, const _Ty& _Imagval) : _Valbase{{_Realval, _Imagval}} {} - void real(const _Ty& _Right) { // set real component + _CONSTEXPR20 void real(const _Ty& _Right) { // set real component this->_Val[_RE] = _Right; } - void imag(const _Ty& _Right) { // set imaginary component + _CONSTEXPR20 void imag(const _Ty& _Right) { // set imaginary component this->_Val[_IM] = _Right; } @@ -549,19 +549,19 @@ public: protected: template - void _Add(const complex<_Other>& _Right) { + _CONSTEXPR20 void _Add(const complex<_Other>& _Right) { this->_Val[_RE] = this->_Val[_RE] + static_cast<_Ty>(_Right.real()); this->_Val[_IM] = this->_Val[_IM] + static_cast<_Ty>(_Right.imag()); } template - void _Sub(const complex<_Other>& _Right) { + _CONSTEXPR20 void _Sub(const complex<_Other>& _Right) { this->_Val[_RE] = this->_Val[_RE] - static_cast<_Ty>(_Right.real()); this->_Val[_IM] = this->_Val[_IM] - static_cast<_Ty>(_Right.imag()); } template - void _Mul(const complex<_Other>& _Right) { + _CONSTEXPR20 void _Mul(const complex<_Other>& _Right) { _Ty _Rightreal = static_cast<_Ty>(_Right.real()); _Ty _Rightimag = static_cast<_Ty>(_Right.imag()); @@ -635,46 +635,45 @@ public: : _Complex_base( static_cast(_Right._Val[_RE]), static_cast(_Right._Val[_IM])) {} - complex<_Ty>& operator=(const _Ty& _Right) { - + _CONSTEXPR20 complex<_Ty>& operator=(const _Ty& _Right) { _Val[_RE] = _Right; _Val[_IM] = 0; return *this; } - complex& operator+=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator+=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] + _Right; return *this; } - complex& operator-=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator-=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] - _Right; return *this; } - complex& operator*=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator*=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] * _Right; _Val[_IM] = _Val[_IM] * _Right; return *this; } - complex& operator/=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator/=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] / _Right; _Val[_IM] = _Val[_IM] / _Right; return *this; } - complex& operator+=(const complex& _Right) { + _CONSTEXPR20 complex& operator+=(const complex& _Right) { this->_Add(_Right); return *this; } - complex& operator-=(const complex& _Right) { + _CONSTEXPR20 complex& operator-=(const complex& _Right) { this->_Sub(_Right); return *this; } - complex& operator*=(const complex& _Right) { + _CONSTEXPR20 complex& operator*=(const complex& _Right) { this->_Mul(_Right); return *this; } @@ -685,26 +684,26 @@ public: } template - complex& operator=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator=(const complex<_Other>& _Right) { _Val[_RE] = static_cast<_Ty>(_Right._Val[_RE]); _Val[_IM] = static_cast<_Ty>(_Right._Val[_IM]); return *this; } template - complex& operator+=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator+=(const complex<_Other>& _Right) { this->_Add(_Right); return *this; } template - complex& operator-=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator-=(const complex<_Other>& _Right) { this->_Sub(_Right); return *this; } template - complex& operator*=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator*=(const complex<_Other>& _Right) { this->_Mul(_Right); return *this; } @@ -735,46 +734,45 @@ public: : _Complex_base( static_cast(_Right._Val[_RE]), static_cast(_Right._Val[_IM])) {} - complex<_Ty>& operator=(const _Ty& _Right) { - + _CONSTEXPR20 complex<_Ty>& operator=(const _Ty& _Right) { _Val[_RE] = _Right; _Val[_IM] = 0; return *this; } - complex& operator+=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator+=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] + _Right; return *this; } - complex& operator-=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator-=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] - _Right; return *this; } - complex& operator*=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator*=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] * _Right; _Val[_IM] = _Val[_IM] * _Right; return *this; } - complex& operator/=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator/=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] / _Right; _Val[_IM] = _Val[_IM] / _Right; return *this; } - complex& operator+=(const complex& _Right) { + _CONSTEXPR20 complex& operator+=(const complex& _Right) { this->_Add(_Right); return *this; } - complex& operator-=(const complex& _Right) { + _CONSTEXPR20 complex& operator-=(const complex& _Right) { this->_Sub(_Right); return *this; } - complex& operator*=(const complex& _Right) { + _CONSTEXPR20 complex& operator*=(const complex& _Right) { this->_Mul(_Right); return *this; } @@ -785,26 +783,26 @@ public: } template - complex& operator=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator=(const complex<_Other>& _Right) { _Val[_RE] = static_cast<_Ty>(_Right._Val[_RE]); _Val[_IM] = static_cast<_Ty>(_Right._Val[_IM]); return *this; } template - complex& operator+=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator+=(const complex<_Other>& _Right) { this->_Add(_Right); return *this; } template - complex& operator-=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator-=(const complex<_Other>& _Right) { this->_Sub(_Right); return *this; } template - complex& operator*=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator*=(const complex<_Other>& _Right) { this->_Mul(_Right); return *this; } @@ -831,46 +829,45 @@ public: constexpr complex(const _Lcomplex_value& _Right) : _Complex_base(_Right._Val[_RE], _Right._Val[_IM]) {} - complex<_Ty>& operator=(const _Ty& _Right) { - + _CONSTEXPR20 complex<_Ty>& operator=(const _Ty& _Right) { _Val[_RE] = _Right; _Val[_IM] = 0; return *this; } - complex& operator+=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator+=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] + _Right; return *this; } - complex& operator-=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator-=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] - _Right; return *this; } - complex& operator*=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator*=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] * _Right; _Val[_IM] = _Val[_IM] * _Right; return *this; } - complex& operator/=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator/=(const _Ty& _Right) { _Val[_RE] = _Val[_RE] / _Right; _Val[_IM] = _Val[_IM] / _Right; return *this; } - complex& operator+=(const complex& _Right) { + _CONSTEXPR20 complex& operator+=(const complex& _Right) { this->_Add(_Right); return *this; } - complex& operator-=(const complex& _Right) { + _CONSTEXPR20 complex& operator-=(const complex& _Right) { this->_Sub(_Right); return *this; } - complex& operator*=(const complex& _Right) { + _CONSTEXPR20 complex& operator*=(const complex& _Right) { this->_Mul(_Right); return *this; } @@ -881,26 +878,26 @@ public: } template - complex& operator=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator=(const complex<_Other>& _Right) { _Val[_RE] = static_cast<_Ty>(_Right._Val[_RE]); _Val[_IM] = static_cast<_Ty>(_Right._Val[_IM]); return *this; } template - complex& operator+=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator+=(const complex<_Other>& _Right) { this->_Add(_Right); return *this; } template - complex& operator-=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator-=(const complex<_Other>& _Right) { this->_Sub(_Right); return *this; } template - complex& operator*=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator*=(const complex<_Other>& _Right) { this->_Mul(_Right); return *this; } @@ -939,7 +936,7 @@ public: constexpr complex(const _Ty& _Realval = _Ty(), const _Ty& _Imagval = _Ty()) : _Mybase(_Realval, _Imagval) {} - complex& operator=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator=(const _Ty& _Right) { this->_Val[_RE] = _Right; this->_Val[_IM] = _Ty(); return *this; @@ -950,45 +947,45 @@ public: : _Mybase(static_cast<_Ty>(_Right.real()), static_cast<_Ty>(_Right.imag())) {} template - complex& operator=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator=(const complex<_Other>& _Right) { this->_Val[_RE] = static_cast<_Ty>(_Right.real()); this->_Val[_IM] = static_cast<_Ty>(_Right.imag()); return *this; } - complex& operator+=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator+=(const _Ty& _Right) { this->_Val[_RE] = this->_Val[_RE] + _Right; return *this; } - complex& operator-=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator-=(const _Ty& _Right) { this->_Val[_RE] = this->_Val[_RE] - _Right; return *this; } - complex& operator*=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator*=(const _Ty& _Right) { this->_Val[_RE] = this->_Val[_RE] * _Right; this->_Val[_IM] = this->_Val[_IM] * _Right; return *this; } - complex& operator/=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator/=(const _Ty& _Right) { this->_Val[_RE] = this->_Val[_RE] / _Right; this->_Val[_IM] = this->_Val[_IM] / _Right; return *this; } - complex& operator+=(const complex& _Right) { + _CONSTEXPR20 complex& operator+=(const complex& _Right) { this->_Add(_Right); return *this; } - complex& operator-=(const complex& _Right) { + _CONSTEXPR20 complex& operator-=(const complex& _Right) { this->_Sub(_Right); return *this; } - complex& operator*=(const complex& _Right) { + _CONSTEXPR20 complex& operator*=(const complex& _Right) { this->_Mul(_Right); return *this; } @@ -999,19 +996,19 @@ public: } template - complex& operator+=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator+=(const complex<_Other>& _Right) { this->_Add(_Right); return *this; } template - complex& operator-=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator-=(const complex<_Other>& _Right) { this->_Sub(_Right); return *this; } template - complex& operator*=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator*=(const complex<_Other>& _Right) { this->_Mul(_Right); return *this; } @@ -1025,21 +1022,21 @@ public: // FUNCTION TEMPLATE operator+ template -_NODISCARD complex<_Ty> operator+(const complex<_Ty>& _Left, const complex<_Ty>& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator+(const complex<_Ty>& _Left, const complex<_Ty>& _Right) { complex<_Ty> _Tmp(_Left); _Tmp += _Right; return _Tmp; } template -_NODISCARD complex<_Ty> operator+(const complex<_Ty>& _Left, const _Ty& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator+(const complex<_Ty>& _Left, const _Ty& _Right) { complex<_Ty> _Tmp(_Left); _Tmp.real(_Tmp.real() + _Right); return _Tmp; } template -_NODISCARD complex<_Ty> operator+(const _Ty& _Left, const complex<_Ty>& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator+(const _Ty& _Left, const complex<_Ty>& _Right) { complex<_Ty> _Tmp(_Left); _Tmp += _Right; return _Tmp; @@ -1047,21 +1044,21 @@ _NODISCARD complex<_Ty> operator+(const _Ty& _Left, const complex<_Ty>& _Right) // FUNCTION TEMPLATE operator- template -_NODISCARD complex<_Ty> operator-(const complex<_Ty>& _Left, const complex<_Ty>& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator-(const complex<_Ty>& _Left, const complex<_Ty>& _Right) { complex<_Ty> _Tmp(_Left); _Tmp -= _Right; return _Tmp; } template -_NODISCARD complex<_Ty> operator-(const complex<_Ty>& _Left, const _Ty& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator-(const complex<_Ty>& _Left, const _Ty& _Right) { complex<_Ty> _Tmp(_Left); _Tmp.real(_Tmp.real() - _Right); return _Tmp; } template -_NODISCARD complex<_Ty> operator-(const _Ty& _Left, const complex<_Ty>& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator-(const _Ty& _Left, const complex<_Ty>& _Right) { complex<_Ty> _Tmp(_Left); _Tmp -= _Right; return _Tmp; @@ -1069,14 +1066,14 @@ _NODISCARD complex<_Ty> operator-(const _Ty& _Left, const complex<_Ty>& _Right) // FUNCTION TEMPLATE operator* template -_NODISCARD complex<_Ty> operator*(const complex<_Ty>& _Left, const complex<_Ty>& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator*(const complex<_Ty>& _Left, const complex<_Ty>& _Right) { complex<_Ty> _Tmp(_Left); _Tmp *= _Right; return _Tmp; } template -_NODISCARD complex<_Ty> operator*(const complex<_Ty>& _Left, const _Ty& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator*(const complex<_Ty>& _Left, const _Ty& _Right) { complex<_Ty> _Tmp(_Left); _Tmp.real(_Tmp.real() * _Right); _Tmp.imag(_Tmp.imag() * _Right); @@ -1084,7 +1081,7 @@ _NODISCARD complex<_Ty> operator*(const complex<_Ty>& _Left, const _Ty& _Right) } template -_NODISCARD complex<_Ty> operator*(const _Ty& _Left, const complex<_Ty>& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator*(const _Ty& _Left, const complex<_Ty>& _Right) { complex<_Ty> _Tmp(_Left); _Tmp *= _Right; return _Tmp; @@ -1099,7 +1096,7 @@ _NODISCARD complex<_Ty> operator/(const complex<_Ty>& _Left, const complex<_Ty>& } template -_NODISCARD complex<_Ty> operator/(const complex<_Ty>& _Left, const _Ty& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator/(const complex<_Ty>& _Left, const _Ty& _Right) { complex<_Ty> _Tmp(_Left); _Tmp.real(_Tmp.real() / _Right); _Tmp.imag(_Tmp.imag() / _Right); @@ -1107,7 +1104,7 @@ _NODISCARD complex<_Ty> operator/(const complex<_Ty>& _Left, const _Ty& _Right) } template -_NODISCARD complex<_Ty> operator/(const _Ty& _Left, const complex<_Ty>& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator/(const _Ty& _Left, const complex<_Ty>& _Right) { complex<_Ty> _Tmp(_Left); _Tmp /= _Right; return _Tmp; @@ -1115,13 +1112,13 @@ _NODISCARD complex<_Ty> operator/(const _Ty& _Left, const complex<_Ty>& _Right) // FUNCTION TEMPLATE UNARY operator+ template -_NODISCARD complex<_Ty> operator+(const complex<_Ty>& _Left) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator+(const complex<_Ty>& _Left) { return _Left; } // FUNCTION TEMPLATE UNARY operator- template -_NODISCARD complex<_Ty> operator-(const complex<_Ty>& _Left) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator-(const complex<_Ty>& _Left) { return complex<_Ty>(-_Left.real(), -_Left.imag()); } @@ -1682,7 +1679,7 @@ _NODISCARD _Ty arg(const complex<_Ty>& _Left) { // return phase angle of complex // FUNCTION TEMPLATE conj template -_NODISCARD complex<_Ty> conj(const complex<_Ty>& _Left) { // return complex conjugate +_NODISCARD _CONSTEXPR20 complex<_Ty> conj(const complex<_Ty>& _Left) { // return complex conjugate return complex<_Ty>(real(_Left), -imag(_Left)); } @@ -1718,7 +1715,7 @@ _NODISCARD complex<_Ty> log10(const complex<_Ty>& _Left) { // FUNCTION TEMPLATE norm template -_NODISCARD _Ty norm(const complex<_Ty>& _Left) { // return squared magnitude +_NODISCARD _CONSTEXPR20 _Ty norm(const complex<_Ty>& _Left) { // return squared magnitude return real(_Left) * real(_Left) + imag(_Left) * imag(_Left); } From eb17be0171191eb9f365a2f4825ba5b7a4855aee Mon Sep 17 00:00:00 2001 From: neargye Date: Tue, 10 Dec 2019 18:32:50 +0500 Subject: [PATCH 03/17] define __cpp_lib_constexpr_complex --- stl/inc/yvals_core.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 31994905820..d91dbfc0efd 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -138,6 +138,7 @@ // P0325R4 to_array() // P0356R5 bind_front() // P0357R3 Supporting Incomplete Types In reference_wrapper +// P0415R1 constexpr For (Again) // P0439R0 enum class memory_order // P0457R2 starts_with()/ends_with() For basic_string/basic_string_view // P0458R2 contains() For Ordered And Unordered Associative Containers @@ -1103,6 +1104,7 @@ #endif // defined(__cpp_concepts) && __cpp_concepts > 201507L #define __cpp_lib_constexpr_algorithms 201806L +#define __cpp_lib_constexpr_complex 201711L #define __cpp_lib_constexpr_memory 201811L #define __cpp_lib_constexpr_numeric 201911L #define __cpp_lib_endian 201907L From a9f064065f3e1775d74f87337c9403fb23957399 Mon Sep 17 00:00:00 2001 From: Neargye Date: Wed, 11 Dec 2019 15:08:34 +0500 Subject: [PATCH 04/17] operator= return complex& --- stl/inc/complex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 89f9923093d..0d97244cd42 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -635,7 +635,7 @@ public: : _Complex_base( static_cast(_Right._Val[_RE]), static_cast(_Right._Val[_IM])) {} - _CONSTEXPR20 complex<_Ty>& operator=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator=(const _Ty& _Right) { _Val[_RE] = _Right; _Val[_IM] = 0; return *this; @@ -734,7 +734,7 @@ public: : _Complex_base( static_cast(_Right._Val[_RE]), static_cast(_Right._Val[_IM])) {} - _CONSTEXPR20 complex<_Ty>& operator=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator=(const _Ty& _Right) { _Val[_RE] = _Right; _Val[_IM] = 0; return *this; @@ -829,7 +829,7 @@ public: constexpr complex(const _Lcomplex_value& _Right) : _Complex_base(_Right._Val[_RE], _Right._Val[_IM]) {} - _CONSTEXPR20 complex<_Ty>& operator=(const _Ty& _Right) { + _CONSTEXPR20 complex& operator=(const _Ty& _Right) { _Val[_RE] = _Right; _Val[_IM] = 0; return *this; From a4cebd2a8d2c8047cc455656cca1e3d18c48b822 Mon Sep 17 00:00:00 2001 From: Neargye Date: Wed, 11 Dec 2019 15:29:20 +0500 Subject: [PATCH 05/17] marked _Ctraits functions constexpr that forward numeric_limits --- stl/inc/complex | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 0d97244cd42..7aaa85e1c5d 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -57,11 +57,11 @@ class complex; template class _Ctraits { public: - static _Ty _Flt_eps() { // get epsilon + static constexpr _Ty _Flt_eps() { // get epsilon return numeric_limits<_Ty>::epsilon(); } - static _Ty _Flt_max() { + static constexpr _Ty _Flt_max() { return (numeric_limits<_Ty>::max)(); } @@ -76,8 +76,8 @@ public: return _Ans; } - static _Ty _Infv() { // return infinity - return numeric_limits<_Ty>::infinity(); + static constexpr _Ty _Infv() { // return infinity + return numeric_limits::infinity(); } static bool _Isinf(_Ty _Left) { // test for infinity @@ -90,8 +90,8 @@ public: return _CSTD _Dtest(&_Tmp) == _NANCODE; } - static _Ty _Nanv() { // return NaN - return numeric_limits<_Ty>::quiet_NaN(); + static constexpr _Ty _Nanv() { // return NaN + return numeric_limits::quiet_NaN(); } static _Ty _Sinh(_Ty _Left, _Ty _Right) { // return sinh(_Left) * _Right @@ -175,12 +175,12 @@ class _Ctraits { public: using _Ty = long double; - static _Ty _Flt_eps() { // get epsilon - return LDBL_EPSILON; + static constexpr _Ty _Flt_eps() { // get epsilon + return numeric_limits::epsilon(); } - static _Ty _Flt_max() { - return LDBL_MAX; + static constexpr _Ty _Flt_max() { + return (numeric_limits::max)(); } static _Ty _Cosh(_Ty _Left, _Ty _Right) { // return cosh(_Left) * _Right @@ -191,7 +191,7 @@ public: return _CSTD _LExp(_Pleft, _Right, _Exponent); } - static _Ty _Infv() { // return infinity + static constexpr _Ty _Infv() { // return infinity return numeric_limits::infinity(); } @@ -203,7 +203,7 @@ public: return _CSTD _LDtest(&_Left) == _NANCODE; } - static _Ty _Nanv() { // return NaN + static constexpr _Ty _Nanv() { // return NaN return numeric_limits::quiet_NaN(); } @@ -288,12 +288,12 @@ class _Ctraits { public: using _Ty = double; - static _Ty _Flt_eps() { // get epsilon - return DBL_EPSILON; + static constexpr _Ty _Flt_eps() { // get epsilon + return numeric_limits::epsilon(); } - static _Ty _Flt_max() { - return DBL_MAX; + static constexpr _Ty _Flt_max() { + return (numeric_limits::max)(); } static _Ty _Cosh(_Ty _Left, _Ty _Right) { // return cosh(_Left) * _Right @@ -304,7 +304,7 @@ public: return _CSTD _Exp(_Pleft, _Right, _Exponent); } - static _Ty _Infv() { // return infinity + static constexpr _Ty _Infv() { // return infinity return numeric_limits::infinity(); } @@ -316,7 +316,7 @@ public: return _CSTD _Dtest(&_Left) == _NANCODE; } - static _Ty _Nanv() { // return NaN + static constexpr _Ty _Nanv() { // return NaN return numeric_limits::quiet_NaN(); } @@ -408,12 +408,12 @@ class _Ctraits { public: using _Ty = float; - static _Ty _Flt_eps() { // get epsilon - return FLT_EPSILON; + static constexpr _Ty _Flt_eps() { // get epsilon + return numeric_limits::epsilon(); } - static _Ty _Flt_max() { - return FLT_MAX; + static constexpr _Ty _Flt_max() { + return (numeric_limits::max)(); } static _Ty _Cosh(_Ty _Left, _Ty _Right) { // return cosh(_Left) * _Right @@ -424,7 +424,7 @@ public: return _CSTD _FExp(_Pleft, _Right, _Exponent); } - static _Ty _Infv() { // return infinity + static constexpr _Ty _Infv() { // return infinity return numeric_limits::infinity(); } @@ -436,7 +436,7 @@ public: return _CSTD _FDtest(&_Left) == _NANCODE; } - static _Ty _Nanv() { // return NaN + static constexpr _Ty _Nanv() { // return NaN return numeric_limits::quiet_NaN(); } From 3472827efad23339b882ffddee0ab0b845c9a503 Mon Sep 17 00:00:00 2001 From: Neargye Date: Wed, 11 Dec 2019 15:30:00 +0500 Subject: [PATCH 06/17] mark additional overloads norm, conj, imag and real constexpr --- stl/inc/complex | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 7aaa85e1c5d..d437462fe80 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -1750,26 +1750,26 @@ struct _Promote_to_float { // promote integral to double using type = conditional_t, double, _Ty>; }; -#define _GENERIC_MATHC0X(FUN, VAL) \ +#define _GENERIC_MATHC0X(FUN, VAL, ATTR) \ template , int> = 0> \ - _NODISCARD typename _Promote_to_float<_Ty>::type FUN(_Ty) { \ + ATTR typename _Promote_to_float<_Ty>::type FUN(_Ty) { \ return static_cast::type>(VAL); \ } -#define _GENERIC_MATHC1X(FUN, VAL) \ +#define _GENERIC_MATHC1X(FUN, VAL, ATTR) \ template , int> = 0> \ - _NODISCARD typename _Promote_to_float<_Ty>::type FUN(_Ty _Left) { \ + ATTR typename _Promote_to_float<_Ty>::type FUN(_Ty _Left) { \ return static_cast::type>(VAL); \ } -_GENERIC_MATHC0X(arg, 0) -_GENERIC_MATHC0X(imag, 0) -_GENERIC_MATHC1X(real, _Left) +_GENERIC_MATHC0X(arg, 0, _NODISCARD) +_GENERIC_MATHC0X(imag, 0, _NODISCARD _CONSTEXPR20) +_GENERIC_MATHC1X(real, _Left, _NODISCARD _CONSTEXPR20) -_GENERIC_MATHC1X(norm, (_Left * _Left)) +_GENERIC_MATHC1X(norm, (_Left * _Left), _NODISCARD _CONSTEXPR20) -_GENERIC_MATHC1X(conj, _Left) -_GENERIC_MATHC1X(proj, _Left) +_GENERIC_MATHC1X(conj, _Left, _NODISCARD _CONSTEXPR20) +_GENERIC_MATHC1X(proj, _Left, _NODISCARD) #undef _GENERIC_MATHC0X #undef _GENERIC_MATHC1X From 24f7ebae4f1a2dfc2f6e525a0b4f3d205e3f1fe2 Mon Sep 17 00:00:00 2001 From: Neargye Date: Sat, 7 Mar 2020 13:29:03 +0500 Subject: [PATCH 07/17] mark operator/ constexpr --- stl/inc/complex | 64 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index d437462fe80..8d8d7c7dd31 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -12,6 +12,11 @@ #include #include +#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) +#include +#include +#endif + #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) @@ -85,9 +90,15 @@ public: return _CSTD _Dtest(&_Tmp) == _INFCODE; } - static bool _Isnan(_Ty _Left) { + static _CONSTEXPR20 bool _Isnan(_Ty _Left) { double _Tmp = static_cast(_Left); - return _CSTD _Dtest(&_Tmp) == _NANCODE; +#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) + if (_STD is_constant_evaluated()) { + uint64_t _Uint = _STD bit_cast(_Tmp); + return ((_Uint >> 32) & 0x7fffffffU) + (_Uint != 0U) > 0x7ff00000U; + } else +#endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast + return _CSTD _Dtest(&_Tmp) == _NANCODE; } static constexpr _Ty _Nanv() { // return NaN @@ -199,8 +210,14 @@ public: return _CSTD _LDtest(&_Left) == _INFCODE; } - static bool _Isnan(_Ty _Left) { - return _CSTD _LDtest(&_Left) == _NANCODE; + static _CONSTEXPR20 bool _Isnan(_Ty _Left) { +#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) + if (_STD is_constant_evaluated()) { + uint64_t _Tmp = _STD bit_cast(static_cast(_Left)); + return ((_Tmp >> 32) & 0x7fffffffU) + (_Tmp != 0U) > 0x7ff00000U; + } else +#endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast + return _CSTD _LDtest(&_Left) == _NANCODE; } static constexpr _Ty _Nanv() { // return NaN @@ -312,8 +329,14 @@ public: return _CSTD _Dtest(&_Left) == _INFCODE; } - static bool _Isnan(_Ty _Left) { - return _CSTD _Dtest(&_Left) == _NANCODE; + static _CONSTEXPR20 bool _Isnan(_Ty _Left) { +#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) + if (_STD is_constant_evaluated()) { + uint64_t _Tmp = _STD bit_cast(static_cast(_Left)); + return ((_Tmp >> 32) & 0x7fffffffU) + (_Tmp != 0U) > 0x7ff00000U; + } else +#endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast + return _CSTD _Dtest(&_Left) == _NANCODE; } static constexpr _Ty _Nanv() { // return NaN @@ -432,8 +455,13 @@ public: return _CSTD _FDtest(&_Left) == _INFCODE; } - static bool _Isnan(_Ty _Left) { - return _CSTD _FDtest(&_Left) == _NANCODE; + static _CONSTEXPR20 bool _Isnan(_Ty _Left) { +#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) + if (_STD is_constant_evaluated()) { + return (_STD bit_cast(_Left) & 0x7fffffffU) > 0x7f800000U; + } else +#endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast + return _CSTD _FDtest(&_Left) == _NANCODE; } static constexpr _Ty _Nanv() { // return NaN @@ -571,7 +599,7 @@ protected: } template - void _Div(const complex<_Other>& _Right) { + _CONSTEXPR20 void _Div(const complex<_Other>& _Right) { using _Myctraits = _Ctraits<_Ty>; _Ty _Rightreal = static_cast<_Ty>(_Right.real()); @@ -678,7 +706,7 @@ public: return *this; } - complex& operator/=(const complex& _Right) { + _CONSTEXPR20 complex& operator/=(const complex& _Right) { this->_Div(_Right); return *this; } @@ -709,7 +737,7 @@ public: } template - complex& operator/=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator/=(const complex<_Other>& _Right) { this->_Div(_Right); return *this; } @@ -777,7 +805,7 @@ public: return *this; } - complex& operator/=(const complex& _Right) { + _CONSTEXPR20 complex& operator/=(const complex& _Right) { this->_Div(_Right); return *this; } @@ -808,7 +836,7 @@ public: } template - complex& operator/=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator/=(const complex<_Other>& _Right) { this->_Div(_Right); return *this; } @@ -872,7 +900,7 @@ public: return *this; } - complex& operator/=(const complex& _Right) { + _CONSTEXPR20 complex& operator/=(const complex& _Right) { this->_Div(_Right); return *this; } @@ -903,7 +931,7 @@ public: } template - complex& operator/=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator/=(const complex<_Other>& _Right) { this->_Div(_Right); return *this; } @@ -990,7 +1018,7 @@ public: return *this; } - complex& operator/=(const complex& _Right) { + _CONSTEXPR20 complex& operator/=(const complex& _Right) { this->_Div(_Right); return *this; } @@ -1014,7 +1042,7 @@ public: } template - complex& operator/=(const complex<_Other>& _Right) { + _CONSTEXPR20 complex& operator/=(const complex<_Other>& _Right) { this->_Div(_Right); return *this; } @@ -1089,7 +1117,7 @@ _NODISCARD _CONSTEXPR20 complex<_Ty> operator*(const _Ty& _Left, const complex<_ // FUNCTION TEMPLATE operator/ template -_NODISCARD complex<_Ty> operator/(const complex<_Ty>& _Left, const complex<_Ty>& _Right) { +_NODISCARD _CONSTEXPR20 complex<_Ty> operator/(const complex<_Ty>& _Left, const complex<_Ty>& _Right) { complex<_Ty> _Tmp(_Left); _Tmp /= _Right; return _Tmp; From af52e6c396bc41b02db30ba98eefe613f31c604c Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 31 Mar 2020 11:50:05 -0700 Subject: [PATCH 08/17] Remove skips for libcxx complex tests --- tests/libcxx/expected_results.txt | 4 ---- tests/libcxx/skipped_tests.txt | 4 ---- 2 files changed, 8 deletions(-) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 39a88e49139..618fd6f4e60 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -411,10 +411,6 @@ std/utilities/time/time.hms/time.hms.members/subseconds.pass.cpp SKIP std/utilities/time/time.hms/time.hms.members/to_duration.pass.cpp SKIP std/utilities/time/time.hms/time.hms.members/width.pass.cpp SKIP -# C++20 P0415R1 "constexpr For (Again)" -std/numerics/complex.number/cmplx.over/imag.pass.cpp SKIP -std/numerics/complex.number/cmplx.over/real.pass.cpp SKIP - # C++20 P0476R2 " bit_cast" std/language.support/support.limits/support.limits.general/bit.version.pass.cpp SKIP diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 27551a81790..2e7caaab737 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -411,10 +411,6 @@ utilities\time\time.hms\time.hms.members\subseconds.pass.cpp utilities\time\time.hms\time.hms.members\to_duration.pass.cpp utilities\time\time.hms\time.hms.members\width.pass.cpp -# C++20 P0415R1 "constexpr For (Again)" -numerics\complex.number\cmplx.over\imag.pass.cpp -numerics\complex.number\cmplx.over\real.pass.cpp - # C++20 P0476R2 " bit_cast" language.support\support.limits\support.limits.general\bit.version.pass.cpp From 84deed52b2ab57d2087e3795b75aae9e766b6d89 Mon Sep 17 00:00:00 2001 From: neargye Date: Wed, 1 Apr 2020 15:54:58 +0500 Subject: [PATCH 09/17] small fix --- stl/inc/complex | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 8d8d7c7dd31..4ac22e5ab82 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -82,7 +82,7 @@ public: } static constexpr _Ty _Infv() { // return infinity - return numeric_limits::infinity(); + return numeric_limits<_Ty>::infinity(); } static bool _Isinf(_Ty _Left) { // test for infinity @@ -95,14 +95,14 @@ public: #if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) if (_STD is_constant_evaluated()) { uint64_t _Uint = _STD bit_cast(_Tmp); - return ((_Uint >> 32) & 0x7fffffffU) + (_Uint != 0U) > 0x7ff00000U; + return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; } else #endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast return _CSTD _Dtest(&_Tmp) == _NANCODE; } static constexpr _Ty _Nanv() { // return NaN - return numeric_limits::quiet_NaN(); + return numeric_limits<_Ty>::quiet_NaN(); } static _Ty _Sinh(_Ty _Left, _Ty _Right) { // return sinh(_Left) * _Right @@ -213,8 +213,8 @@ public: static _CONSTEXPR20 bool _Isnan(_Ty _Left) { #if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) if (_STD is_constant_evaluated()) { - uint64_t _Tmp = _STD bit_cast(static_cast(_Left)); - return ((_Tmp >> 32) & 0x7fffffffU) + (_Tmp != 0U) > 0x7ff00000U; + uint64_t _Uint = _STD bit_cast(static_cast(_Left)); + return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; } else #endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast return _CSTD _LDtest(&_Left) == _NANCODE; @@ -332,8 +332,8 @@ public: static _CONSTEXPR20 bool _Isnan(_Ty _Left) { #if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) if (_STD is_constant_evaluated()) { - uint64_t _Tmp = _STD bit_cast(static_cast(_Left)); - return ((_Tmp >> 32) & 0x7fffffffU) + (_Tmp != 0U) > 0x7ff00000U; + uint64_t _Uint = _STD bit_cast(static_cast(_Left)); + return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; } else #endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast return _CSTD _Dtest(&_Left) == _NANCODE; From 1d1e1ef51c9e9fba42dc9a83d87f867d03e5649f Mon Sep 17 00:00:00 2001 From: Curtis J Bezault Date: Thu, 9 Apr 2020 19:13:42 -0700 Subject: [PATCH 10/17] Fix Clang format issue --- stl/inc/yvals_core.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 2b0b8f6d06c..41a82088fea 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1110,10 +1110,10 @@ #define __cpp_lib_concepts 201907L #endif // defined(__cpp_concepts) && __cpp_concepts > 201507L -#define __cpp_lib_constexpr_algorithms 201806L -#define __cpp_lib_constexpr_complex 201711L -#define __cpp_lib_constexpr_memory 201811L -#define __cpp_lib_constexpr_numeric 201911L +#define __cpp_lib_constexpr_algorithms 201806L +#define __cpp_lib_constexpr_complex 201711L +#define __cpp_lib_constexpr_memory 201811L +#define __cpp_lib_constexpr_numeric 201911L #ifdef __cpp_impl_destroying_delete #define __cpp_lib_destroying_delete 201806L From cb4ad703b48f8e2f52814fb1b14df5f0ffb90b4e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 24 Apr 2020 16:26:39 -0700 Subject: [PATCH 11/17] Update VSO_0157762_feature_test_macros. --- .../tests/VSO_0157762_feature_test_macros/test.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp index 36871483320..1faba2aa45e 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp @@ -982,6 +982,20 @@ STATIC_ASSERT(__cpp_lib_constexpr_algorithms == 201806L); #endif #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_constexpr_complex +#error __cpp_lib_constexpr_complex is not defined +#elif __cpp_lib_constexpr_complex != 201711L +#error __cpp_lib_constexpr_complex is not 201711L +#else +STATIC_ASSERT(__cpp_lib_constexpr_complex == 201711L); +#endif +#else +#ifdef __cpp_lib_constexpr_complex +#error __cpp_lib_constexpr_complex is defined +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_constexpr_memory #error __cpp_lib_constexpr_memory is not defined From d5b6b8f55ca6b5a01196af9ed2cec660ed15d46a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 24 Apr 2020 16:44:02 -0700 Subject: [PATCH 12/17] Adjust conditional compilation. is_constant_evaluated and bit_cast are now always available in C++20 mode. Additionally, we don't need `else` after `if ... return`, which avoids having non-braced control flow. --- stl/inc/complex | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 4ac22e5ab82..8b925a72be1 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -12,10 +12,10 @@ #include #include -#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) +#if _HAS_CXX20 #include #include -#endif +#endif // _HAS_CXX20 #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -92,13 +92,13 @@ public: static _CONSTEXPR20 bool _Isnan(_Ty _Left) { double _Tmp = static_cast(_Left); -#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) +#if _HAS_CXX20 if (_STD is_constant_evaluated()) { uint64_t _Uint = _STD bit_cast(_Tmp); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; - } else -#endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast - return _CSTD _Dtest(&_Tmp) == _NANCODE; + } +#endif // _HAS_CXX20 + return _CSTD _Dtest(&_Tmp) == _NANCODE; } static constexpr _Ty _Nanv() { // return NaN @@ -211,13 +211,13 @@ public: } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { -#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) +#if _HAS_CXX20 if (_STD is_constant_evaluated()) { uint64_t _Uint = _STD bit_cast(static_cast(_Left)); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; - } else -#endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast - return _CSTD _LDtest(&_Left) == _NANCODE; + } +#endif // _HAS_CXX20 + return _CSTD _LDtest(&_Left) == _NANCODE; } static constexpr _Ty _Nanv() { // return NaN @@ -330,13 +330,13 @@ public: } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { -#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) +#if _HAS_CXX20 if (_STD is_constant_evaluated()) { uint64_t _Uint = _STD bit_cast(static_cast(_Left)); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; - } else -#endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast - return _CSTD _Dtest(&_Left) == _NANCODE; + } +#endif // _HAS_CXX20 + return _CSTD _Dtest(&_Left) == _NANCODE; } static constexpr _Ty _Nanv() { // return NaN @@ -456,12 +456,12 @@ public: } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { -#if defined(__cpp_lib_is_constant_evaluated) && defined(__cpp_lib_bit_cast) +#if _HAS_CXX20 if (_STD is_constant_evaluated()) { return (_STD bit_cast(_Left) & 0x7fffffffU) > 0x7f800000U; - } else -#endif // __cpp_lib_is_constant_evaluated && __cpp_lib_bit_cast - return _CSTD _FDtest(&_Left) == _NANCODE; + } +#endif // _HAS_CXX20 + return _CSTD _FDtest(&_Left) == _NANCODE; } static constexpr _Ty _Nanv() { // return NaN From 8a8c6660341c1a14816496c2ec45cd5f91db6c30 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 24 Apr 2020 17:04:40 -0700 Subject: [PATCH 13/17] Simplify _Isnan. In C++20 mode, we can always use bit_cast. At runtime, it should be significantly more efficient than calling _Dtest etc. which is separately compiled and performs a full classification instead of testing for just NaN. Avoid unnecessary static_cast - our long double is always 64-bit, and double is already double. Use auto after bit_cast to avoid repeating the type. Add const. For consistency, use named _Uint for 32-bit float too. --- stl/inc/complex | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 8b925a72be1..dc78b448498 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -93,12 +93,11 @@ public: static _CONSTEXPR20 bool _Isnan(_Ty _Left) { double _Tmp = static_cast(_Left); #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { - uint64_t _Uint = _STD bit_cast(_Tmp); - return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; - } -#endif // _HAS_CXX20 + const auto _Uint = _STD bit_cast(_Tmp); + return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; +#else // _HAS_CXX20 return _CSTD _Dtest(&_Tmp) == _NANCODE; +#endif // _HAS_CXX20 } static constexpr _Ty _Nanv() { // return NaN @@ -212,12 +211,11 @@ public: static _CONSTEXPR20 bool _Isnan(_Ty _Left) { #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { - uint64_t _Uint = _STD bit_cast(static_cast(_Left)); - return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; - } -#endif // _HAS_CXX20 + const auto _Uint = _STD bit_cast(_Left); + return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; +#else // _HAS_CXX20 return _CSTD _LDtest(&_Left) == _NANCODE; +#endif // _HAS_CXX20 } static constexpr _Ty _Nanv() { // return NaN @@ -331,12 +329,11 @@ public: static _CONSTEXPR20 bool _Isnan(_Ty _Left) { #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { - uint64_t _Uint = _STD bit_cast(static_cast(_Left)); - return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; - } -#endif // _HAS_CXX20 + const auto _Uint = _STD bit_cast(_Left); + return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; +#else // _HAS_CXX20 return _CSTD _Dtest(&_Left) == _NANCODE; +#endif // _HAS_CXX20 } static constexpr _Ty _Nanv() { // return NaN @@ -457,11 +454,11 @@ public: static _CONSTEXPR20 bool _Isnan(_Ty _Left) { #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { - return (_STD bit_cast(_Left) & 0x7fffffffU) > 0x7f800000U; - } -#endif // _HAS_CXX20 + const auto _Uint = _STD bit_cast(_Left); + return (_Uint & 0x7fffffffU) > 0x7f800000U; +#else // _HAS_CXX20 return _CSTD _FDtest(&_Left) == _NANCODE; +#endif // _HAS_CXX20 } static constexpr _Ty _Nanv() { // return NaN From 23fdd4c8c3c4b310a96557e443dc6771d55f3b5b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 24 Apr 2020 17:56:02 -0700 Subject: [PATCH 14/17] Always use _Bit_cast. Copy bit_cast in to _Bit_cast in , superseding _Bit_cast in . Unlike C++20 bit_cast, _Bit_cast is always available. ( is a common ancestor of and , and includes the necessary machinery for this definition.) I verified that MSVC, Clang, and IntelliSense all accept `__builtin_bit_cast` in 14/17 mode. For CUDA, I provide the memcpy fallback (which isn't constexpr, of course). Finally, _Isinf should use _Bit_cast; I'm marking that with a comment (and will file a GitHub issue in the future) instead of extending this PR indefinitely. --- stl/inc/charconv | 11 ----------- stl/inc/complex | 40 ++++++++++------------------------------ stl/inc/xutility | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 41 deletions(-) diff --git a/stl/inc/charconv b/stl/inc/charconv index 66fd8c9f837..11ab046a08c 100644 --- a/stl/inc/charconv +++ b/stl/inc/charconv @@ -193,17 +193,6 @@ inline to_chars_result to_chars(char* const _First, char* const _Last, const uns to_chars_result to_chars(char* _First, char* _Last, bool _Value, int _Base = 10) = delete; -// FUNCTION TEMPLATE _Bit_cast -template && is_trivially_copyable_v<_From>, int> = - 0> -_NODISCARD /*constexpr*/ _To _Bit_cast(const _From& _From_obj) noexcept { - _To _To_obj; // assumes default-init - _CSTD memcpy(_STD addressof(_To_obj), _STD addressof(_From_obj), sizeof(_To)); - return _To_obj; -} - - // STRUCT from_chars_result struct from_chars_result { const char* ptr; diff --git a/stl/inc/complex b/stl/inc/complex index dc78b448498..242b2407e13 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -9,14 +9,10 @@ #include #if _STL_COMPILER_PREPROCESSOR #include +#include #include #include -#if _HAS_CXX20 -#include -#include -#endif // _HAS_CXX20 - #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) @@ -87,17 +83,13 @@ public: static bool _Isinf(_Ty _Left) { // test for infinity double _Tmp = static_cast(_Left); - return _CSTD _Dtest(&_Tmp) == _INFCODE; + return _CSTD _Dtest(&_Tmp) == _INFCODE; // TRANSITION, should use _Bit_cast } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { - double _Tmp = static_cast(_Left); -#if _HAS_CXX20 - const auto _Uint = _STD bit_cast(_Tmp); + double _Tmp = static_cast(_Left); + const auto _Uint = _Bit_cast(_Tmp); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; -#else // _HAS_CXX20 - return _CSTD _Dtest(&_Tmp) == _NANCODE; -#endif // _HAS_CXX20 } static constexpr _Ty _Nanv() { // return NaN @@ -206,16 +198,12 @@ public: } static bool _Isinf(_Ty _Left) { // test for infinity - return _CSTD _LDtest(&_Left) == _INFCODE; + return _CSTD _LDtest(&_Left) == _INFCODE; // TRANSITION, should use _Bit_cast } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { -#if _HAS_CXX20 - const auto _Uint = _STD bit_cast(_Left); + const auto _Uint = _Bit_cast(_Left); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; -#else // _HAS_CXX20 - return _CSTD _LDtest(&_Left) == _NANCODE; -#endif // _HAS_CXX20 } static constexpr _Ty _Nanv() { // return NaN @@ -324,16 +312,12 @@ public: } static bool _Isinf(_Ty _Left) { // test for infinity - return _CSTD _Dtest(&_Left) == _INFCODE; + return _CSTD _Dtest(&_Left) == _INFCODE; // TRANSITION, should use _Bit_cast } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { -#if _HAS_CXX20 - const auto _Uint = _STD bit_cast(_Left); + const auto _Uint = _Bit_cast(_Left); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; -#else // _HAS_CXX20 - return _CSTD _Dtest(&_Left) == _NANCODE; -#endif // _HAS_CXX20 } static constexpr _Ty _Nanv() { // return NaN @@ -449,16 +433,12 @@ public: } static bool _Isinf(_Ty _Left) { // test for infinity - return _CSTD _FDtest(&_Left) == _INFCODE; + return _CSTD _FDtest(&_Left) == _INFCODE; // TRANSITION, should use _Bit_cast } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { -#if _HAS_CXX20 - const auto _Uint = _STD bit_cast(_Left); + const auto _Uint = _Bit_cast(_Left); return (_Uint & 0x7fffffffU) > 0x7f800000U; -#else // _HAS_CXX20 - return _CSTD _FDtest(&_Left) == _NANCODE; -#endif // _HAS_CXX20 } static constexpr _Ty _Nanv() { // return NaN diff --git a/stl/inc/xutility b/stl/inc/xutility index 83693c452fe..9d254ebbe5b 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -47,6 +47,23 @@ _END_EXTERN_C _STD_BEGIN +// FUNCTION TEMPLATE _Bit_cast +template , is_trivially_copyable<_To>, + is_trivially_copyable<_From>>, + int> = 0> +#ifdef __CUDACC__ +_NODISCARD _To _Bit_cast(const _From& _Val) noexcept { + _To _To_obj; // assumes default-init + _CSTD memcpy(_STD addressof(_To_obj), _STD addressof(_Val), sizeof(_To)); + return _To_obj; +} +#else // ^^^ workaround ^^^ / vvv no workaround vvv +_NODISCARD constexpr _To _Bit_cast(const _From& _Val) noexcept { + return __builtin_bit_cast(_To, _Val); +} +#endif // ^^^ no workaround ^^^ + // STRUCT TEMPLATE _Get_first_parameter template struct _Get_first_parameter; From 6e0429effc2f47efe68f8095963664b8864607a0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 27 Apr 2020 16:01:35 -0700 Subject: [PATCH 15/17] Use _Bit_cast in _Isinf. This extends the PR a bit more than strictly necessary, but I realized it was simpler than filing an issue. Also use `const auto` after static_cast. --- stl/inc/complex | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 242b2407e13..0c4239770e1 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -82,12 +82,13 @@ public: } static bool _Isinf(_Ty _Left) { // test for infinity - double _Tmp = static_cast(_Left); - return _CSTD _Dtest(&_Tmp) == _INFCODE; // TRANSITION, should use _Bit_cast + const auto _Tmp = static_cast(_Left); + const auto _Uint = _Bit_cast(_Tmp); + return (_Uint & 0x7fffffffffffffffU) == 0x7ff0000000000000U; } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { - double _Tmp = static_cast(_Left); + const auto _Tmp = static_cast(_Left); const auto _Uint = _Bit_cast(_Tmp); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; } @@ -198,7 +199,8 @@ public: } static bool _Isinf(_Ty _Left) { // test for infinity - return _CSTD _LDtest(&_Left) == _INFCODE; // TRANSITION, should use _Bit_cast + const auto _Uint = _Bit_cast(_Left); + return (_Uint & 0x7fffffffffffffffU) == 0x7ff0000000000000U; } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { @@ -312,7 +314,8 @@ public: } static bool _Isinf(_Ty _Left) { // test for infinity - return _CSTD _Dtest(&_Left) == _INFCODE; // TRANSITION, should use _Bit_cast + const auto _Uint = _Bit_cast(_Left); + return (_Uint & 0x7fffffffffffffffU) == 0x7ff0000000000000U; } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { @@ -433,7 +436,8 @@ public: } static bool _Isinf(_Ty _Left) { // test for infinity - return _CSTD _FDtest(&_Left) == _INFCODE; // TRANSITION, should use _Bit_cast + const auto _Uint = _Bit_cast(_Left); + return (_Uint & 0x7fffffffU) == 0x7f800000U; } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { From 1c75062eb928b25a6588b0e577a0ab4507f1240c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 27 Apr 2020 16:52:45 -0700 Subject: [PATCH 16/17] Cleanup: Eliminate macros, use alias templates. This eliminates the _GENERIC_MATHC0X and _GENERIC_MATHC1X macros in favor of directly stamping out the functions. (Over the years, we've moved away from the practice of using macros to stamp out highly repetitive code. The only remaining scenario where I believe that macros are valuable is when we need to stamp out something for every possible calling convention etc. as that's incredibly verbose and platform-dependent.) Additionally, this changes _Promote_to_float to _Upgrade_to_double. This is better-named in two different ways ("promote" is a Word Of Power that isn't exactly applicable here, and the replacement type is double). It's also less verbose and higher throughput (the former is obvious; the latter is because struct templates are more expensive for compilers to instantiate, as they have to do a lot of work when they generate a class definition). Avoiding macros allows us to perform a couple of micro-cleanups: we can directly return 0 (no need to static_cast to floating type) and we don't have to parenthesize `_Left * _Left` to make clang-format happy. --- stl/inc/complex | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/stl/inc/complex b/stl/inc/complex index 0c4239770e1..dc9ced16f3b 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -1755,33 +1755,37 @@ _NODISCARD complex<_Ty> tan(const complex<_Ty>& _Left) { // ADDITIONAL OVERLOADS template -struct _Promote_to_float { // promote integral to double - using type = conditional_t, double, _Ty>; -}; +using _Upgrade_to_double = conditional_t, double, _Ty>; -#define _GENERIC_MATHC0X(FUN, VAL, ATTR) \ - template , int> = 0> \ - ATTR typename _Promote_to_float<_Ty>::type FUN(_Ty) { \ - return static_cast::type>(VAL); \ - } +template , int> = 0> +_NODISCARD _Upgrade_to_double<_Ty> arg(_Ty) { + return 0; +} -#define _GENERIC_MATHC1X(FUN, VAL, ATTR) \ - template , int> = 0> \ - ATTR typename _Promote_to_float<_Ty>::type FUN(_Ty _Left) { \ - return static_cast::type>(VAL); \ - } +template , int> = 0> +_NODISCARD _CONSTEXPR20 _Upgrade_to_double<_Ty> imag(_Ty) { + return 0; +} -_GENERIC_MATHC0X(arg, 0, _NODISCARD) -_GENERIC_MATHC0X(imag, 0, _NODISCARD _CONSTEXPR20) -_GENERIC_MATHC1X(real, _Left, _NODISCARD _CONSTEXPR20) +template , int> = 0> +_NODISCARD _CONSTEXPR20 _Upgrade_to_double<_Ty> real(_Ty _Left) { + return static_cast<_Upgrade_to_double<_Ty>>(_Left); +} -_GENERIC_MATHC1X(norm, (_Left * _Left), _NODISCARD _CONSTEXPR20) +template , int> = 0> +_NODISCARD _CONSTEXPR20 _Upgrade_to_double<_Ty> norm(_Ty _Left) { + return static_cast<_Upgrade_to_double<_Ty>>(_Left * _Left); +} -_GENERIC_MATHC1X(conj, _Left, _NODISCARD _CONSTEXPR20) -_GENERIC_MATHC1X(proj, _Left, _NODISCARD) +template , int> = 0> +_NODISCARD _CONSTEXPR20 _Upgrade_to_double<_Ty> conj(_Ty _Left) { + return static_cast<_Upgrade_to_double<_Ty>>(_Left); +} -#undef _GENERIC_MATHC0X -#undef _GENERIC_MATHC1X +template , int> = 0> +_NODISCARD _Upgrade_to_double<_Ty> proj(_Ty _Left) { + return static_cast<_Upgrade_to_double<_Ty>>(_Left); +} // FUNCTION TEMPLATE pow template From fe896676aad90a1b2f74eb56e7a982f89ae4d387 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 27 Apr 2020 19:39:25 -0700 Subject: [PATCH 17/17] Add P0415R1_constexpr_complex testing. --- tests/std/test.lst | 1 + .../tests/P0415R1_constexpr_complex/env.lst | 4 + .../tests/P0415R1_constexpr_complex/test.cpp | 131 ++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 tests/std/tests/P0415R1_constexpr_complex/env.lst create mode 100644 tests/std/tests/P0415R1_constexpr_complex/test.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index 300921abe31..9cdaa15d150 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -209,6 +209,7 @@ tests\P0325R4_to_array tests\P0356R5_bind_front tests\P0357R3_supporting_incomplete_types_in_reference_wrapper tests\P0414R2_shared_ptr_for_arrays +tests\P0415R1_constexpr_complex tests\P0426R1_constexpr_char_traits tests\P0433R2_deduction_guides tests\P0476R2_bit_cast diff --git a/tests/std/tests/P0415R1_constexpr_complex/env.lst b/tests/std/tests/P0415R1_constexpr_complex/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0415R1_constexpr_complex/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0415R1_constexpr_complex/test.cpp b/tests/std/tests/P0415R1_constexpr_complex/test.cpp new file mode 100644 index 00000000000..e02267a93f2 --- /dev/null +++ b/tests/std/tests/P0415R1_constexpr_complex/test.cpp @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +using namespace std; + +template +constexpr void test_type() { + static_assert(is_floating_point_v); + + constexpr F f1{1}; + constexpr F f2{2}; + constexpr F f3{3}; + constexpr F f4{4}; + + complex c{f1, f2}; + assert(c.real() == f1); + assert(c.imag() == f2); + assert((c == complex{f1, f2})); + + c.real(f3); + assert((c == complex{f3, f2})); + + c.imag(f4); + assert((c == complex{f3, f4})); + + // Test GH-190 ": real(T) and imag(T) setters should return void". + static_assert(is_void_v); + static_assert(is_void_v); + + c = f1; + assert(c == complex{f1}); + + c.imag(f1); + assert((c == complex{f1, f1})); + + c += f2; + assert((c == complex{f3, f1})); + + c -= f1; + assert((c == complex{f2, f1})); + + c *= f2; + assert((c == complex{f4, f2})); + + c /= f2; + assert((c == complex{f2, f1})); + + c = complex{f1, f3}; + assert((c == complex{f1, f3})); + + c += complex{f2, f1}; + assert((c == complex{f3, f4})); + + c -= complex{f1, f3}; + assert((c == complex{f2, f1})); + + c *= complex{f1, f1}; + assert((c == complex{f1, f3})); + + c /= complex{f1, f3}; + assert(c == complex{f1}); + + { + using Other = conditional_t, double, float>; + + c = complex{Other{1}, Other{3}}; + assert((c == complex{f1, f3})); + + c += complex{Other{2}, Other{1}}; + assert((c == complex{f3, f4})); + + c -= complex{Other{1}, Other{3}}; + assert((c == complex{f2, f1})); + + c *= complex{Other{1}, Other{1}}; + assert((c == complex{f1, f3})); + + c /= complex{Other{1}, Other{3}}; + assert(c == complex{f1}); + } + + assert((complex{f1, f1} + complex{f1, f2} == complex{f2, f3})); + assert((complex{f1, f1} + f1 == complex{f2, f1})); + assert((f1 + complex{f2, f2} == complex{f3, f2})); + + assert((complex{f3, f4} - complex{f1, f1} == complex{f2, f3})); + assert((complex{f4, f4} - f2 == complex{f2, f4})); + assert((f2 - complex{f1, f1} == complex{f1, -f1})); + + assert((complex{f1, f1} * complex{f2, f1} == complex{f1, f3})); + assert((complex{f1, f2} * f2 == complex{f2, f4})); + assert((f3 * complex{f1, f1} == complex{f3, f3})); + + assert((complex{f4, f4} / complex{f2, f2} == complex{f2})); + assert((complex{f3, f3} / f3 == complex{f1, f1})); + assert((f1 / complex{f1, f1} == complex{F{0.5}, F{-0.5}})); + + assert((+complex{f2, f3} == complex{f2, f3})); + + assert((-complex{f2, f3} == complex{-f2, -f3})); + + assert((norm(complex{f3, f4}) == F{25})); + + assert((conj(complex{f3, f4}) == complex{f3, -f4})); + + assert(real(f2) == f2); + assert(imag(f2) == F{0}); + assert(norm(f2) == f4); + assert(conj(f2) == f2); +} + +constexpr bool test_all() { + test_type(); + test_type(); + test_type(); + + assert(real(2) == 2.0); + assert(imag(2) == 0.0); + assert(norm(2) == 4.0); + assert(conj(2) == 2.0); + + return true; +} + +int main() { + assert(test_all()); + static_assert(test_all()); +}