From 740dbb6598817ae2a498f760e4239e2db7f57a74 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 16 Sep 2020 23:54:23 -0700 Subject: [PATCH 01/17] _XB and _XS were zero. --- stl/inc/xlocale | 4 ++-- stl/inc/xlocinfo.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/stl/inc/xlocale b/stl/inc/xlocale index 3f2a2a488de..3ba6167b278 100644 --- a/stl/inc/xlocale +++ b/stl/inc/xlocale @@ -2356,10 +2356,10 @@ struct _CRTIMP2_PURE_IMPORT ctype_base : locale::facet { // base for ctype lower = _LO, print = _DI | _LO | _PU | _SP | _UP | _XA | _XD, punct = _PU, - space = _CN | _SP | _XS, + space = _CN | _SP, upper = _UP, xdigit = _XD, - blank = _CN | _SP | _XS | _XB + blank = _CN | _SP }; using mask = short; // to match diff --git a/stl/inc/xlocinfo.h b/stl/inc/xlocinfo.h index 5cfba660a07..3e05ce96d12 100644 --- a/stl/inc/xlocinfo.h +++ b/stl/inc/xlocinfo.h @@ -24,9 +24,7 @@ _STL_DISABLE_CLANG_WARNINGS _EXTERN_C_UNLESS_PURE // CTYPE CODE BITS -#define _XB 0x000 // extra blank #define _XA 0x100 // extra alphabetic -#define _XS 0x000 // extra space #define _BB _CONTROL // BEL, BS, etc. #define _CN _SPACE // CR, FF, HT, NL, VT #define _DI _DIGIT // '0'-'9' From 2c264771b5f8cb780be61572a2ee01c6d1426995 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 16 Sep 2020 23:57:25 -0700 Subject: [PATCH 02/17] Move and undef extremely short macros. --- stl/inc/xlocale | 21 +++++++++++++++++++++ stl/inc/xlocinfo.h | 11 ----------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/stl/inc/xlocale b/stl/inc/xlocale index 3ba6167b278..d95168e49af 100644 --- a/stl/inc/xlocale +++ b/stl/inc/xlocale @@ -2345,6 +2345,17 @@ protected: virtual __CLR_OR_THIS_CALL ~codecvt_byname() noexcept {} }; +// CTYPE CODE BITS +#define _XA 0x100 // extra alphabetic +#define _BB _CONTROL // BEL, BS, etc. +#define _CN _SPACE // CR, FF, HT, NL, VT +#define _DI _DIGIT // '0'-'9' +#define _LO _LOWER // 'a'-'z' +#define _PU _PUNCT // punctuation +#define _SP _BLANK // space +#define _UP _UPPER // 'A'-'Z' +#define _XD _HEX // '0'-'9', 'A'-'F', 'a'-'f' + // STRUCT ctype_base struct _CRTIMP2_PURE_IMPORT ctype_base : locale::facet { // base for ctype enum { // constants for character classifications @@ -2368,6 +2379,16 @@ struct _CRTIMP2_PURE_IMPORT ctype_base : locale::facet { // base for ctype __CLR_OR_THIS_CALL ~ctype_base() noexcept {} }; +#undef _XA +#undef _BB +#undef _CN +#undef _DI +#undef _LO +#undef _PU +#undef _SP +#undef _UP +#undef _XD + // CLASS TEMPLATE ctype template class ctype : public ctype_base { // facet for classifying elements, converting cases diff --git a/stl/inc/xlocinfo.h b/stl/inc/xlocinfo.h index 3e05ce96d12..9891775d16a 100644 --- a/stl/inc/xlocinfo.h +++ b/stl/inc/xlocinfo.h @@ -23,17 +23,6 @@ _STL_DISABLE_CLANG_WARNINGS _EXTERN_C_UNLESS_PURE -// CTYPE CODE BITS -#define _XA 0x100 // extra alphabetic -#define _BB _CONTROL // BEL, BS, etc. -#define _CN _SPACE // CR, FF, HT, NL, VT -#define _DI _DIGIT // '0'-'9' -#define _LO _LOWER // 'a'-'z' -#define _PU _PUNCT // punctuation -#define _SP _BLANK // space -#define _UP _UPPER // 'A'-'Z' -#define _XD _HEX // '0'-'9', 'A'-'F', 'a'-'f' - // SUPPLEMENTAL LOCALE MACROS AND DECLARATIONS #define _X_ALL LC_ALL #define _X_COLLATE LC_COLLATE From 43a34a87d0818fc323d38604460940d72aba4565 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 00:00:28 -0700 Subject: [PATCH 03/17] _CLASS_DEFINE_CONST is unused. --- stl/inc/xstddef | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stl/inc/xstddef b/stl/inc/xstddef index 32cd98a5a54..6d067214921 100644 --- a/stl/inc/xstddef +++ b/stl/inc/xstddef @@ -375,10 +375,6 @@ _STD_END #define _MEMBER_CALL_CV_REF_NOEXCEPT(FUNC) _MEMBER_CALL_CV_REF(FUNC, ) #endif // __cpp_noexcept_function_type -#define _CLASS_DEFINE_CONST(CLASS) \ - CLASS(_EMPTY_ARGUMENT) \ - CLASS(const) - #ifdef __cpp_noexcept_function_type #define _CLASS_DEFINE_CV_REF_NOEXCEPT(CLASS) \ CLASS(_EMPTY_ARGUMENT) \ From fe8fd8bd5f6e05c8fea791d4aa447ca6ac04999c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 00:06:52 -0700 Subject: [PATCH 04/17] Move macros from inc/ymath.h to src/xmath.hpp. --- stl/inc/ymath.h | 13 ------------- stl/src/xferaise.cpp | 5 +---- stl/src/xmath.hpp | 13 +++++++++++++ 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/stl/inc/ymath.h b/stl/inc/ymath.h index 850ccd6e173..04d29a9a1f1 100644 --- a/stl/inc/ymath.h +++ b/stl/inc/ymath.h @@ -17,19 +17,6 @@ _STL_DISABLE_CLANG_WARNINGS _EXTERN_C_UNLESS_PURE -// MACROS FOR _Dtest RETURN (0 => ZERO) -#define _DENORM (-2) // C9X only -#define _FINITE (-1) -#define _INFCODE 1 -#define _NANCODE 2 - -// MACROS FOR _Feraise ARGUMENT -#define _FE_DIVBYZERO 0x04 -#define _FE_INEXACT 0x20 -#define _FE_INVALID 0x01 -#define _FE_OVERFLOW 0x08 -#define _FE_UNDERFLOW 0x10 - void __CLRCALL_PURE_OR_CDECL _Feraise(int); union _Dconst { // pun float types as integer array diff --git a/stl/src/xferaise.cpp b/stl/src/xferaise.cpp index b1683d6e194..a36a55a98b4 100644 --- a/stl/src/xferaise.cpp +++ b/stl/src/xferaise.cpp @@ -3,10 +3,7 @@ // _Feraise function -#include - -#include -#include +#include "xmath.hpp" _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index 200d7a9d981..c51ca196f81 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -8,6 +8,19 @@ #include #include +// MACROS FOR _Dtest RETURN (0 => ZERO) +#define _DENORM (-2) // C9X only +#define _FINITE (-1) +#define _INFCODE 1 +#define _NANCODE 2 + +// MACROS FOR _Feraise ARGUMENT +#define _FE_DIVBYZERO 0x04 +#define _FE_INEXACT 0x20 +#define _FE_INVALID 0x01 +#define _FE_OVERFLOW 0x08 +#define _FE_UNDERFLOW 0x10 + // FLOAT PROPERTIES #define _D0 3 // little-endian, small long doubles #define _D1 2 From 65ce644f72f81ca05b539f034d707e22ba1628b5 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 00:14:26 -0700 Subject: [PATCH 05/17] VSO-1132105 was resolved fixed; can we remove the workaround? --- stl/inc/functional | 19 ------------------- stl/inc/xutility | 18 ++++-------------- 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index 05b969b5ef2..469d8d714e0 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1472,24 +1472,6 @@ public: _Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, \ _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...)) -#ifdef __EDG__ // TRANSITION, VSO-1132105 - template - _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, - _STD declval<_First&>(), _STD declval<_Second&>(), _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...)))) - -> decltype(_Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _STD declval<_First&>(), _STD declval<_Second&>(), - _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))) { - return _CALL_BINDER; - } - - template - _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) const - noexcept(noexcept(_Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _STD declval(), - _STD declval(), _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...)))) - -> decltype(_Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _STD declval(), - _STD declval(), _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))) { - return _CALL_BINDER; - } -#else // ^^^ workaround / no workaround vvv template _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_CALL_BINDER)) -> decltype(_CALL_BINDER) { return _CALL_BINDER; @@ -1500,7 +1482,6 @@ public: -> decltype(_CALL_BINDER) { return _CALL_BINDER; } -#endif // TRANSITION, VSO-1132105 #undef _CALL_BINDER }; diff --git a/stl/inc/xutility b/stl/inc/xutility index 9658711f8ac..c9ba26eece9 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4123,24 +4123,14 @@ public: return _Left._Current - _Right._Get_last(); } - _NODISCARD friend constexpr reference iter_move(const move_iterator& _It) -#ifdef __EDG__ // TRANSITION, VSO-1132105 - noexcept(noexcept(_RANGES iter_move(_STD declval()))) -#else // ^^^ workaround / no workaround vvv - noexcept(noexcept(_RANGES iter_move(_It._Current))) -#endif // TRANSITION, VSO-1132105 - { + _NODISCARD friend constexpr reference iter_move(const move_iterator& _It) noexcept( + noexcept(_RANGES iter_move(_It._Current))) { return _RANGES iter_move(_It._Current); } template _Iter2> - friend constexpr void iter_swap(const move_iterator& _Left, const move_iterator<_Iter2>& _Right) -#ifdef __EDG__ // TRANSITION, VSO-1132105 - noexcept(noexcept(_RANGES iter_swap(_STD declval(), _STD declval()))) -#else // ^^^ workaround / no workaround vvv - noexcept(noexcept(_RANGES iter_swap(_Left._Current, _Right.base()))) -#endif // TRANSITION, VSO-1132105 - { + friend constexpr void iter_swap(const move_iterator& _Left, const move_iterator<_Iter2>& _Right) noexcept( + noexcept(_RANGES iter_swap(_Left._Current, _Right.base()))) { _RANGES iter_swap(_Left._Current, _Right.base()); } #endif // __cpp_lib_concepts From 2e1d6f278e2df680239d731c73875f1e49dfbb53 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 00:22:19 -0700 Subject: [PATCH 06/17] Centralize emplace_front/_Emplace_back_internal. --- stl/inc/deque | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index 3da10106758..85428a18f4f 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -786,10 +786,7 @@ private: public: void push_front(_Ty&& _Val) { - _Orphan_all(); - _PUSH_FRONT_BEGIN; - _Alty_traits::construct(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD move(_Val)); - _PUSH_FRONT_END; + emplace_front(_STD move(_Val)); } void push_back(_Ty&& _Val) { @@ -817,10 +814,7 @@ public: template decltype(auto) emplace_back(_Valty&&... _Val) { _Orphan_all(); - _PUSH_BACK_BEGIN; - _Alty_traits::construct( - _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD forward<_Valty>(_Val)...); - _PUSH_BACK_END; + _Emplace_back_internal(_STD forward<_Valty>(_Val)...); #if _HAS_CXX17 return back(); @@ -1077,10 +1071,7 @@ public: } void push_front(const _Ty& _Val) { - _Orphan_all(); - _PUSH_FRONT_BEGIN; - _Alty_traits::construct(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _Val); - _PUSH_FRONT_END; + emplace_front(_Val); } void pop_front() noexcept /* strengthened */ { From e97ec08581f7a77fd26ae1c7a20b9361104e98a6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 00:27:22 -0700 Subject: [PATCH 07/17] Substitute _PUSH_FRONT_BEGIN etc. macros. --- stl/inc/deque | 58 +++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index 85428a18f4f..c9926afe86a 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -675,34 +675,6 @@ private: _Guard._Target = nullptr; } -#define _PUSH_FRONT_BEGIN \ - if (_Myoff() % _DEQUESIZ == 0 && _Mapsize() <= (_Mysize() + _DEQUESIZ) / _DEQUESIZ) { \ - _Growmap(1); \ - } \ - _Myoff() &= _Mapsize() * _DEQUESIZ - 1; \ - size_type _Newoff = _Myoff() != 0 ? _Myoff() : _Mapsize() * _DEQUESIZ; \ - size_type _Block = _Getblock(--_Newoff); \ - if (_Map()[_Block] == nullptr) { \ - _Map()[_Block] = _Getal().allocate(_DEQUESIZ); \ - } - -#define _PUSH_FRONT_END \ - _Myoff() = _Newoff; \ - ++_Mysize() - -#define _PUSH_BACK_BEGIN \ - if ((_Myoff() + _Mysize()) % _DEQUESIZ == 0 && _Mapsize() <= (_Mysize() + _DEQUESIZ) / _DEQUESIZ) { \ - _Growmap(1); \ - } \ - _Myoff() &= _Mapsize() * _DEQUESIZ - 1; \ - size_type _Newoff = _Myoff() + _Mysize(); \ - size_type _Block = _Getblock(_Newoff); \ - if (_Map()[_Block] == nullptr) { \ - _Map()[_Block] = _Getal().allocate(_DEQUESIZ); \ - } - -#define _PUSH_BACK_END ++_Mysize() - public: deque(deque&& _Right) : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { _Get_data()._Alloc_proxy(static_cast<_Alproxy_ty>(_Getal())); @@ -801,10 +773,22 @@ public: template decltype(auto) emplace_front(_Valty&&... _Val) { _Orphan_all(); - _PUSH_FRONT_BEGIN; + + if (_Myoff() % _DEQUESIZ == 0 && _Mapsize() <= (_Mysize() + _DEQUESIZ) / _DEQUESIZ) { + _Growmap(1); + } + _Myoff() &= _Mapsize() * _DEQUESIZ - 1; + size_type _Newoff = _Myoff() != 0 ? _Myoff() : _Mapsize() * _DEQUESIZ; + size_type _Block = _Getblock(--_Newoff); + if (_Map()[_Block] == nullptr) { + _Map()[_Block] = _Getal().allocate(_DEQUESIZ); + } + _Alty_traits::construct( _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD forward<_Valty>(_Val)...); - _PUSH_FRONT_END; + + _Myoff() = _Newoff; + ++_Mysize(); #if _HAS_CXX17 return front(); @@ -1103,9 +1087,19 @@ public: private: template void _Emplace_back_internal(_Tys&&... _Vals) { - _PUSH_BACK_BEGIN; + if ((_Myoff() + _Mysize()) % _DEQUESIZ == 0 && _Mapsize() <= (_Mysize() + _DEQUESIZ) / _DEQUESIZ) { + _Growmap(1); + } + _Myoff() &= _Mapsize() * _DEQUESIZ - 1; + size_type _Newoff = _Myoff() + _Mysize(); + size_type _Block = _Getblock(_Newoff); + if (_Map()[_Block] == nullptr) { + _Map()[_Block] = _Getal().allocate(_DEQUESIZ); + } + _Alty_traits::construct(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD forward<_Tys>(_Vals)...); - _PUSH_BACK_END; + + ++_Mysize(); } public: From 21e363b60c0183e6f99f052405d98daa90b72130 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 02:21:30 -0700 Subject: [PATCH 08/17] Comment why _C_COMPLEX_T is necessary. --- stl/inc/complex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/complex b/stl/inc/complex index 2bbba58573b..131ad886a9e 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -21,7 +21,7 @@ _STL_DISABLE_CLANG_WARNINGS #undef new #ifndef _C_COMPLEX_T -#define _C_COMPLEX_T +#define _C_COMPLEX_T // Also defined by UCRT struct _C_double_complex { double _Val[2]; From 346fe6fa6154cd1068323de015b133c863c8eef7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 21:04:59 -0700 Subject: [PATCH 09/17] Add missing braces. --- stl/inc/deque | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index c9926afe86a..baa6f1d7ef0 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -944,8 +944,9 @@ public: size_type _Oldcapacity = _DEQUESIZ * _Mapsize(); size_type _Newcapacity = _Oldcapacity / 2; - if (_Newcapacity < _DEQUESIZ * _DEQUEMAPSIZ) + if (_Newcapacity < _DEQUESIZ * _DEQUEMAPSIZ) { _Newcapacity = _DEQUESIZ * _DEQUEMAPSIZ; + } if ((empty() && 0 < _Mapsize()) || (!empty() && size() <= _Newcapacity && _Newcapacity < _Oldcapacity)) { // worth shrinking, do it @@ -993,8 +994,10 @@ public: } _NODISCARD const_reference at(size_type _Pos) const { - if (_Mysize() <= _Pos) + if (_Mysize() <= _Pos) { _Xran(); + } + return *(begin() + static_cast(_Pos)); } From bbe8d44b68fc403d3975d197ec3b88e2c7b14850 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 21:11:32 -0700 Subject: [PATCH 10/17] _DEQUEMAPSIZ ==> _Minimum_map_size. --- stl/inc/deque | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index baa6f1d7ef0..6d597c539aa 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -23,7 +23,6 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN // DEQUE PARAMETERS -#define _DEQUEMAPSIZ 8 // minimum map size, at least 1 #define _DEQUESIZ \ (sizeof(value_type) <= 1 \ ? 16 \ @@ -574,6 +573,8 @@ private: _Deque_iter_types<_Ty, typename _Alty_traits::size_type, typename _Alty_traits::difference_type, typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Ty&, const _Ty&, _Mapptr>>>; + static constexpr int _Minimum_map_size = 8; + public: using allocator_type = _Alloc; using value_type = _Ty; @@ -944,8 +945,8 @@ public: size_type _Oldcapacity = _DEQUESIZ * _Mapsize(); size_type _Newcapacity = _Oldcapacity / 2; - if (_Newcapacity < _DEQUESIZ * _DEQUEMAPSIZ) { - _Newcapacity = _DEQUESIZ * _DEQUEMAPSIZ; + if (_Newcapacity < _DEQUESIZ * _Minimum_map_size) { + _Newcapacity = _DEQUESIZ * _Minimum_map_size; } if ((empty() && 0 < _Mapsize()) @@ -1416,11 +1417,11 @@ private: } void _Growmap(size_type _Count) { // grow map by at least _Count pointers, _Mapsize() a power of 2 - static_assert(1 < _DEQUEMAPSIZ, "The _Xlen() test should always be performed."); + static_assert(1 < _Minimum_map_size, "The _Xlen() test should always be performed."); _Alpty _Almap(_Getal()); size_type _Newsize = 0 < _Mapsize() ? _Mapsize() : 1; - while (_Newsize - _Mapsize() < _Count || _Newsize < _DEQUEMAPSIZ) { + while (_Newsize - _Mapsize() < _Count || _Newsize < _Minimum_map_size) { // scale _Newsize to 2^N >= _Mapsize() + _Count if (max_size() / _DEQUESIZ - _Newsize < _Newsize) { _Xlen(); // result too long From dbe42caf2c091ee6ef7d5eaa894ed8b522675958 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 21:40:18 -0700 Subject: [PATCH 11/17] Un-macroize _DEQUESIZ. --- stl/inc/deque | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index 6d597c539aa..1f7a6e106c1 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -22,21 +22,14 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN -// DEQUE PARAMETERS -#define _DEQUESIZ \ - (sizeof(value_type) <= 1 \ - ? 16 \ - : sizeof(value_type) <= 2 \ - ? 8 \ - : sizeof(value_type) <= 4 ? 4 \ - : sizeof(value_type) <= 8 ? 2 : 1) // elements per block (a power of 2) - // CLASS TEMPLATE _Deque_unchecked_const_iterator template class _Deque_unchecked_const_iterator { private: using _Size_type = typename _Mydeque::size_type; + static constexpr int _DEQUESIZ = _Mydeque::_DEQUESIZ; + public: using iterator_category = random_access_iterator_tag; @@ -238,6 +231,8 @@ class _Deque_const_iterator : public _Iterator_base12 { private: using _Size_type = typename _Mydeque::size_type; + static constexpr int _DEQUESIZ = _Mydeque::_DEQUESIZ; + public: using iterator_category = random_access_iterator_tag; @@ -540,6 +535,13 @@ public: using const_reference = const value_type&; using _Mapptr = typename _Val_types::_Mapptr; +private: + static constexpr size_t _Bytes = sizeof(value_type); + +public: + static constexpr int _DEQUESIZ = + _Bytes <= 1 ? 16 : _Bytes <= 2 ? 8 : _Bytes <= 4 ? 4 : _Bytes <= 8 ? 2 : 1; // elements per block (a power of 2) + _Deque_val() noexcept : _Map(), _Mapsize(0), _Myoff(0), _Mysize(0) {} size_type _Getblock(size_type _Off) const noexcept { @@ -574,6 +576,7 @@ private: typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Ty&, const _Ty&, _Mapptr>>>; static constexpr int _Minimum_map_size = 8; + static constexpr int _DEQUESIZ = _Scary_val::_DEQUESIZ; public: using allocator_type = _Alloc; From 56dd2da994359018bcf4b402d0d4c2af83982b6d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 18 Sep 2020 15:40:19 -0700 Subject: [PATCH 12/17] Replace macros with ratio/chrono logic. --- stl/inc/chrono | 6 +++--- stl/inc/filesystem | 2 +- stl/inc/xtimec.h | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 4991b19d61a..f4d97a40aca 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -577,7 +577,7 @@ namespace chrono { struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime using rep = long long; - using period = ratio_multiply, nano>; + using period = ratio_multiply, nano>; using duration = chrono::duration; using time_point = chrono::time_point; @@ -588,11 +588,11 @@ namespace chrono { } _NODISCARD static __time64_t to_time_t(const time_point& _Time) noexcept { // convert to __time64_t - return static_cast<__time64_t>(_Time.time_since_epoch().count() / _XTIME_TICKS_PER_TIME_T); + return duration_cast(_Time.time_since_epoch()).count(); } _NODISCARD static time_point from_time_t(__time64_t _Tm) noexcept { // convert from __time64_t - return time_point(duration(_Tm * _XTIME_TICKS_PER_TIME_T)); + return time_point{seconds{_Tm}}; } }; diff --git a/stl/inc/filesystem b/stl/inc/filesystem index a2f4bd1dd09..3d91cc84e9e 100644 --- a/stl/inc/filesystem +++ b/stl/inc/filesystem @@ -2112,7 +2112,7 @@ namespace filesystem { // ALIAS file_time_type struct _File_time_clock { // Implementation of trivial-clock using rep = long long; - using period = ratio_multiply, nano>; + using period = chrono::system_clock::period; using duration = chrono::duration; using time_point = chrono::time_point<_File_time_clock>; diff --git a/stl/inc/xtimec.h b/stl/inc/xtimec.h index b5cc5ab3082..67b75522d16 100644 --- a/stl/inc/xtimec.h +++ b/stl/inc/xtimec.h @@ -30,8 +30,6 @@ _CRTIMP2_PURE int __cdecl xtime_get(xtime*, int); _CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis(const xtime*); _CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis2(const xtime*, const xtime*); _CRTIMP2_PURE long long __cdecl _Xtime_get_ticks(); -#define _XTIME_NSECS_PER_TICK 100 -#define _XTIME_TICKS_PER_TIME_T 10000000LL _CRTIMP2_PURE long long __cdecl _Query_perf_counter(); _CRTIMP2_PURE long long __cdecl _Query_perf_frequency(); From 31a6e8a9a9141005de646ccd8000fcf7fd7f87fa Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 21 Sep 2020 23:52:18 -0700 Subject: [PATCH 13/17] Provide system_clock::period directly. --- stl/inc/chrono | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index f4d97a40aca..8405b26be58 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -575,10 +575,8 @@ namespace chrono { // CLOCKS struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime - using rep = long long; - - using period = ratio_multiply, nano>; - + using rep = long long; + using period = ratio<1, 10'000'000>; // 100 nanoseconds using duration = chrono::duration; using time_point = chrono::time_point; static constexpr bool is_steady = false; From 80928a3a210536b0c32497913f215e25ad82c7c8 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 21 Sep 2020 23:56:01 -0700 Subject: [PATCH 14/17] Restore VSO-1132105 workaround in xutility. --- stl/inc/xutility | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index c9ba26eece9..9658711f8ac 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4123,14 +4123,24 @@ public: return _Left._Current - _Right._Get_last(); } - _NODISCARD friend constexpr reference iter_move(const move_iterator& _It) noexcept( - noexcept(_RANGES iter_move(_It._Current))) { + _NODISCARD friend constexpr reference iter_move(const move_iterator& _It) +#ifdef __EDG__ // TRANSITION, VSO-1132105 + noexcept(noexcept(_RANGES iter_move(_STD declval()))) +#else // ^^^ workaround / no workaround vvv + noexcept(noexcept(_RANGES iter_move(_It._Current))) +#endif // TRANSITION, VSO-1132105 + { return _RANGES iter_move(_It._Current); } template _Iter2> - friend constexpr void iter_swap(const move_iterator& _Left, const move_iterator<_Iter2>& _Right) noexcept( - noexcept(_RANGES iter_swap(_Left._Current, _Right.base()))) { + friend constexpr void iter_swap(const move_iterator& _Left, const move_iterator<_Iter2>& _Right) +#ifdef __EDG__ // TRANSITION, VSO-1132105 + noexcept(noexcept(_RANGES iter_swap(_STD declval(), _STD declval()))) +#else // ^^^ workaround / no workaround vvv + noexcept(noexcept(_RANGES iter_swap(_Left._Current, _Right.base()))) +#endif // TRANSITION, VSO-1132105 + { _RANGES iter_swap(_Left._Current, _Right.base()); } #endif // __cpp_lib_concepts From c437e231e9fc7f1fb879a7237cc6c140edad641c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 21 Sep 2020 23:59:19 -0700 Subject: [PATCH 15/17] Rename _DEQUESIZ to _Block_size. --- stl/inc/deque | 59 ++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index 1f7a6e106c1..829ab6709a7 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -28,7 +28,7 @@ class _Deque_unchecked_const_iterator { private: using _Size_type = typename _Mydeque::size_type; - static constexpr int _DEQUESIZ = _Mydeque::_DEQUESIZ; + static constexpr int _Block_size = _Mydeque::_Block_size; public: using iterator_category = random_access_iterator_tag; @@ -45,7 +45,7 @@ public: _NODISCARD reference operator*() const noexcept { _Size_type _Block = _Mycont->_Getblock(_Myoff); - _Size_type _Off = _Myoff % _DEQUESIZ; + _Size_type _Off = _Myoff % _Block_size; return _Mycont->_Map[_Block][_Off]; } @@ -231,7 +231,7 @@ class _Deque_const_iterator : public _Iterator_base12 { private: using _Size_type = typename _Mydeque::size_type; - static constexpr int _DEQUESIZ = _Mydeque::_DEQUESIZ; + static constexpr int _Block_size = _Mydeque::_Block_size; public: using iterator_category = random_access_iterator_tag; @@ -242,7 +242,7 @@ public: using reference = const value_type&; using _Mydeque_t = _Mydeque; // helper for expression evaluator - enum { _EEN_DS = _DEQUESIZ }; // helper for expression evaluator + enum { _EEN_DS = _Block_size }; // helper for expression evaluator _Deque_const_iterator() noexcept : _Myoff(0) { _Setcont(nullptr); } @@ -260,7 +260,7 @@ public: #endif // _ITERATOR_DEBUG_LEVEL != 0 _Size_type _Block = _Mycont->_Getblock(_Myoff); - _Size_type _Off = _Myoff % _DEQUESIZ; + _Size_type _Off = _Myoff % _Block_size; return _Mycont->_Map[_Block][_Off]; } @@ -539,14 +539,14 @@ private: static constexpr size_t _Bytes = sizeof(value_type); public: - static constexpr int _DEQUESIZ = + static constexpr int _Block_size = _Bytes <= 1 ? 16 : _Bytes <= 2 ? 8 : _Bytes <= 4 ? 4 : _Bytes <= 8 ? 2 : 1; // elements per block (a power of 2) _Deque_val() noexcept : _Map(), _Mapsize(0), _Myoff(0), _Mysize(0) {} size_type _Getblock(size_type _Off) const noexcept { - // NB: _Mapsize and _DEQUESIZ are guaranteed to be powers of 2 - return (_Off / _DEQUESIZ) & (_Mapsize - 1); + // NB: _Mapsize and _Block_size are guaranteed to be powers of 2 + return (_Off / _Block_size) & (_Mapsize - 1); } _Mapptr _Map; // pointer to array of pointers to blocks @@ -576,7 +576,7 @@ private: typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Ty&, const _Ty&, _Mapptr>>>; static constexpr int _Minimum_map_size = 8; - static constexpr int _DEQUESIZ = _Scary_val::_DEQUESIZ; + static constexpr int _Block_size = _Scary_val::_Block_size; public: using allocator_type = _Alloc; @@ -595,7 +595,7 @@ public: using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; - enum { _EEN_DS = _DEQUESIZ }; // helper for expression evaluator + enum { _EEN_DS = _Block_size }; // helper for expression evaluator deque() : _Mypair(_Zero_then_variadic_args_t{}) { _Get_data()._Alloc_proxy(static_cast<_Alproxy_ty>(_Getal())); @@ -778,18 +778,18 @@ public: decltype(auto) emplace_front(_Valty&&... _Val) { _Orphan_all(); - if (_Myoff() % _DEQUESIZ == 0 && _Mapsize() <= (_Mysize() + _DEQUESIZ) / _DEQUESIZ) { + if (_Myoff() % _Block_size == 0 && _Mapsize() <= (_Mysize() + _Block_size) / _Block_size) { _Growmap(1); } - _Myoff() &= _Mapsize() * _DEQUESIZ - 1; - size_type _Newoff = _Myoff() != 0 ? _Myoff() : _Mapsize() * _DEQUESIZ; + _Myoff() &= _Mapsize() * _Block_size - 1; + size_type _Newoff = _Myoff() != 0 ? _Myoff() : _Mapsize() * _Block_size; size_type _Block = _Getblock(--_Newoff); if (_Map()[_Block] == nullptr) { - _Map()[_Block] = _Getal().allocate(_DEQUESIZ); + _Map()[_Block] = _Getal().allocate(_Block_size); } _Alty_traits::construct( - _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD forward<_Valty>(_Val)...); + _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size), _STD forward<_Valty>(_Val)...); _Myoff() = _Newoff; ++_Mysize(); @@ -945,11 +945,11 @@ public: } void shrink_to_fit() { - size_type _Oldcapacity = _DEQUESIZ * _Mapsize(); + size_type _Oldcapacity = _Block_size * _Mapsize(); size_type _Newcapacity = _Oldcapacity / 2; - if (_Newcapacity < _DEQUESIZ * _Minimum_map_size) { - _Newcapacity = _DEQUESIZ * _Minimum_map_size; + if (_Newcapacity < _Block_size * _Minimum_map_size) { + _Newcapacity = _Block_size * _Minimum_map_size; } if ((empty() && 0 < _Mapsize()) @@ -1072,7 +1072,7 @@ public: } else { // something to erase, do it _Orphan_off(_Myoff()); size_type _Block = _Getblock(_Myoff()); - _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Myoff() % _DEQUESIZ)); + _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Myoff() % _Block_size)); if (--_Mysize() == 0) { _Myoff() = 0; } else { @@ -1082,7 +1082,7 @@ public: #else // _ITERATOR_DEBUG_LEVEL == 2 size_type _Block = _Getblock(_Myoff()); - _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Myoff() % _DEQUESIZ)); + _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Myoff() % _Block_size)); if (--_Mysize() == 0) { _Myoff() = 0; } else { @@ -1094,17 +1094,18 @@ public: private: template void _Emplace_back_internal(_Tys&&... _Vals) { - if ((_Myoff() + _Mysize()) % _DEQUESIZ == 0 && _Mapsize() <= (_Mysize() + _DEQUESIZ) / _DEQUESIZ) { + if ((_Myoff() + _Mysize()) % _Block_size == 0 && _Mapsize() <= (_Mysize() + _Block_size) / _Block_size) { _Growmap(1); } - _Myoff() &= _Mapsize() * _DEQUESIZ - 1; + _Myoff() &= _Mapsize() * _Block_size - 1; size_type _Newoff = _Myoff() + _Mysize(); size_type _Block = _Getblock(_Newoff); if (_Map()[_Block] == nullptr) { - _Map()[_Block] = _Getal().allocate(_DEQUESIZ); + _Map()[_Block] = _Getal().allocate(_Block_size); } - _Alty_traits::construct(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD forward<_Tys>(_Vals)...); + _Alty_traits::construct( + _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size), _STD forward<_Tys>(_Vals)...); ++_Mysize(); } @@ -1123,7 +1124,7 @@ public: size_type _Newoff = _Myoff() + _Mysize() - 1; _Orphan_off(_Newoff); size_type _Block = _Getblock(_Newoff); - _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ)); + _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size)); if (--_Mysize() == 0) { _Myoff() = 0; } @@ -1132,7 +1133,7 @@ public: #else // _ITERATOR_DEBUG_LEVEL == 2 size_type _Newoff = _Myoff() + _Mysize() - 1; size_type _Block = _Getblock(_Newoff); - _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ)); + _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size)); if (--_Mysize() == 0) { _Myoff() = 0; } @@ -1426,7 +1427,7 @@ private: size_type _Newsize = 0 < _Mapsize() ? _Mapsize() : 1; while (_Newsize - _Mapsize() < _Count || _Newsize < _Minimum_map_size) { // scale _Newsize to 2^N >= _Mapsize() + _Count - if (max_size() / _DEQUESIZ - _Newsize < _Newsize) { + if (max_size() / _Block_size - _Newsize < _Newsize) { _Xlen(); // result too long } @@ -1434,7 +1435,7 @@ private: } _Count = _Newsize - _Mapsize(); - size_type _Myboff = _Myoff() / _DEQUESIZ; + size_type _Myboff = _Myoff() / _Block_size; _Mapptr _Newmap = _Almap.allocate(_Mapsize() + _Count); _Mapptr _Myptr = _Newmap + _Myboff; @@ -1468,7 +1469,7 @@ private: for (size_type _Block = _Mapsize(); 0 < _Block;) { // free storage for a block and destroy pointer if (_Map()[--_Block]) { // free block and destroy its pointer - _Getal().deallocate(_Map()[_Block], _DEQUESIZ); + _Getal().deallocate(_Map()[_Block], _Block_size); _Destroy_in_place(_Map()[_Block]); } } From e4ec97c6a4d57d951a46e2bed1eb7ac6d0cfb20a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 23 Sep 2020 17:59:00 -0700 Subject: [PATCH 16/17] Change example paths to cat/dog/elk. --- stl/inc/filesystem | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/stl/inc/filesystem b/stl/inc/filesystem index 3d91cc84e9e..a84d02a5671 100644 --- a/stl/inc/filesystem +++ b/stl/inc/filesystem @@ -525,10 +525,10 @@ namespace filesystem { auto _Last = _First + _Str.size(); const auto _Relative_path = _Find_relative_path(_First, _Last); // case 1: relative-path ends in a directory-separator, remove the separator to remove "magic empty path" - // for example: R"(/foo/bar/\//\)" + // for example: R"(/cat/dog/\//\)" // case 2: relative-path doesn't end in a directory-separator, remove the filename and last directory-separator // to prevent creation of a "magic empty path" - // for example: "/foo/bar" + // for example: "/cat/dog" while (_Relative_path != _Last && !_Is_slash(_Last[-1])) { // handle case 2 by removing trailing filename, puts us into case 1 --_Last; @@ -769,12 +769,12 @@ namespace filesystem { path& operator/=(const path& _Other) { // set *this to the path lexically resolved by _Other relative to *this // examples: - // path("foo") / "c:/bar"; // yields "c:/bar" - // path("foo") / "c:"; // yields "c:" + // path("cat") / "c:/dog"; // yields "c:/dog" + // path("cat") / "c:"; // yields "c:" // path("c:") / ""; // yields "c:" - // path("c:foo") / "/bar"; // yields "c:/bar" - // path("c:foo") / "c:bar"; // yields "c:foo/bar" - // path("c:foo") / "d:bar"; // yields "d:bar" + // path("c:cat") / "/dog"; // yields "c:/dog" + // path("c:cat") / "c:dog"; // yields "c:cat/dog" + // path("c:cat") / "d:dog"; // yields "d:dog" // several places herein quote the standard, but the standard's variable p is replaced with _Other if (_Other.is_absolute()) { // if _Other.is_absolute(), then op=(_Other) @@ -814,8 +814,8 @@ namespace filesystem { // If there is a trailing slash not part of root_directory, then !has_filename, so only // (!has_root_directory && is_absolute) remains // Going through our root_name kinds: - // X:foo\ needs a root_directory to be absolute - // \\server\foo must have a root_directory to exist with a relative_path + // X:cat\ needs a root_directory to be absolute + // \\server\cat must have a root_directory to exist with a relative_path // \\?\ must have a root_directory to exist // As a result, the test fails if there is a trailing slash. // If there is no trailing slash, then has_filename, so the test passes. @@ -1235,7 +1235,7 @@ namespace filesystem { // all other paths are absolute const auto _First = _Text.data(); const auto _Last = _First + _Text.size(); - if (_Has_drive_letter_prefix(_First, _Last)) { // test for X:\ but not X:foo + if (_Has_drive_letter_prefix(_First, _Last)) { // test for X:\ but not X:cat return _Last - _First >= 3 && _Is_slash(_First[2]); } @@ -1642,11 +1642,11 @@ namespace filesystem { // calculate a hash value for _Path // See path::compare; we effectively decompose the path with special handling for root_name, root_directory. // Examples: - // c:\foo\bar => {"c:", true , "foo", "bar"} - // c:foo\bar => {"c:", false, "foo", "bar"} - // \foo\bar => {"" , true , "foo", "bar"} - // foo\bar => {"" , false, "foo", "bar"} - // c:\foo\bar\ => {"c:", true , "foo", "bar", ""} + // c:\cat\dog => {"c:", true , "cat", "dog"} + // c:cat\dog => {"c:", false, "cat", "dog"} + // \cat\dog => {"" , true , "cat", "dog"} + // cat\dog => {"" , false, "cat", "dog"} + // c:\cat\dog\ => {"c:", true , "cat", "dog", ""} size_t _Val = _FNV_offset_basis; const auto& _Text = _Path.native(); const auto _First = _Text.data(); @@ -1658,7 +1658,7 @@ namespace filesystem { // The remaining path elements, including root_directory, are effectively hashed by normalizing each // directory-separator into a single preferred-separator when that goes into the hash function. - // path::compare has special handling for root_directory to ensure c:\foo sorts before c:foo, but hash only + // path::compare has special handling for root_directory to ensure c:\cat sorts before c:cat, but hash only // cares about equality, so no special case is necessary. bool _Slash_inserted = false; for (; _Next != _Last; ++_Next) { @@ -3767,11 +3767,11 @@ namespace filesystem { _Cursor = _Root_path_end; // When creating directories, sometimes we get error reports on earlier directories. - // Consider a case like X:\foo\bar\baz, where we get the following errors: + // Consider a case like X:\cat\dog\elk, where we get the following errors: // X: ERROR_ACCESS_DENIED - // X:\foo ERROR_ALREADY_EXISTS - // X:\foo\bar ERROR_ACCESS_DENIED - // X:\foo\bar\baz ERROR_FILE_NOT_FOUND + // X:\cat ERROR_ALREADY_EXISTS + // X:\cat\dog ERROR_ACCESS_DENIED + // X:\cat\dog\elk ERROR_FILE_NOT_FOUND // Here, the previous access denied error prevented us from creating a parent directory, // and the subsequent ERROR_FILE_NOT_FOUND is not the interesting error for the user. // Therefore: From 6e2de04cf135f82111b1b8a8b5fee40b7411bfff Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 24 Sep 2020 17:37:30 -0700 Subject: [PATCH 17/17] Move the "_Dtest return" macros back for GH-1316. --- stl/inc/ymath.h | 6 ++++++ stl/src/xmath.hpp | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/stl/inc/ymath.h b/stl/inc/ymath.h index 04d29a9a1f1..112f9cfa075 100644 --- a/stl/inc/ymath.h +++ b/stl/inc/ymath.h @@ -17,6 +17,12 @@ _STL_DISABLE_CLANG_WARNINGS _EXTERN_C_UNLESS_PURE +// MACROS FOR _Dtest RETURN (0 => ZERO) +#define _DENORM (-2) // C9X only +#define _FINITE (-1) +#define _INFCODE 1 +#define _NANCODE 2 + void __CLRCALL_PURE_OR_CDECL _Feraise(int); union _Dconst { // pun float types as integer array diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index c51ca196f81..d89029cd2b5 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -8,12 +8,6 @@ #include #include -// MACROS FOR _Dtest RETURN (0 => ZERO) -#define _DENORM (-2) // C9X only -#define _FINITE (-1) -#define _INFCODE 1 -#define _NANCODE 2 - // MACROS FOR _Feraise ARGUMENT #define _FE_DIVBYZERO 0x04 #define _FE_INEXACT 0x20