diff --git a/benchmarks/src/regex_match.cpp b/benchmarks/src/regex_match.cpp index 4522be62883..e705bde94b4 100644 --- a/benchmarks/src/regex_match.cpp +++ b/benchmarks/src/regex_match.cpp @@ -22,6 +22,23 @@ void bm_match_sequence_of_as(benchmark::State& state, const char* pattern, synta } } +void bm_match_sequence_of_9a1b(benchmark::State& state, const char* pattern, syntax_option_type syntax = ECMAScript) { + string input; + for (int i = 0; i < state.range(); ++i) { + input += "aaaaaaaaab"; + } + + regex re{pattern, syntax}; + + for (auto _ : state) { + benchmark::DoNotOptimize(input); + const char* pos = input.data(); + const char* end = input.data() + input.size(); + cmatch match; + regex_match(pos, end, match, re); + } +} + void common_args(auto bm) { bm->Arg(100)->Arg(200)->Arg(400); } @@ -36,5 +53,6 @@ BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(b|a)*", "(b|a)*")->Apply(common_arg BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)(?:b|a)*", "(a)(?:b|a)*")->Apply(common_args); BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)(b|a)*", "(a)(b|a)*")->Apply(common_args); BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)(?:b|a)*c", "(a)(?:b|a)*c")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_9a1b, "(?:a*b)*", "(?:a*b)*")->Apply(common_args); BENCHMARK_MAIN(); diff --git a/stl/debugger/STL.natvis b/stl/debugger/STL.natvis index aad4b34577e..c61e29cf5e3 100644 --- a/stl/debugger/STL.natvis +++ b/stl/debugger/STL.natvis @@ -586,7 +586,16 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - + + ranges::equal_to + ranges::not_equal_to + ranges::greater + ranges::less + ranges::greater_equal + ranges::less_equal + compare_three_way + + plus<> minus<> multiplies<> @@ -607,101 +616,26 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception bit_xor<> bit_not<> - - - plus - - - - - minus - - - - - multiplies - - - - - divides - - - - - modulus - - - - - negate - - - - - equal_to - - - - - not_equal_to - - - - - greater - - - - - less - - - - - greater_equal - - - - - less_equal - - - - - logical_and - - - - - logical_or - - - - - logical_not - - - - - bit_and - - - - - bit_or - - - - - bit_xor - - - - - bit_not - - + + plus + minus + multiplies + divides + modulus + negate + equal_to + not_equal_to + greater + less + greater_equal + less_equal + logical_and + logical_or + logical_not + bit_and + bit_or + bit_xor + bit_not @@ -1084,6 +1018,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception _Ptr,na + {*_Ptr} _Ptr @@ -1228,14 +1163,27 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - + + _Ptr,na + {*_Ptr} _Ptr + + + + + _Ptr,na + end + {*_Ptr} + + _Ptr + + @@ -1838,13 +1786,25 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - + + _Myptr,na + {*_Myptr} _Myptr + + + _Myptr,na + end + {*_Myptr} + + _Myptr + + + default sentinel diff --git a/stl/inc/cmath b/stl/inc/cmath index 78e0d7cb959..6c45e1c61a3 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -1686,14 +1686,15 @@ _EXPORT_STD _NODISCARD constexpr inline double lerp( _EXPORT_STD _NODISCARD constexpr inline long double lerp( const long double _ArgA, const long double _ArgB, const long double _ArgT) noexcept { - return _Common_lerp(_ArgA, _ArgB, _ArgT); + return _Common_lerp(static_cast(_ArgA), static_cast(_ArgB), static_cast(_ArgT)); } _EXPORT_STD template requires is_arithmetic_v<_Ty1> && is_arithmetic_v<_Ty2> && is_arithmetic_v<_Ty3> _NODISCARD constexpr auto lerp(const _Ty1 _ArgA, const _Ty2 _ArgB, const _Ty3 _ArgT) noexcept { - using _Tgt = conditional_t<_Is_any_of_v, long double, double>; - return _Common_lerp(static_cast<_Tgt>(_ArgA), static_cast<_Tgt>(_ArgB), static_cast<_Tgt>(_ArgT)); + using _Common = _Common_float_type_t<_Ty1, _Common_float_type_t<_Ty2, _Ty3>>; + return static_cast<_Common>( + _Common_lerp(static_cast(_ArgA), static_cast(_ArgB), static_cast(_ArgT))); } #endif // _HAS_CXX20 _STD_END diff --git a/stl/inc/functional b/stl/inc/functional index 1e8877df2d6..21654698b9b 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -974,7 +974,7 @@ private: }; #if _HAS_CXX23 -template +template class _Function_base; #endif // _HAS_CXX23 @@ -1105,7 +1105,7 @@ protected: private: #if _HAS_CXX23 - friend _Function_base<_Ret, false, _Types...>; + friend _Function_base<_Ret, _Types...>; #endif // _HAS_CXX23 bool _Local() const noexcept { // test for locally stored copy of object @@ -1574,10 +1574,11 @@ _NODISCARD void* _Function_new_large(_CTypes&&... _Args) { return _Ptr; } -template +template class _Function_base { public: - using result_type = _Rx; + using result_type = _Rx; + using _Signature_without_cv_ref_noex = _Rx(_Types...); struct _Impl_t { // A per-callable-type structure acting as a virtual function table. // Using vtable emulations gives more flexibility for optimizations and reduces the amount of RTTI data. @@ -1588,7 +1589,7 @@ public: // empty function from a DLL that is unloaded later, and then safely moving/destroying that empty function. // Calls target - _Rx(__stdcall* _Invoke)(void*, _Types&&...) _NOEXCEPT_FNPTR_COND(_Noexcept); + _Rx(__stdcall* _Invoke)(void*, _Types&&...); // Moves the data, including pointer to "vtable", AND destroys old data (not resetting its "vtable"). // nullptr if we can trivially move two pointers. void(__stdcall* _Move)(_Function_data&, _Function_data&) _NOEXCEPT_FNPTR; @@ -1625,12 +1626,12 @@ public: void _Construct_with_old_fn(_Fn&& _Func) { const auto _Old_fn_impl = _Func._Getimpl(); if (_Old_fn_impl == nullptr) { - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, false, void>(); } else if (_Func._Local()) { #ifdef _WIN64 _STL_INTERNAL_STATIC_ASSERT(alignof(max_align_t) == alignof(void*)); // 64-bit target, can put small function into small move_only_function directly - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, false, void>(); if constexpr (is_lvalue_reference_v<_Fn>) { _Old_fn_impl->_Copy(_Data._Buf_ptr()); } else { @@ -1663,12 +1664,12 @@ public: _Func._Tidy(); } - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, false, void>(); _Data._Set_large_fn_ptr(_Where); #endif // ^^^ 32-bit ^^^ } else { // Just take ownership of the inner impl pointer - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, false, void>(); if constexpr (is_lvalue_reference_v<_Fn>) { _Data._Set_large_fn_ptr(_Old_fn_impl->_Copy(nullptr)); } else { @@ -1678,9 +1679,9 @@ public: } } - template + template void _Construct_with_fn(_CTypes&&... _Args) { - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Usual, _Vt, _VtInvQuals>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Usual, _Vt, _Noexcept, _VtInvQuals>(); if constexpr (_Large_function_engaged<_Vt>) { _Data._Set_large_fn_ptr(_STD _Function_new_large<_Vt>(_STD forward<_CTypes>(_Args)...)); } else { @@ -1756,8 +1757,17 @@ public: || sizeof(_Vt) > _Function_data::_Buf_size<_Vt> || !is_nothrow_move_constructible_v<_Vt>; + template _NODISCARD auto _Get_invoke() const noexcept { - return _Get_impl(_Data)->_Invoke; + if constexpr (_Noexcept) { +#ifdef __cpp_noexcept_function_type + return reinterpret_cast<_Rx(__stdcall*)(void*, _Types&&...) noexcept>(_Get_impl(_Data)->_Invoke); +#else + static_assert(false); // when noexcept isn't in the type system, this should never be selected +#endif + } else { + return _Get_impl(_Data)->_Invoke; + } } _NODISCARD static const _Impl_t* _Get_impl(const _Function_data& _Data) noexcept { @@ -1771,7 +1781,7 @@ public: return _Ret ? _Ret : &_Null_move_only_function; } - template <_Impl_kind _Kind, class _Vt, class _VtInvQuals> + template <_Impl_kind _Kind, class _Vt, bool _Noexcept, class _VtInvQuals> _NODISCARD static constexpr _Impl_t _Create_impl() noexcept { _Impl_t _Impl{}; if constexpr (_Kind != _Impl_kind::_Usual) { @@ -1834,9 +1844,9 @@ public: return _Impl; } - template <_Impl_kind _Kind, class _Vt, class _VtInvQuals> + template <_Impl_kind _Kind, class _Vt, bool _Noexcept, class _VtInvQuals> _NODISCARD static const _Impl_t* _Create_impl_ptr() noexcept { - static constexpr _Impl_t _Impl = _Create_impl<_Kind, _Vt, _VtInvQuals>(); + static constexpr _Impl_t _Impl = _Create_impl<_Kind, _Vt, _Noexcept, _VtInvQuals>(); return &_Impl; } }; @@ -1856,7 +1866,7 @@ class _Function_call { // Beginning of generated code - DO NOT EDIT manually! template class _Function_call<_Rx(_Types...)> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&; @@ -1865,14 +1875,16 @@ public: static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, _Vt, _Types...> && is_invocable_r_v<_Rx, _Vt&, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) &> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&; @@ -1880,14 +1892,16 @@ public: template static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, _Vt&, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) & { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) &&> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&&; @@ -1895,14 +1909,16 @@ public: template static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, _Vt, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) && { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&; @@ -1911,14 +1927,17 @@ public: static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, const _Vt, _Types...> && is_invocable_r_v<_Rx, const _Vt&, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) const { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const&> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&; @@ -1926,14 +1945,17 @@ public: template static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, const _Vt&, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) const& { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const&&> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&&; @@ -1941,15 +1963,18 @@ public: template static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, const _Vt, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) const&& { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; #ifdef __cpp_noexcept_function_type template class _Function_call<_Rx(_Types...) noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&; @@ -1958,14 +1983,16 @@ public: static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, _Vt, _Types...> && is_nothrow_invocable_r_v<_Rx, _Vt&, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) noexcept { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) & noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&; @@ -1973,14 +2000,16 @@ public: template static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, _Vt&, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) & noexcept { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) && noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&&; @@ -1988,14 +2017,16 @@ public: template static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, _Vt, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) && noexcept { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&; @@ -2004,14 +2035,17 @@ public: static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, const _Vt, _Types...> && is_nothrow_invocable_r_v<_Rx, const _Vt&, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) const noexcept { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const & noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&; @@ -2019,14 +2053,17 @@ public: template static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, const _Vt&, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) const& noexcept { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const && noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&&; @@ -2034,8 +2071,11 @@ public: template static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, const _Vt, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) const&& noexcept { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; #endif // defined(__cpp_noexcept_function_type) @@ -2060,6 +2100,19 @@ private: is_constructible_v, initializer_list<_Ux>&, _CTypes...> && _Call::template _Is_callable_from>; + template + friend class move_only_function; + + template + static constexpr bool _Is_move_only_function_varying_cv_ref_noex() { + if constexpr (_Is_specialization_v<_Vt, move_only_function>) { + return is_same_v; + } else { + return false; + } + } + public: using typename _Call::result_type; @@ -2079,7 +2132,7 @@ public: using _Vt = decay_t<_Fn>; static_assert(is_constructible_v<_Vt, _Fn>, "_Vt should be constructible from _Fn. " "(N4950 [func.wrap.move.ctor]/6)"); - if constexpr (is_same_v<_Vt, function<_Signature...>>) { + if constexpr (is_same_v<_Vt, function>) { this->template _Construct_with_old_fn<_Vt>(_STD forward<_Fn>(_Callable)); } else { if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt> @@ -2090,8 +2143,13 @@ public: } } - using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; - this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable)); + if constexpr (_Is_move_only_function_varying_cv_ref_noex<_Vt>()) { + _Call::_Checked_move(this->_Data, _Callable._Data); + _Callable._Reset_to_null(); + } else { + using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; + this->template _Construct_with_fn<_Vt, _Call::_Noexcept, _VtInvQuals>(_STD forward<_Fn>(_Callable)); + } } } @@ -2102,7 +2160,7 @@ public: static_assert(is_same_v<_Vt, _Fn>, "_Vt should be the same type as _Fn. (N4950 [func.wrap.move.ctor]/12)"); using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; - this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_CTypes>(_Args)...); + this->template _Construct_with_fn<_Vt, _Call::_Noexcept, _VtInvQuals>(_STD forward<_CTypes>(_Args)...); } template @@ -2112,7 +2170,7 @@ public: static_assert(is_same_v<_Vt, _Fn>, "_Vt should be the same type as _Fn. (N4950 [func.wrap.move.ctor]/18)"); using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; - this->template _Construct_with_fn<_Vt, _VtInvQuals>(_Li, _STD forward<_CTypes>(_Args)...); + this->template _Construct_with_fn<_Vt, _Call::_Noexcept, _VtInvQuals>(_Li, _STD forward<_CTypes>(_Args)...); } ~move_only_function() { diff --git a/stl/inc/regex b/stl/inc/regex index 932cddeefe4..35ba5ef909b 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1279,7 +1279,8 @@ enum _Node_flags : int { // flags for nfa nodes with special properties _Fl_class_cl_all_bits = 0x800, // TRANSITION, ABI: GH-5242 _Fl_begin_needs_w = 0x100, _Fl_begin_needs_s = 0x200, - _Fl_begin_needs_d = 0x400 + _Fl_begin_needs_d = 0x400, + _Fl_rep_branchless = 0x800, }; _BITMASK_OPS(_EMPTY_ARGUMENT, _Node_flags) @@ -1700,7 +1701,7 @@ class _Matcher3 { // provides ways to match a regular expression to a text seque public: _Matcher3(_It _Pfirst, _It _Plast, const _RxTraits& _Tr, _Root_node* _Re, unsigned int _Nx, regex_constants::syntax_option_type _Sf, regex_constants::match_flag_type _Mf) - : _Begin(_Pfirst), _End(_Plast), _Rep(_Re), _Sflags(_Sf), _Mflags(_Mf), _Ncap(_Nx), + : _Begin(_Pfirst), _End(_Plast), _Sflags(_Sf), _Mflags(_Mf), _Ncap(_Nx), _Longest((_Re->_Flags & _Fl_longest) && !(_Mf & regex_constants::match_any)), _Traits(_Tr) { _Loop_vals.resize(_Re->_Loops); _Adl_verify_range(_Pfirst, _Plast); @@ -1720,6 +1721,12 @@ public: _Frames_limit = _Calculate_frames_limit(_Input_length); _Complexity_limit = _Calculate_complexity_limit(_Input_length); + // TRANSITION, ABI, GH-6025: + // The first two nodes are of types _N_begin and _N_capture with capturing group 0. + // These nodes do not affect the state of the matcher and thus can be skipped immediately + // before engaging the expensive NFA interpreter loop. + _Start = _Re->_Next->_Next; + // sanitize multiline mode setting #if _REGEX_LEGACY_MULTILINE_MODE _Sflags |= regex_constants::multiline; // old matcher applied multiline mode for all grammars @@ -1763,7 +1770,7 @@ public: _Matched = false; - bool _Succeeded = _Match_pat(_Rep) || _Matched; + bool _Succeeded = _Match_pat(_Start) || _Matched; if (!_Succeeded) { return false; @@ -1832,7 +1839,7 @@ private: _It _Begin; _It _End; - _Node_base* _Rep; + _Node_base* _Start; regex_constants::syntax_option_type _Sflags; regex_constants::match_flag_type _Mflags; bool _Matched = false; @@ -1900,7 +1907,7 @@ private: void _Quantifier(); bool _Alternative(); void _Disjunction(); - void _Calculate_loop_simplicity(_Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep); + void _Calculate_loop_simplicity(_Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep, bool _Nonreentrant); _FwdIt _Pat; _FwdIt _End; @@ -3997,14 +4004,13 @@ bool _Matcher3<_BidIt, _Elem, _RxTraits, _It, _Alloc>::_Match_pat(_Node_base* _N { // record current position auto _Node = static_cast<_Node_capture*>(_Nx); auto _Idx = _Node->_Idx; - if (_Idx != 0U) { - auto& _Group = _Tgt_state._Grps[_Idx]; - auto _Frame_idx = _Push_frame(_Rx_unwind_ops::_Capture_restore_begin, _Node); - auto& _Frame = _Frames[_Frame_idx]; - _Frame._Pos = _Group._Begin; - _Frame._Capture_idx = _Idx; - _Group._Begin = _Tgt_state._Cur; - } + _STL_INTERNAL_CHECK(_Idx != 0U); + auto& _Group = _Tgt_state._Grps[_Idx]; + auto _Frame_idx = _Push_frame(_Rx_unwind_ops::_Capture_restore_begin, _Node); + auto& _Frame = _Frames[_Frame_idx]; + _Frame._Pos = _Group._Begin; + _Frame._Capture_idx = _Idx; + _Group._Begin = _Tgt_state._Cur; break; } @@ -4129,7 +4135,7 @@ bool _Matcher3<_BidIt, _Elem, _RxTraits, _It, _Alloc>::_Match_pat(_Node_base* _N _Node_rep* _Nr = static_cast<_Node_end_rep*>(_Nx)->_Begin_rep; auto& _Sav = _Loop_vals[_Nr->_Loop_number]; bool _Greedy = (_Nr->_Flags & _Fl_greedy) != 0; - if (_Nr->_Simple_loop != 0) { + if (_Nr->_Simple_loop != 0 || (_Nr->_Flags & _Fl_rep_branchless) != 0) { if (_Sav._Loop_idx == 1) { auto& _Base_frame = _Frames[_Sav._Loop_frame_idx]; _Sav._Loop_length = _STD distance(_Base_frame._Pos, _Tgt_state._Cur); @@ -4146,6 +4152,7 @@ bool _Matcher3<_BidIt, _Elem, _RxTraits, _It, _Alloc>::_Match_pat(_Node_base* _N // allocate stack frame holding loop-specific unwinding opcode for second rep and beyond auto _New_frame_code = _Base_frame._Code == _Rx_unwind_ops::_Loop_simple_greedy_firstrep + || _Base_frame._Code == _Rx_unwind_ops::_Loop_greedy ? _Rx_unwind_ops::_Loop_simple_greedy_lastrep : _Rx_unwind_ops::_Do_nothing; auto _New_frame_idx = _Push_frame(_New_frame_code, _Nr); @@ -4469,7 +4476,7 @@ _BidIt _Matcher3<_BidIt, _Elem, _RxTraits, _It, _Alloc>::_Skip( static constexpr wchar_t _Line_terminators_wchar_t[] = {static_cast(_Meta_cr), static_cast(_Meta_nl), static_cast(_Meta_ls), static_cast(_Meta_ps)}; constexpr unsigned int _Max_recursion_depth = 50U; - _Node_base* _Nx = _Node_arg ? _Node_arg : _Rep; + _Node_base* _Nx = _Node_arg ? _Node_arg : _Start; while (_First_arg != _Last && _Nx) { // check current node switch (_Nx->_Kind) { // handle current node's type @@ -5424,7 +5431,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Disjunction() { // check for valid dis template void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity( - _Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep) { + _Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep, const bool _Nonreentrant) { // walks regex NFA, calculates values of _Node_rep::_Simple_loop for (; _Nx != _Ne && _Nx; _Nx = _Nx->_Next) { switch (_Nx->_Kind) { @@ -5432,11 +5439,12 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity( // _Node_if inside a _Node_rep makes the rep not simple if (_Outer_rep) { _Outer_rep->_Simple_loop = 0; + _Outer_rep->_Flags &= ~_Fl_rep_branchless; } // visit each branch of the if for (_Node_if* _Branch = static_cast<_Node_if*>(_Nx)->_Child; _Branch; _Branch = _Branch->_Child) { - _Calculate_loop_simplicity(_Branch->_Next, _Branch->_Endif, _Outer_rep); + _Calculate_loop_simplicity(_Branch->_Next, _Branch->_Endif, _Outer_rep, _Nonreentrant); } break; @@ -5444,13 +5452,14 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity( // A positive lookahead assertion inside a _Node_rep makes the rep not simple if (_Outer_rep) { _Outer_rep->_Simple_loop = 0; + _Outer_rep->_Flags &= ~_Fl_rep_branchless; } _FALLTHROUGH; case _N_neg_assert: // visit the assertion body // note _Outer_rep being reset: the assertion regex is completely independent - _Calculate_loop_simplicity(static_cast<_Node_assert*>(_Nx)->_Child, nullptr, nullptr); + _Calculate_loop_simplicity(static_cast<_Node_assert*>(_Nx)->_Child, nullptr, nullptr, true); break; case _N_rep: @@ -5459,15 +5468,20 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity( // If _Outer_rep can repeat at most once, we have to analyze the structure of the inner loop. if (_Outer_rep) { _Outer_rep->_Simple_loop = 0; - auto _Inner_rep = static_cast<_Node_rep*>(_Nx); - if (_Outer_rep->_Max >= 0 && _Outer_rep->_Max <= 1) { - _Calculate_loop_simplicity(_Inner_rep->_Next, _Inner_rep->_End_rep->_Next, _Inner_rep); - _Nx = _Inner_rep->_End_rep; - } else { + _Outer_rep->_Flags &= ~_Fl_rep_branchless; + auto _Inner_rep = static_cast<_Node_rep*>(_Nx); + _Inner_rep->_Flags |= _Fl_rep_branchless; + const bool _Inner_nonreentrant = _Outer_rep->_Max >= 0 && _Outer_rep->_Max <= 1 && _Nonreentrant; + if (!_Inner_nonreentrant) { _Inner_rep->_Simple_loop = 0; } + + _Calculate_loop_simplicity( + _Inner_rep->_Next, _Inner_rep->_End_rep->_Next, _Inner_rep, _Inner_nonreentrant); + _Nx = _Inner_rep->_End_rep; } else { _Outer_rep = static_cast<_Node_rep*>(_Nx); + _Outer_rep->_Flags |= _Fl_rep_branchless; } break; @@ -5492,6 +5506,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity( if (_Coll_diff_size || _Node->_Equiv || ((_Flags & regex_constants::collate) && (_Node->_Ranges || (_Node->_Flags & _Fl_negate)))) { _Outer_rep->_Simple_loop = 0; + _Outer_rep->_Flags &= ~_Fl_rep_branchless; } } break; @@ -5530,7 +5545,7 @@ _Root_node* _Parser2<_FwdIt, _Elem, _RxTraits>::_Compile() { // compile regular _Res = _Nfa._End_pattern(); _Res->_Fl = _Flags; _Res->_Marks = _Mark_count(); - _Calculate_loop_simplicity(_Res, nullptr, nullptr); + _Calculate_loop_simplicity(_Res, nullptr, nullptr, true); _Guard._Target = nullptr; return _Res; } diff --git a/stl/inc/vector b/stl/inc/vector index 2994548bd8c..5ada42b06b7 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -39,7 +39,8 @@ public: using pointer = typename _Myvec::const_pointer; using reference = const value_type&; - using _Tptr = typename _Myvec::pointer; + using _Tptr = typename _Myvec::pointer; + using _Myvec_t = _Myvec; // helper for expression evaluator _CONSTEXPR20 _Vector_const_iterator() noexcept : _Ptr() {} @@ -3705,8 +3706,8 @@ _CONSTEXPR20 void _Fill_vbool(_VbIt _First, const _VbIt _Last, const bool _Val) } else #endif // _HAS_CXX20 { - const auto _VbFirst_ch = reinterpret_cast(_VbFirst); - const auto _VbLast_ch = reinterpret_cast(_VbLast); + const auto _VbFirst_ch = reinterpret_cast(_VbFirst); + const auto _VbLast_ch = reinterpret_cast(_VbLast); const auto _Count_ch = static_cast(_VbLast_ch - _VbFirst_ch); const auto _ValChar = static_cast(_Val ? -1 : 0); _CSTD memset(_VbFirst, _ValChar, _Count_ch); @@ -3895,21 +3896,24 @@ _CONSTEXPR20 _OutIt _Copy_vbool(_VbIt _First, _VbIt _Last, _OutIt _Dest) { } else #endif // _HAS_CXX20 { - // If _First and _Dest have matching char alignment, use memmove + // If _First and _Dest have matching unsigned char alignment, use memmove const auto _UnalignedFirstBits = _First._Myoff & _Vbase{7}; const auto _UnalignedDestBits = _Dest._Myoff & _Vbase{7}; if (_UnalignedFirstBits == _UnalignedDestBits) { const auto _UnalignedLastBits = _Last._Myoff & _Vbase{7}; - auto _VbFirst_ch = reinterpret_cast(_VbFirst) + (_First._Myoff - _UnalignedFirstBits) / 8; - const auto _VbLast_ch = reinterpret_cast(_VbLast) + (_Last._Myoff - _UnalignedLastBits) / 8; - auto _VbDest_ch = reinterpret_cast(_VbDest) + (_Dest._Myoff - _UnalignedDestBits) / 8; + auto _VbFirst_ch = + reinterpret_cast(_VbFirst) + (_First._Myoff - _UnalignedFirstBits) / 8; + const auto _VbLast_ch = + reinterpret_cast(_VbLast) + (_Last._Myoff - _UnalignedLastBits) / 8; + auto _VbDest_ch = reinterpret_cast(_VbDest) + (_Dest._Myoff - _UnalignedDestBits) / 8; - // Copy bits until the next char alignment + // Copy bits until the next unsigned char alignment if (_UnalignedFirstBits != 0) { - const auto _SourceBitMask = static_cast(UCHAR_MAX << _UnalignedFirstBits); - const auto _DestBitMask = static_cast(UCHAR_MAX >> (8 - _UnalignedFirstBits)); - *_VbDest_ch = (*_VbDest_ch & _DestBitMask) | (*_VbFirst_ch & _SourceBitMask); + const auto _SourceBitMask = static_cast(UCHAR_MAX << _UnalignedFirstBits); + const auto _DestBitMask = static_cast(UCHAR_MAX >> (8 - _UnalignedFirstBits)); + *_VbDest_ch = + static_cast((*_VbDest_ch & _DestBitMask) | (*_VbFirst_ch & _SourceBitMask)); ++_VbFirst_ch; ++_VbDest_ch; } @@ -3918,9 +3922,9 @@ _CONSTEXPR20 _OutIt _Copy_vbool(_VbIt _First, _VbIt _Last, _OutIt _Dest) { // Copy remaining last bits if (_UnalignedLastBits != 0) { - const auto _SourceBitMask = static_cast(UCHAR_MAX >> (8 - _UnalignedLastBits)); - const auto _DestBitMask = static_cast(UCHAR_MAX << _UnalignedLastBits); - *_VbDest_ch = (*_VbDest_ch & _DestBitMask) | (*_VbLast_ch & _SourceBitMask); + const auto _SourceBitMask = static_cast(UCHAR_MAX >> (8 - _UnalignedLastBits)); + const auto _DestBitMask = static_cast(UCHAR_MAX << _UnalignedLastBits); + *_VbDest_ch = static_cast((*_VbDest_ch & _DestBitMask) | (*_VbLast_ch & _SourceBitMask)); } return _DestEnd; diff --git a/stl/inc/xutility b/stl/inc/xutility index 39e202b8c27..0ce4be4193f 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -88,7 +88,7 @@ _STL_DISABLE_CLANG_WARNINGS #define _VECTORIZED_FIND_LAST _VECTORIZED_FOR_X64_X86 #define _VECTORIZED_FIND_LAST_OF _VECTORIZED_FOR_X64_X86 #define _VECTORIZED_INCLUDES _VECTORIZED_FOR_X64_X86 -#define _VECTORIZED_IS_SORTED_UNTIL _VECTORIZED_FOR_X64_X86 +#define _VECTORIZED_IS_SORTED_UNTIL _VECTORIZED_FOR_X64_X86_ARM64 #define _VECTORIZED_MINMAX _VECTORIZED_FOR_X64_X86_ARM64 #define _VECTORIZED_MINMAX_ELEMENT _VECTORIZED_FOR_X64_X86_ARM64 #define _VECTORIZED_MISMATCH _VECTORIZED_FOR_X64_X86 diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index baaf9c6539a..7550a613043 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1935,11 +1935,9 @@ _EMIT_STL_ERROR(STL1013, "The STL doesn't support /RTCc because it rejects confo // The earliest Windows supported by this implementation is Windows 10. #ifdef __cpp_noexcept_function_type -#define _NOEXCEPT_FNPTR noexcept -#define _NOEXCEPT_FNPTR_COND(...) noexcept(__VA_ARGS__) +#define _NOEXCEPT_FNPTR noexcept #else // ^^^ defined(__cpp_noexcept_function_type) / !defined(__cpp_noexcept_function_type) vvv #define _NOEXCEPT_FNPTR -#define _NOEXCEPT_FNPTR_COND(...) #endif // ^^^ !defined(__cpp_noexcept_function_type) ^^^ #ifdef __clang__ diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index a9d49bd754a..57f33bfc920 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -1085,6 +1085,11 @@ namespace { return vget_lane_u64(vreinterpret_u64_u8(_Res), 0); } + static uint64_t _Match_mask(const _Vec_t _Val_lo, const _Vec_t _Val_hi) noexcept { + const uint64x2_t _Val = vreinterpretq_u64_s8(vorrq_s8(_Val_lo, _Val_hi)); + return vgetq_lane_u64(vpaddq_u64(_Val, _Val), 0); + } + static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept { return _CountTrailingZeros64(_Mask) >> 2; } @@ -1396,6 +1401,11 @@ namespace { return vget_lane_u64(vreinterpret_u64_u16(_Res), 0); } + static uint64_t _Match_mask(const _Vec_t _Val_lo, const _Vec_t _Val_hi) noexcept { + const int8x8_t _Val = vaddhn_s16(_Val_lo, _Val_hi); + return vget_lane_u64(vreinterpret_u64_s8(_Val), 0); + } + static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept { return _CountTrailingZeros64(_Mask) >> 2; } @@ -1704,6 +1714,11 @@ namespace { return vget_lane_u64(vreinterpret_u64_u32(_Res), 0); } + static uint64_t _Match_mask(const _Vec_t _Val_lo, const _Vec_t _Val_hi) noexcept { + const int8x8_t _Val = vaddhn_s16(vreinterpretq_s16_s32(_Val_lo), vreinterpretq_s16_s32(_Val_hi)); + return vget_lane_u64(vreinterpret_u64_s8(_Val), 0); + } + static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept { return _CountTrailingZeros64(_Mask) >> 2; } @@ -1983,6 +1998,21 @@ namespace { return _Val; } + // Compresses a 128-bit Mask of 2 64-bit values into a 64-bit Mask of 2 32-bit values. + static uint64_t _Mask(const _Vec_t _Val) noexcept { + const uint32x2_t _Res = vreinterpret_u32_s32(vmovn_s64(_Val)); + return vget_lane_u64(vreinterpret_u64_u32(_Res), 0); + } + + static uint64_t _Match_mask(const _Vec_t _Val_lo, const _Vec_t _Val_hi) noexcept { + const int8x8_t _Val = vaddhn_s16(vreinterpretq_s16_s64(_Val_lo), vreinterpretq_s16_s64(_Val_hi)); + return vget_lane_u64(vreinterpret_u64_s8(_Val), 0); + } + + static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept { + return _CountTrailingZeros64(_Mask) >> 2; + } + static _Vec_t _Load(const void* const _Src) noexcept { return vld1q_s64(reinterpret_cast(_Src)); } @@ -2048,6 +2078,10 @@ namespace { static _Vec_t _Max_u(const _Vec_t _First, const _Vec_t _Second) noexcept { return _Max(_First, _Second, _Cmp_gt_u(_Second, _First)); } + + static _Vec_t _Mask_cast(const _Vec_t _Mask) noexcept { + return _Mask; + } }; #elif !defined(_M_ARM64EC) struct _Traits_8_sse : _Traits_8_base, _Traits_sse_base { @@ -2284,6 +2318,10 @@ namespace { return _Traits_4_neon::_Mask(_Val); } + static uint64_t _Match_mask(const _Idx_t _Val_lo, const _Idx_t _Val_hi) noexcept { + return _Traits_4_neon::_Match_mask(_Val_lo, _Val_hi); + } + static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept { return _Traits_4_neon::_Get_first_h_pos(_Mask); } @@ -2549,12 +2587,15 @@ namespace { // Compresses a 128-bit Mask of 2 64-bit values into a 64-bit Mask of 2 32-bit values. static uint64_t _Mask(const int64x2_t _Val) noexcept { - const uint32x2_t _Res = vreinterpret_u32_s32(vmovn_s64(_Val)); - return vget_lane_u64(vreinterpret_u64_u32(_Res), 0); + return _Traits_8_neon::_Mask(_Val); + } + + static uint64_t _Match_mask(const _Idx_t _Val_lo, const _Idx_t _Val_hi) noexcept { + return _Traits_8_neon::_Match_mask(_Val_lo, _Val_hi); } static unsigned long _Get_first_h_pos(const uint64_t _Mask) noexcept { - return _CountTrailingZeros64(_Mask) >> 2; + return _Traits_8_neon::_Get_first_h_pos(_Mask); } static unsigned long _Get_last_h_pos(const uint64_t _Mask) noexcept { @@ -3490,7 +3531,88 @@ namespace { return _Minmax_impl<_Mode, typename _Traits::_Scalar, _Sign>(_First, _Last); } -#ifndef _M_ARM64 +#ifdef _M_ARM64 + template + const void* _Is_sorted_until_impl(const void* _First, const void* const _Last, const bool _Greater) noexcept { + const ptrdiff_t _Left_off = 0 - static_cast(_Greater); + const ptrdiff_t _Right_off = static_cast(_Greater) - 1; + + if constexpr (_Traits::_Vectorized) { + const size_t _Total_size_bytes = _Byte_length(_First, _Last); + + const auto _Cmp_gt_wrap = [](const auto _Right, const auto _Left) noexcept { + constexpr bool _Unsigned = static_cast<_Ty>(-1) > _Ty{0}; + + if constexpr (_Unsigned && _Traits::_Has_unsigned_cmp) { + return _Traits::_Cmp_gt_u(_Right, _Left); + } else { + return _Traits::_Cmp_gt(_Right, _Left); + } + }; + + if (_Total_size_bytes >= 32) { + constexpr size_t _Bytes_per_iter = 2 * _Traits::_Vec_size; + const size_t _Vec_byte_size = _Total_size_bytes & ~(_Bytes_per_iter - 1); + const void* _Stop_at = _First; + _Advance_bytes(_Stop_at, _Vec_byte_size); + + do { + const void* const _Next = static_cast(_First) + _Traits::_Vec_size; + + const auto _Left_lo = _Traits::_Load(static_cast(_First) + _Left_off); + const auto _Right_lo = _Traits::_Load(static_cast(_First) + _Right_off); + const auto _Left_hi = _Traits::_Load(static_cast(_Next) + _Left_off); + const auto _Right_hi = _Traits::_Load(static_cast(_Next) + _Right_off); + + const auto _Is_less_lo = _Cmp_gt_wrap(_Right_lo, _Left_lo); + const auto _Is_less_hi = _Cmp_gt_wrap(_Right_hi, _Left_hi); + const auto _Any_match = _Traits::_Match_mask(_Is_less_lo, _Is_less_hi); + + if (_Any_match != 0) { + const auto _Mask_lo = _Traits::_Mask(_Is_less_lo); + if (_Mask_lo != 0) { + const unsigned long _H_pos = _Traits::_Get_first_h_pos(_Mask_lo); + _Advance_bytes(_First, _H_pos); + return _First; + } + + const auto _Mask_hi = _Traits::_Mask(_Is_less_hi); + const unsigned long _H_pos = _Traits::_Get_first_h_pos(_Mask_hi) + _Traits::_Vec_size; + _Advance_bytes(_First, _H_pos); + return _First; + } + + _Advance_bytes(_First, 2 * _Traits::_Vec_size); + } while (_First != _Stop_at); + } + + const size_t _Has_vec_tail = (_Byte_length(_First, _Last) & ~_Traits::_Vec_mask) != 0; + if (_Has_vec_tail) { + const auto _Left = _Traits::_Load(static_cast(_First) + _Left_off); + const auto _Right = _Traits::_Load(static_cast(_First) + _Right_off); + + const auto _Is_less = _Cmp_gt_wrap(_Right, _Left); + const auto _Mask = _Traits::_Mask(_Traits::_Mask_cast(_Is_less)); + + if (_Mask != 0) { + const unsigned long _H_pos = _Traits::_Get_first_h_pos(_Mask); + _Advance_bytes(_First, _H_pos); + return _First; + } + + _Advance_bytes(_First, _Traits::_Vec_size); + } + } + + for (const _Ty* _Ptr = static_cast(_First); _Ptr != _Last; ++_Ptr) { + if (_Ptr[_Left_off] < _Ptr[_Right_off]) { + return _Ptr; + } + } + + return _Last; + } +#else // ^^^ defined(_M_ARM64) / !defined(_M_ARM64) vvv template const void* _Is_sorted_until_impl(const void* _First, const void* const _Last, const bool _Greater) noexcept { const ptrdiff_t _Left_off = 0 - static_cast(_Greater); @@ -3569,6 +3691,7 @@ namespace { return _Last; } +#endif // ^^^ !defined(_M_ARM64) ^^^ template const void* __stdcall _Is_sorted_until_disp( @@ -3579,7 +3702,11 @@ namespace { _Advance_bytes(_First, sizeof(_Ty)); -#ifndef _M_ARM64EC +#ifdef _M_ARM64 + if (_Byte_length(_First, _Last) >= 16) { + return _Is_sorted_until_impl(_First, _Last, _Greater); + } +#elif !defined(_M_ARM64EC) if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { return _Is_sorted_until_impl(_First, _Last, _Greater); } @@ -3590,7 +3717,6 @@ namespace { #endif // ^^^ !defined(_M_ARM64EC) ^^^ return _Is_sorted_until_impl(_First, _Last, _Greater); } -#endif // ^^^ !defined(_M_ARM64) ^^^ } // namespace _Sorting } // unnamed namespace @@ -3812,7 +3938,6 @@ __declspec(noalias) _Min_max_d __stdcall __std_minmax_d(const void* const _First return _Sorting::_Minmax_disp<_Sorting::_Mode_both, _Sorting::_Traits_d, true>(_First, _Last); } -#ifndef _M_ARM64 const void* __stdcall __std_is_sorted_until_1i( const void* const _First, const void* const _Last, const bool _Greater) noexcept { return _Sorting::_Is_sorted_until_disp<_Sorting::_Traits_1, int8_t>(_First, _Last, _Greater); @@ -3862,7 +3987,6 @@ const void* __stdcall __std_is_sorted_until_d( const void* const _First, const void* const _Last, const bool _Greater) noexcept { return _Sorting::_Is_sorted_until_disp<_Sorting::_Traits_d, double>(_First, _Last, _Greater); } -#endif // ^^^ !defined(_M_ARM64) ^^^ } // extern "C" diff --git a/tests/std/test.lst b/tests/std/test.lst index 7e348a49808..b6d7f41de16 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -277,6 +277,7 @@ tests\GH_005546_containers_size_type_cast tests\GH_005553_regex_character_translation tests\GH_005768_pow_accuracy tests\GH_005800_stable_sort_large_alignment +tests\GH_005968_headers_provide_begin_end tests\LWG2381_num_get_floating_point tests\LWG2510_tag_classes tests\LWG2597_complex_branch_cut diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/env.lst b/tests/std/tests/GH_000625_vector_bool_optimization/env.lst index 19f025bd0e6..52bbd11aa13 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/env.lst +++ b/tests/std/tests/GH_000625_vector_bool_optimization/env.lst @@ -1,4 +1,7 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\usual_matrix.lst +RUNALL_INCLUDE ..\impure_matrix.lst +RUNALL_CROSSLIST +* PM_CL="" +* PM_CL="/J" diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index 41e73cff35a..6a7ab81aea1 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -18,8 +18,6 @@ #define CONSTEXPR20 inline #endif -#pragma warning(disable : 4365) // conversion from 'unsigned __int64' to 'const __int64', signed/unsigned mismatch - using namespace std; constexpr int blockSize = 32; @@ -84,14 +82,14 @@ CONSTEXPR20 void test_transform_helper(const size_t length) { transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xnor_expected_raw), equal_to<>{}); transform(begin(source_raw), end(source_raw), begin(not_expected_raw), logical_not<>{}); - const vector source1(source_raw, source_raw + length); - const vector source2(source2_raw, source2_raw + length); + const vector source1(source_raw, source_raw + static_cast(length)); + const vector source2(source2_raw, source2_raw + static_cast(length)); - vector and_expected(and_expected_raw, and_expected_raw + length); - vector or_expected(or_expected_raw, or_expected_raw + length); - vector xor_expected(xor_expected_raw, xor_expected_raw + length); - vector xnor_expected(xnor_expected_raw, xnor_expected_raw + length); - vector not_expected(not_expected_raw, not_expected_raw + length); + vector and_expected(and_expected_raw, and_expected_raw + static_cast(length)); + vector or_expected(or_expected_raw, or_expected_raw + static_cast(length)); + vector xor_expected(xor_expected_raw, xor_expected_raw + static_cast(length)); + vector xnor_expected(xnor_expected_raw, xnor_expected_raw + static_cast(length)); + vector not_expected(not_expected_raw, not_expected_raw + static_cast(length)); and_expected.resize(length + 3, false); or_expected.resize(length + 3, false); @@ -110,49 +108,49 @@ CONSTEXPR20 void test_transform_helper(const size_t length) { const auto cfirst1 = source1.cbegin(); const auto first2 = source2.begin(); const auto cfirst2 = source2.cbegin(); - const auto last1 = first1 + length; - const auto clast1 = cfirst1 + length; + const auto last1 = first1 + static_cast(length); + const auto clast1 = cfirst1 + static_cast(length); { auto and_ret = transform(first1, last1, first2, and_actual.begin(), logical_and<>{}); assert(and_actual == and_expected); - assert(and_ret == and_actual.begin() + length); + assert(and_ret == and_actual.begin() + static_cast(length)); and_actual.assign(and_actual.size(), false); and_ret = transform(first1, last1, first2, and_actual.begin(), bit_and<>{}); assert(and_actual == and_expected); - assert(and_ret == and_actual.begin() + length); + assert(and_ret == and_actual.begin() + static_cast(length)); } { auto or_ret = transform(first1, last1, cfirst2, or_actual.begin(), logical_or<>{}); assert(or_actual == or_expected); - assert(or_ret == or_actual.begin() + length); + assert(or_ret == or_actual.begin() + static_cast(length)); or_actual.assign(or_actual.size(), false); or_ret = transform(first1, last1, cfirst2, or_actual.begin(), bit_or<>{}); assert(or_actual == or_expected); - assert(or_ret == or_actual.begin() + length); + assert(or_ret == or_actual.begin() + static_cast(length)); } { auto xor_ret = transform(cfirst1, clast1, first2, xor_actual.begin(), not_equal_to<>{}); assert(xor_actual == xor_expected); - assert(xor_ret == xor_actual.begin() + length); + assert(xor_ret == xor_actual.begin() + static_cast(length)); xor_actual.assign(xor_actual.size(), false); xor_ret = transform(cfirst1, clast1, first2, xor_actual.begin(), bit_xor<>{}); assert(xor_actual == xor_expected); - assert(xor_ret == xor_actual.begin() + length); + assert(xor_ret == xor_actual.begin() + static_cast(length)); } { const auto xnor_ret = transform(cfirst1, clast1, cfirst2, xnor_actual.begin(), equal_to<>{}); assert(xnor_actual == xnor_expected); - assert(xnor_ret == xnor_actual.begin() + length); + assert(xnor_ret == xnor_actual.begin() + static_cast(length)); // bit_xnor doesn't exist in the Standard } @@ -160,7 +158,7 @@ CONSTEXPR20 void test_transform_helper(const size_t length) { { auto not_ret = transform(first1, last1, not_actual.begin(), logical_not<>{}); assert(not_actual == not_expected); - assert(not_ret == not_actual.begin() + length); + assert(not_ret == not_actual.begin() + static_cast(length)); not_actual.assign(not_actual.size(), false); @@ -168,7 +166,7 @@ CONSTEXPR20 void test_transform_helper(const size_t length) { // Continue using logical_not to test vector::const_iterator: not_ret = transform(cfirst1, clast1, not_actual.begin(), logical_not<>{}); assert(not_actual == not_expected); - assert(not_ret == not_actual.begin() + length); + assert(not_ret == not_actual.begin() + static_cast(length)); } } @@ -459,28 +457,29 @@ CONSTEXPR20 void test_copy_no_offset(const size_t length) { { vector dest(length, false); - const auto res_copy = copy(source.begin(), next(source.begin(), length), dest.begin()); + const auto res_copy = copy(source.begin(), source.begin() + static_cast(length), dest.begin()); assert(dest == result); assert(res_copy == dest.end()); } { vector dest_n(length, false); - const auto res_copy_n = copy_n(source.begin(), length, dest_n.begin()); + const auto res_copy_n = copy_n(source.begin(), static_cast(length), dest_n.begin()); assert(dest_n == result); assert(res_copy_n == dest_n.end()); } { vector dest_backward(length, false); - const auto res_copy_backward = copy_backward(source.begin(), next(source.begin(), length), dest_backward.end()); + const auto res_copy_backward = + copy_backward(source.begin(), source.begin() + static_cast(length), dest_backward.end()); assert(dest_backward == result); assert(res_copy_backward == dest_backward.begin()); } { vector dest_move(length, false); - const auto res_move = move(source.begin(), next(source.begin(), length), dest_move.begin()); + const auto res_move = move(source.begin(), source.begin() + static_cast(length), dest_move.begin()); assert(dest_move == result); assert(res_move == dest_move.end()); } @@ -488,7 +487,7 @@ CONSTEXPR20 void test_copy_no_offset(const size_t length) { { vector dest_move_backward(length, false); const auto res_move_backward = - move_backward(source.begin(), next(source.begin(), length), dest_move_backward.end()); + move_backward(source.begin(), source.begin() + static_cast(length), dest_move_backward.end()); assert(dest_move_backward == result); assert(res_move_backward == dest_move_backward.begin()); } @@ -546,37 +545,39 @@ CONSTEXPR20 void test_copy_offset_source(const size_t length) { { vector dest(length, false); - const auto res_copy = copy(next(source.begin()), next(source.begin(), length + 1), dest.begin()); + const auto res_copy = + copy(next(source.begin()), source.begin() + static_cast(length) + 1, dest.begin()); assert(dest == result); assert(res_copy == dest.end()); } { vector dest_n(length, false); - const auto res_copy_n = copy_n(next(source.begin()), length, dest_n.begin()); + const auto res_copy_n = copy_n(next(source.begin()), static_cast(length), dest_n.begin()); assert(dest_n == result); assert(res_copy_n == dest_n.end()); } { vector dest_backward(length, false); - const auto res_copy_backward = - copy_backward(next(source.begin()), next(source.begin(), length + 1), dest_backward.end()); + const auto res_copy_backward = copy_backward( + next(source.begin()), source.begin() + static_cast(length) + 1, dest_backward.end()); assert(dest_backward == result); assert(res_copy_backward == dest_backward.begin()); } { vector dest_move(length, false); - const auto res_move = move(next(source.begin()), next(source.begin(), length + 1), dest_move.begin()); + const auto res_move = + move(next(source.begin()), source.begin() + static_cast(length) + 1, dest_move.begin()); assert(dest_move == result); assert(res_move == dest_move.end()); } { vector dest_move_backward(length, false); - const auto res_move_backward = - move_backward(next(source.begin()), next(source.begin(), length + 1), dest_move_backward.end()); + const auto res_move_backward = move_backward( + next(source.begin()), source.begin() + static_cast(length) + 1, dest_move_backward.end()); assert(dest_move_backward == result); assert(res_move_backward == dest_move_backward.begin()); } @@ -639,28 +640,30 @@ CONSTEXPR20 void test_copy_offset_dest(const size_t length) { { vector dest(length + 1, false); - const auto res_copy = copy(source.begin(), next(source.begin(), length), next(dest.begin())); + const auto res_copy = copy(source.begin(), source.begin() + static_cast(length), next(dest.begin())); assert(dest == result); assert(res_copy == dest.end()); } { vector dest_n(length + 1, false); - const auto res_copy_n = copy_n(source.begin(), length, next(dest_n.begin())); + const auto res_copy_n = copy_n(source.begin(), static_cast(length), next(dest_n.begin())); assert(dest_n == result); assert(res_copy_n == dest_n.end()); } { vector dest_backward(length + 1, false); - const auto res_copy_backward = copy_backward(source.begin(), next(source.begin(), length), dest_backward.end()); + const auto res_copy_backward = + copy_backward(source.begin(), source.begin() + static_cast(length), dest_backward.end()); assert(dest_backward == result); assert(res_copy_backward == next(dest_backward.begin())); } { vector dest_move(length + 1, false); - const auto res_move = move(source.begin(), next(source.begin(), length), next(dest_move.begin())); + const auto res_move = + move(source.begin(), source.begin() + static_cast(length), next(dest_move.begin())); assert(dest_move == result); assert(res_move == dest_move.end()); } @@ -668,7 +671,7 @@ CONSTEXPR20 void test_copy_offset_dest(const size_t length) { { vector dest_move_backward(length + 1, false); const auto res_move_backward = - move_backward(source.begin(), next(source.begin(), length), dest_move_backward.end()); + move_backward(source.begin(), source.begin() + static_cast(length), dest_move_backward.end()); assert(dest_move_backward == result); assert(res_move_backward == next(dest_move_backward.begin())); } @@ -731,14 +734,15 @@ CONSTEXPR20 void test_copy_offset_match(const size_t length) { { vector dest(length, false); - const auto res_copy = copy(next(source.begin()), next(source.begin(), length), next(dest.begin())); + const auto res_copy = + copy(next(source.begin()), source.begin() + static_cast(length), next(dest.begin())); assert(dest == result); assert(res_copy == dest.end()); } { vector dest_n(length, false); - const auto res_copy_n = copy_n(next(source.begin()), length - 1, next(dest_n.begin())); + const auto res_copy_n = copy_n(next(source.begin()), static_cast(length) - 1, next(dest_n.begin())); assert(dest_n == result); assert(res_copy_n == dest_n.end()); } @@ -746,22 +750,23 @@ CONSTEXPR20 void test_copy_offset_match(const size_t length) { { vector dest_backward(length, false); const auto res_copy_backward = - copy_backward(next(source.begin()), next(source.begin(), length), dest_backward.end()); + copy_backward(next(source.begin()), source.begin() + static_cast(length), dest_backward.end()); assert(dest_backward == result); assert(res_copy_backward == next(dest_backward.begin())); } { vector dest_move(length, false); - const auto res_move = move(next(source.begin()), next(source.begin(), length), next(dest_move.begin())); + const auto res_move = + move(next(source.begin()), source.begin() + static_cast(length), next(dest_move.begin())); assert(dest_move == result); assert(res_move == dest_move.end()); } { vector dest_move_backward(length, false); - const auto res_move_backward = - move_backward(next(source.begin()), next(source.begin(), length), dest_move_backward.end()); + const auto res_move_backward = move_backward( + next(source.begin()), source.begin() + static_cast(length), dest_move_backward.end()); assert(dest_move_backward == result); assert(res_move_backward == next(dest_move_backward.begin())); } @@ -824,14 +829,16 @@ CONSTEXPR20 void test_copy_offset_mismatch_leftshift(const size_t length) { { vector dest(length + 1, false); - const auto res_copy = copy(next(source.begin()), next(source.begin(), length), next(dest.begin(), 2)); + const auto res_copy = + copy(next(source.begin()), source.begin() + static_cast(length), next(dest.begin(), 2)); assert(dest == result); assert(res_copy == dest.end()); } { vector dest_n(length + 1, false); - const auto res_copy_n = copy_n(next(source.begin()), length - 1, next(dest_n.begin(), 2)); + const auto res_copy_n = + copy_n(next(source.begin()), static_cast(length) - 1, next(dest_n.begin(), 2)); assert(dest_n == result); assert(res_copy_n == dest_n.end()); } @@ -839,22 +846,23 @@ CONSTEXPR20 void test_copy_offset_mismatch_leftshift(const size_t length) { { vector dest_backward(length + 1, false); const auto res_copy_backward = - copy_backward(next(source.begin()), next(source.begin(), length), dest_backward.end()); + copy_backward(next(source.begin()), source.begin() + static_cast(length), dest_backward.end()); assert(dest_backward == result); assert(res_copy_backward == next(dest_backward.begin(), 2)); } { vector dest_move(length + 1, false); - const auto res_move = move(next(source.begin()), next(source.begin(), length), next(dest_move.begin(), 2)); + const auto res_move = + move(next(source.begin()), source.begin() + static_cast(length), next(dest_move.begin(), 2)); assert(dest_move == result); assert(res_move == dest_move.end()); } { vector dest_move_backward(length + 1, false); - const auto res_move_backward = - move_backward(next(source.begin()), next(source.begin(), length), dest_move_backward.end()); + const auto res_move_backward = move_backward( + next(source.begin()), source.begin() + static_cast(length), dest_move_backward.end()); assert(dest_move_backward == result); assert(res_move_backward == next(dest_move_backward.begin(), 2)); } @@ -919,37 +927,40 @@ CONSTEXPR20 void test_copy_offset_mismatch_rightshift(const size_t length) { { vector dest(length, false); - const auto res_copy = copy(next(source.begin(), 2), next(source.begin(), length + 1), next(dest.begin())); + const auto res_copy = + copy(next(source.begin(), 2), source.begin() + static_cast(length) + 1, next(dest.begin())); assert(dest == result); assert(res_copy == dest.end()); } { vector dest_n(length, false); - const auto res_copy_n = copy_n(next(source.begin(), 2), length - 1, next(dest_n.begin())); + const auto res_copy_n = + copy_n(next(source.begin(), 2), static_cast(length) - 1, next(dest_n.begin())); assert(dest_n == result); assert(res_copy_n == dest_n.end()); } { vector dest_backward(length, false); - const auto res_copy_backward = - copy_backward(next(source.begin(), 2), next(source.begin(), length + 1), dest_backward.end()); + const auto res_copy_backward = copy_backward( + next(source.begin(), 2), source.begin() + static_cast(length) + 1, dest_backward.end()); assert(dest_backward == result); assert(res_copy_backward == next(dest_backward.begin())); } { vector dest_move(length, false); - const auto res_move = move(next(source.begin(), 2), next(source.begin(), length + 1), next(dest_move.begin())); + const auto res_move = + move(next(source.begin(), 2), source.begin() + static_cast(length) + 1, next(dest_move.begin())); assert(dest_move == result); assert(res_move == dest_move.end()); } { vector dest_move_backward(length, false); - const auto res_move_backward = - move_backward(next(source.begin(), 2), next(source.begin(), length + 1), dest_move_backward.end()); + const auto res_move_backward = move_backward( + next(source.begin(), 2), source.begin() + static_cast(length) + 1, dest_move_backward.end()); assert(dest_move_backward == result); assert(res_move_backward == next(dest_move_backward.begin())); } @@ -1012,37 +1023,40 @@ CONSTEXPR20 void test_copy_offset_aligned(const size_t length) { { vector dest(length, false); - const auto res_copy = copy(next(source.begin(), 9), next(source.begin(), length + 8), next(dest.begin())); + const auto res_copy = + copy(next(source.begin(), 9), source.begin() + static_cast(length) + 8, next(dest.begin())); assert(dest == result); assert(res_copy == dest.end()); } { vector dest_n(length, false); - const auto res_copy_n = copy_n(next(source.begin(), 9), length - 1, next(dest_n.begin())); + const auto res_copy_n = + copy_n(next(source.begin(), 9), static_cast(length) - 1, next(dest_n.begin())); assert(dest_n == result); assert(res_copy_n == dest_n.end()); } { vector dest_backward(length, false); - const auto res_copy_backward = - copy_backward(next(source.begin(), 9), next(source.begin(), length + 8), dest_backward.end()); + const auto res_copy_backward = copy_backward( + next(source.begin(), 9), source.begin() + static_cast(length) + 8, dest_backward.end()); assert(dest_backward == result); assert(res_copy_backward == next(dest_backward.begin())); } { vector dest_move(length, false); - const auto res_move = move(next(source.begin(), 9), next(source.begin(), length + 8), next(dest_move.begin())); + const auto res_move = + move(next(source.begin(), 9), source.begin() + static_cast(length) + 8, next(dest_move.begin())); assert(dest_move == result); assert(res_move == dest_move.end()); } { vector dest_move_backward(length, false); - const auto res_move_backward = - move_backward(next(source.begin(), 9), next(source.begin(), length + 8), dest_move_backward.end()); + const auto res_move_backward = move_backward( + next(source.begin(), 9), source.begin() + static_cast(length) + 8, dest_move_backward.end()); assert(dest_move_backward == result); assert(res_move_backward == next(dest_move_backward.begin())); } @@ -1389,8 +1403,8 @@ void randomized_test_copy(mt19937_64& gen) { // src vector: // dst vector: - vector vb_src(src_prefix + copy_len + src_suffix); - vector vb_dst(dst_prefix + copy_len + dst_suffix); + vector vb_src(static_cast(src_prefix + copy_len + src_suffix)); + vector vb_dst(static_cast(dst_prefix + copy_len + dst_suffix)); generate(vb_src.begin(), vb_src.end(), bool_dist); generate(vb_dst.begin(), vb_dst.end(), bool_dist); @@ -1435,7 +1449,7 @@ void randomized_test_copy(mt19937_64& gen) { // ^ // - vector vb(prefix + overhang + copy_len + suffix); + vector vb(static_cast(prefix + overhang + copy_len + suffix)); generate(vb.begin(), vb.end(), bool_dist); @@ -1473,7 +1487,7 @@ void randomized_test_copy(mt19937_64& gen) { // Vector diagram: // - vector vb(prefix + copy_len + gap + copy_len + suffix); + vector vb(static_cast(prefix + copy_len + gap + copy_len + suffix)); generate(vb.begin(), vb.end(), bool_dist); diff --git a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp index 1102e74009b..62e1a6ed6db 100644 --- a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp +++ b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp @@ -69,12 +69,18 @@ struct copy_counter { int count = 0; }; -using fn_type = int(copy_counter); +using fn_type = int(copy_counter); +using fn_type_r = int(copy_counter) &; +using fn_type_c = int(copy_counter) const; + +#ifdef __cpp_noexcept_function_type +using fn_type_nx = int(copy_counter) noexcept; +#endif // defined(__cpp_noexcept_function_type) struct small_callable { const int context = 42; - int operator()(const copy_counter& counter) { + int operator()(const copy_counter& counter) const noexcept { assert(context == 42); return counter.count; } @@ -83,7 +89,7 @@ struct small_callable { struct alignas(128) large_callable { const int context = 1729; - int operator()(const copy_counter& counter) { + int operator()(const copy_counter& counter) const noexcept { assert((reinterpret_cast(this) & 0x7f) == 0); assert(context == 1729); return counter.count; @@ -156,6 +162,22 @@ int main() { alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0); alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); + // Abominables and noexcept specifier + alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); + alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); + + static_assert(!is_constructible_v, move_only_function>); + static_assert(!is_constructible_v, move_only_function>); + +#ifdef __cpp_noexcept_function_type + alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); + + static_assert(!is_constructible_v, move_only_function>); +#endif // defined(__cpp_noexcept_function_type) + constexpr bool is_64_bit = sizeof(void*) > 4; // Moves from function to move_only_function @@ -163,6 +185,18 @@ int main() { test_wrapped_call, function, small_callable>(0); alloc_checker{1}, test_wrapped_call, function, large_callable>(0); + // Moves from function to abominable move_only_function + alloc_checker{is_64_bit ? 0 : 1}, + test_wrapped_call, function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, function, large_callable>(0); + alloc_checker{is_64_bit ? 0 : 1}, + test_wrapped_call, function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, function, large_callable>(0); + +#ifdef __cpp_noexcept_function_type + static_assert(!is_constructible_v, function>); +#endif // defined(__cpp_noexcept_function_type) + alloc_checker{is_64_bit ? 0 : 1}, test_wrapped_copy_call, function, small_callable>(0); alloc_checker{2}, test_wrapped_copy_call, function, large_callable>(0); diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/__init__.py b/tests/std/tests/GH_005968_headers_provide_begin_end/__init__.py new file mode 100644 index 00000000000..2ac2a854cb0 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/custom_format.py b/tests/std/tests/GH_005968_headers_provide_begin_end/custom_format.py new file mode 100644 index 00000000000..2d698f717b2 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/custom_format.py @@ -0,0 +1,27 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import os + +from stl.test.format import STLTestFormat, TestStep +from stl.test.tests import TestType + + +class CustomTestFormat(STLTestFormat): + def getBuildSteps(self, test, litConfig, shared): + exeSourceDir = os.path.dirname(test.getSourcePath()) + _, outputBase = test.getTempPaths() + + sourceFiles = [] + for filename in os.listdir(exeSourceDir): + if filename.endswith('.cpp'): + sourceFiles.append(os.path.join(exeSourceDir, filename)) + + if TestType.COMPILE in test.testType: + cmd = [test.cxx, '/c', *sourceFiles, *test.flags, *test.compileFlags] + elif TestType.RUN in test.testType: + shared.execFile = outputBase + '.exe' + cmd = [test.cxx, *sourceFiles, *test.flags, *test.compileFlags, '/Fe' + shared.execFile, + '/link', *test.linkFlags] + + yield TestStep(cmd, shared.execDir, shared.env, False) diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/env.lst b/tests/std/tests/GH_005968_headers_provide_begin_end/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/lit.local.cfg b/tests/std/tests/GH_005968_headers_provide_begin_end/lit.local.cfg new file mode 100644 index 00000000000..a2eb46b33dc --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/lit.local.cfg @@ -0,0 +1,9 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import os +import site +site.addsitedir(os.path.dirname(os.path.dirname(__file__))) +import GH_005968_headers_provide_begin_end.custom_format + +config.test_format = GH_005968_headers_provide_begin_end.custom_format.CustomTestFormat() diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/shared_test.hpp b/tests/std/tests/GH_005968_headers_provide_begin_end/shared_test.hpp new file mode 100644 index 00000000000..0937ddb1d26 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/shared_test.hpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +// Intentionally avoid including anything. Order assumption: shared_test.hpp assumes +// that the relevant Standard headers have already been included by the .cpp files. + +// Test requirements of N5032 [iterator.range]/1. + +namespace detail { + + // file test_iterator.cpp uses a non-std container and thus we can't rely on ADL to find begin/end etc. + using namespace std; + + // Define minimal metaprogramming tools, avoid including anything + +#define DEFINE_CONDITIONAL_CALLER_OF_FREE_MEMBER(free_name, member_name) \ + template \ + struct conditional_caller_of_##free_name { \ + constexpr void operator()(T&) {} \ + }; \ + \ + template \ + struct conditional_caller_of_##free_name(nullptr)->member_name())> { \ + constexpr auto operator()(T& t) { \ + return free_name(t); \ + } \ + }; + +#define DEFINE_CONDITIONAL_CALLER_OF(name) DEFINE_CONDITIONAL_CALLER_OF_FREE_MEMBER(name, name) + +#define CONDITIONALLY_CALL(c, name) conditional_caller_of_##name{}(c) + + DEFINE_CONDITIONAL_CALLER_OF(rbegin); + DEFINE_CONDITIONAL_CALLER_OF(rend); + DEFINE_CONDITIONAL_CALLER_OF(crbegin); + DEFINE_CONDITIONAL_CALLER_OF(crend); + DEFINE_CONDITIONAL_CALLER_OF(size); +#if _HAS_CXX20 + DEFINE_CONDITIONAL_CALLER_OF_FREE_MEMBER(ssize, size); // N5032 [iterator.range]/18 +#endif + DEFINE_CONDITIONAL_CALLER_OF(empty); + DEFINE_CONDITIONAL_CALLER_OF(data); + + template + void test_free_container_functions(C& c) { + (void) begin(c); + (void) end(c); + (void) cbegin(c); + (void) cend(c); + CONDITIONALLY_CALL(c, rbegin); // missing e.g. for forward_list + CONDITIONALLY_CALL(c, rend); // missing e.g. for forward_list + CONDITIONALLY_CALL(c, crbegin); // missing e.g. for forward_list + CONDITIONALLY_CALL(c, crend); // missing e.g. for forward_list + CONDITIONALLY_CALL(c, size); // missing e.g. for optional +#if _HAS_CXX20 + CONDITIONALLY_CALL(c, ssize); // missing e.g. for optional +#endif + CONDITIONALLY_CALL(c, empty); // missing e.g. for valarray + CONDITIONALLY_CALL(c, data); // missing e.g. for valarray + } + + inline void test_free_array_functions() { + int a[]{1, 2, 3}; + + (void) begin(a); + (void) end(a); + (void) cbegin(a); + (void) cend(a); + (void) rbegin(a); + (void) rend(a); + (void) crbegin(a); + (void) crend(a); + (void) size(a); +#if _HAS_CXX20 + (void) ssize(a); +#endif + (void) empty(a); + (void) data(a); + } +} // namespace detail + +template +void shared_test(C& c) { + detail::test_free_container_functions(c); + // as_const from not required to be available + detail::test_free_container_functions(const_cast(c)); + + detail::test_free_array_functions(); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test.cpp new file mode 100644 index 00000000000..96e52373adc --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test.cpp @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +void test_array(); +void test_deque(); +void test_flat_map(); +void test_flat_set(); +void test_forward_list(); +void test_hive(); +void test_inplace_vector(); +void test_iterator(); +void test_list(); +void test_map(); +void test_optional(); +void test_regex(); +void test_set(); +void test_span(); +void test_stacktrace(); +void test_string(); +void test_string_view(); +void test_unordered_map(); +void test_unordered_set(); +void test_valarray(); +void test_vector(); + +int main() { + test_array(); + test_deque(); + test_flat_map(); + test_flat_set(); + test_forward_list(); + test_hive(); + test_inplace_vector(); + test_iterator(); + test_list(); + test_map(); + test_optional(); + test_regex(); + test_set(); + test_span(); + test_stacktrace(); + test_string(); + test_string_view(); + test_unordered_map(); + test_unordered_set(); + test_valarray(); + test_vector(); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_array.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_array.cpp new file mode 100644 index 00000000000..f2422e0efa8 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_array.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_array() { + std::array container{1, 2, 3}; + shared_test(container); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_deque.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_deque.cpp new file mode 100644 index 00000000000..3cb47d630d6 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_deque.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_deque() { + std::deque container{1, 2, 3}; + shared_test(container); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_map.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_map.cpp new file mode 100644 index 00000000000..16dafe71849 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_map.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if _HAS_CXX23 + +#include + +#include "shared_test.hpp" + +void test_flat_map() { + { + std::flat_map container{ + {1, 5}, + {3, 7}, + }; + shared_test(container); + } + + { + std::flat_multimap container2{ + {1, 5}, + {3, 7}, + }; + shared_test(container2); + } +} + +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv + +void test_flat_map() {} + +#endif // ^^^ !_HAS_CXX23 ^^^ diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_set.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_set.cpp new file mode 100644 index 00000000000..d995b42124a --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_flat_set.cpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if _HAS_CXX23 + +#include + +#include "shared_test.hpp" + +void test_flat_set() { + { + std::flat_set container{1, 2, 3}; + shared_test(container); + } + + { + std::flat_multiset container2{1, 2, 3}; + shared_test(container2); + } +} + +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv + +void test_flat_set() {} + +#endif // ^^^ !_HAS_CXX23 ^^^ diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_forward_list.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_forward_list.cpp new file mode 100644 index 00000000000..85421feb199 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_forward_list.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_forward_list() { + std::forward_list container{1, 2, 3}; + shared_test(container); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_hive.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_hive.cpp new file mode 100644 index 00000000000..3ef1701b4ef --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_hive.cpp @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if defined(__cpp_lib_hive) +static_assert(false, "When this feature is implemented, update this to a Standard mode check."); + +#include + +#include "shared_test.hpp" + +void test_hive() { + std::hive container{1, 2, 3}; + shared_test(container); +} + +#else // ^^^ defined(__cpp_lib_hive) / !defined(__cpp_lib_hive) vvv + +void test_hive() {} + +#endif // ^^^ !defined(__cpp_lib_hive) ^^^ diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_inplace_vector.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_inplace_vector.cpp new file mode 100644 index 00000000000..990486a72ac --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_inplace_vector.cpp @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if defined(__cpp_lib_inplace_vector) +static_assert(false, "When this feature is implemented, update this to a Standard mode check."); + +#include + +#include "shared_test.hpp" + +void test_inplace_vector() { + std::inplace_vector container{1, 2, 3}; + shared_test(container); +} + +#else // ^^^ defined(__cpp_lib_inplace_vector) / !defined(__cpp_lib_inplace_vector) vvv + +void test_inplace_vector() {} + +#endif // ^^^ !defined(__cpp_lib_inplace_vector) ^^^ diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_iterator.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_iterator.cpp new file mode 100644 index 00000000000..eaa4910839c --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_iterator.cpp @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +struct minimal_container { + static constexpr size_t magic_value = 3376942; + + constexpr void begin() const {} + constexpr void end() const {} + constexpr void cbegin() const {} + constexpr void cend() const {} + constexpr void rbegin() const {} + constexpr void rend() const {} + constexpr void crbegin() const {} + constexpr void crend() const {} + constexpr size_t size() const { + return magic_value; + } + constexpr void empty() const {} + constexpr void data() const {} +}; + + +// Self-test the template machinery to check it properly detects member functions +namespace detail { + template + constexpr bool minimal_container_test(C& c) { + // when the CONDITIONALLY_CALL expression fails to detect the member, it has type void, i.e. clearly + // incompatible with operator==. If the detection mechanism did not work properly, this would fail to compile. + return CONDITIONALLY_CALL(c, size) == minimal_container::magic_value; + } + + constexpr minimal_container min_cont; + static_assert(minimal_container_test(min_cont), "The member detection utility is broken"); +} // namespace detail + +void test_iterator() { + minimal_container container; + + shared_test(container); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_list.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_list.cpp new file mode 100644 index 00000000000..265e676721b --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_list.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_list() { + std::list container{1, 2, 3}; + shared_test(container); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_map.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_map.cpp new file mode 100644 index 00000000000..2b3c7ce636c --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_map.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_map() { + { + std::map container{{1, 2}, {3, 4}}; + shared_test(container); + } + + { + std::multimap container2{{5, 2}, {6, 4}}; + shared_test(container2); + } +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_optional.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_optional.cpp new file mode 100644 index 00000000000..afcaeac5cd9 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_optional.cpp @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if defined(__cpp_lib_optional_range_support) +static_assert(false, "When this feature is implemented, update this to a Standard mode check."); + +#include + +#include "shared_test.hpp" + +void test_optional() { + std::optional container{1}; + shared_test(container); +} + +#else // ^^^ defined(__cpp_lib_optional_range_support) / !defined(__cpp_lib_optional_range_support) vvv + +void test_optional() {} + +#endif // ^^^ !defined(__cpp_lib_optional_range_support) ^^^ diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_regex.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_regex.cpp new file mode 100644 index 00000000000..27f688c0726 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_regex.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_regex() { + std::smatch container; + shared_test(container); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_set.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_set.cpp new file mode 100644 index 00000000000..7f92da62da0 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_set.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_set() { + { + std::set container{1, 2, 3}; + shared_test(container); + } + + { + std::multiset container2{1, 2, 3}; + shared_test(container2); + } +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_span.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_span.cpp new file mode 100644 index 00000000000..6487b673a63 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_span.cpp @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if _HAS_CXX20 + +#include + +#include "shared_test.hpp" + +void test_span() { + int arr[]{1, 2, 3}; + std::span container(arr); + shared_test(container); +} + +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv + +void test_span() {} + +#endif // ^^^ !_HAS_CXX20 ^^^ diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_stacktrace.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_stacktrace.cpp new file mode 100644 index 00000000000..dab992410ba --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_stacktrace.cpp @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if _HAS_CXX23 + +#include + +#include "shared_test.hpp" + +void test_stacktrace() { + std::stacktrace container; + shared_test(container); +} + +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv + +void test_stacktrace() {} + +#endif // ^^^ !_HAS_CXX23 ^^^ diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_string.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_string.cpp new file mode 100644 index 00000000000..2957f1ecf71 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_string.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_string() { + std::string container = "hello"; + shared_test(container); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_string_view.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_string_view.cpp new file mode 100644 index 00000000000..5f16e21f046 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_string_view.cpp @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#if _HAS_CXX17 + +#include + +#include "shared_test.hpp" + +void test_string_view() { + std::string_view container = "hello"; + shared_test(container); +} +#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv + +void test_string_view() {} + +#endif // ^^^ !_HAS_CXX17 ^^^ diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_unordered_map.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_unordered_map.cpp new file mode 100644 index 00000000000..a800671ae5d --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_unordered_map.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_unordered_map() { + { + std::unordered_map container{{1, 2}, {3, 4}}; + shared_test(container); + } + + { + std::unordered_multimap container2{{5, 2}, {6, 4}}; + shared_test(container2); + } +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_unordered_set.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_unordered_set.cpp new file mode 100644 index 00000000000..478c4cf0918 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_unordered_set.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_unordered_set() { + { + std::unordered_set container{1, 2, 3}; + shared_test(container); + } + + { + std::unordered_multiset container2{4, 5, 6}; + shared_test(container2); + } +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_valarray.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_valarray.cpp new file mode 100644 index 00000000000..0fef8a143b4 --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_valarray.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_valarray() { + std::valarray container{1, 2, 3}; + shared_test(container); +} diff --git a/tests/std/tests/GH_005968_headers_provide_begin_end/test_vector.cpp b/tests/std/tests/GH_005968_headers_provide_begin_end/test_vector.cpp new file mode 100644 index 00000000000..942dcef972b --- /dev/null +++ b/tests/std/tests/GH_005968_headers_provide_begin_end/test_vector.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "shared_test.hpp" + +void test_vector() { + std::vector container{1, 2, 3}; + shared_test(container); +} diff --git a/tests/std/tests/VSO_0000000_regex_use/test.cpp b/tests/std/tests/VSO_0000000_regex_use/test.cpp index cce150a1f88..e33d1d2165b 100644 --- a/tests/std/tests/VSO_0000000_regex_use/test.cpp +++ b/tests/std/tests/VSO_0000000_regex_use/test.cpp @@ -2408,6 +2408,37 @@ void test_gh_5944() { } } +void test_gh_6022() { + // GH-6022: Optimize matching of branchless loops + g_regexTester.should_match("acddabb", R"((?:([ac])*d)*ab\1b)"); + g_regexTester.should_match("acdaadabab", R"((?:([ac])*d)*ab\1b)"); + g_regexTester.should_match("acddabcb", R"((?:([ac])*d)*dab\1b)"); + + g_regexTester.should_match("addabb", R"((?:(a){0,1}d)*ab\1b)"); + g_regexTester.should_match("adadabab", R"((?:(a){0,1}d)*ab\1b)"); + g_regexTester.should_match("adadabb", R"((?:(a){0,1}d)*adadab\1b)"); + g_regexTester.should_not_match("adaddabab", R"((?:(a){0,1}d)*ab\1b)"); + g_regexTester.should_not_match("dabb", R"((?:(a){1,1}d)+ab\1b)"); + g_regexTester.should_not_match("addabb", R"((?:(a){1,2}d)+ab\1b)"); + g_regexTester.should_not_match("adaadabb", R"((?:(a){1,2}d)+ab\1b)"); + + g_regexTester.should_match("bacabcdacdabbaddabbcdcdbc", R"((?:(?:([abc])([abc]))*d)+cd\1\2)"); + g_regexTester.should_not_match("bacabcdacdabbaddabbcdcdab", R"((?:(?:([abc])([abc]))*d)+dcd\1\2)"); + g_regexTester.should_not_match("bacabcdacdabbaddabbcdcdab", R"((?:(?:([abc])([abc]))*d)+bcdcd\1\2)"); + g_regexTester.should_match("bacabcdacdabbaddabbcdcd", R"((?:(?:([abc])([abc]))*d)*abbcdcd\1\2)"); + g_regexTester.should_match("bacabcdacdabbaddabbcdcdba", R"((?:(?:([abc])([abc]))*d)*dabbcdcd\1\2)"); + g_regexTester.should_not_match("bacabcdacdabbaddabbcdcdba", R"((?:(?:([abc])([abc]))*d)+ddabbcdcd\1\2)"); + g_regexTester.should_not_match("bacabcdacdabbaddabbcdcdab", R"((?:(?:([abc])([abc]))*d)+baddabbcdcd\1\2)"); + g_regexTester.should_match("bacabcdacdabbaddabbcdcdac", R"((?:(?:([abc])([abc]))*d)*abbaddabbcdcd\1\2)"); + g_regexTester.should_not_match("bacabcdacdabbaddabbcdcdac", R"((?:(?:([abc])([abc]))*d)*dabbaddabcdcd\1\2)"); + g_regexTester.should_match("bacabcdacdabbaddabbcdcdbc", R"((?:(?:([abc])([abc]))*d)*acdabbaddabbcdcd\1\2)"); + g_regexTester.should_not_match("bacabcdacdabbaddabbcdcdbc", R"((?:(?:([abc])([abc]))*d)*dacdabbaddabbcdcd\1\2)"); + g_regexTester.should_not_match("bacabcdacdabbaddabbcdcdca", R"((?:(?:([abc])([abc]))*d)*bcdacdabbaddabbcdcd\1\2)"); + g_regexTester.should_not_match( + "bacabcdacdabbaddabbcdcdba", R"((?:(?:([abc])([abc]))*d)*cabcdacdabbaddabbcdcd\1\2)"); + g_regexTester.should_match("bacabcdacdabbaddabbcdcd", R"((?:(?:([abc])([abc]))*d)*bacabcdacdabbaddabbcdcd\1\2)"); +} + int main() { test_dev10_449367_case_insensitivity_should_work(); test_dev11_462743_regex_collate_should_not_disable_regex_icase(); @@ -2469,6 +2500,7 @@ int main() { test_gh_5918(); test_gh_5939(); test_gh_5944(); + test_gh_6022(); return g_regexTester.result(); } diff --git a/tools/scripts/move_only_function_specializations.py b/tools/scripts/move_only_function_specializations.py index ad49c62e49c..122b2c14d9e 100644 --- a/tools/scripts/move_only_function_specializations.py +++ b/tools/scripts/move_only_function_specializations.py @@ -6,7 +6,7 @@ def specialization(self: str, cv: str, ref: str, ref_inv: str, noex: str, noex_val: str, callable: str) -> str: return f"""template class _Function_call<_Rx(_Types...) {cv} {ref} {noex}> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, {noex_val}, _Types...> {{ + : public _Function_base<_Rx, _Types...> {{ public: template using _VtInvQuals = {cv} _Vt {ref_inv}; @@ -14,8 +14,10 @@ class _Function_call<_Rx(_Types...) {cv} {ref} {noex}> // Generated code - DO NO template static constexpr bool _Is_callable_from = {callable}; + static constexpr bool _Noexcept = {noex_val}; + _Rx operator()(_Types... _Args) {cv} {ref} {noex} {{ - return this->_Get_invoke()({self}, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()({self}, _STD forward<_Types>(_Args)...); }} }}; """