diff --git a/azure-devops/create-vmss.ps1 b/azure-devops/create-vmss.ps1 index 9f47f3825e9..e476dd02f66 100644 --- a/azure-devops/create-vmss.ps1 +++ b/azure-devops/create-vmss.ps1 @@ -17,7 +17,7 @@ or are running from Azure Cloud Shell. $Location = 'westus2' $Prefix = 'StlBuild-' + (Get-Date -Format 'yyyy-MM-dd') -$VMSize = 'Standard_F16s_v2' +$VMSize = 'Standard_D16as_v4' $ProtoVMName = 'PROTOTYPE' $LiveVMPrefix = 'BUILD' $WindowsServerSku = '2019-Datacenter' diff --git a/azure-devops/provision-image.ps1 b/azure-devops/provision-image.ps1 index a207f10e8e4..010233d008b 100644 --- a/azure-devops/provision-image.ps1 +++ b/azure-devops/provision-image.ps1 @@ -296,7 +296,6 @@ Add-MpPreference -ExclusionProcess clang-cl.exe Add-MpPreference -ExclusionProcess cl.exe Add-MpPreference -ExclusionProcess link.exe Add-MpPreference -ExclusionProcess python.exe -Add-MpPreference -ExclusionProcess test.exe InstallPython $PythonUrl InstallVisualStudio -Workloads $Workloads -BootstrapperUrl $VisualStudioBootstrapperUrl diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ea1b680c6e3..b9fa7b9da98 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -4,7 +4,7 @@ # Build STL targeting x86, x64, arm, arm64 variables: - agentPool: 'StlBuild-2020-08-07' + agentPool: 'StlBuild-2020-08-11' tmpDir: 'D:\Temp' stages: diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 6a2069bae7f..3314aab65d3 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -405,6 +405,11 @@ set(STATIC_SOURCES ${SOURCES_SATELLITE_CODECVT_IDS} ) +# Objs that exist in all satellite DLLs +set(SATELLITE_DLL_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/src/dllmain_satellite.cpp + ) + add_library(std_init_once_begin_initialize OBJECT IMPORTED) add_library(std_init_once_complete OBJECT IMPORTED) set_target_properties(std_init_once_begin_initialize PROPERTIES IMPORTED_OBJECTS "${CMAKE_CURRENT_LIST_DIR}/aliases/${VCLIBS_I386_OR_AMD64}/std_init_once_begin_initialize.obj") @@ -440,13 +445,17 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_definitions(msvcp${D_SUFFIX}_implib_objects PRIVATE "_DLL;${THIS_CONFIG_DEFINITIONS}") target_compile_options(msvcp${D_SUFFIX}_implib_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};/EHsc") # No /GL! + add_library(msvcp${D_SUFFIX}_satellite_objects OBJECT ${SATELLITE_DLL_SOURCES}) + target_compile_options(msvcp${D_SUFFIX}_satellite_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") + target_compile_definitions(msvcp${D_SUFFIX}_satellite_objects PRIVATE "_DLL;${THIS_CONFIG_DEFINITIONS}") + # msvcp140_1.dll (the memory_resource satellite) add_library(msvcp_1${D_SUFFIX}_objects OBJECT ${SOURCES_SATELLITE_1}) target_compile_definitions(msvcp_1${D_SUFFIX}_objects PRIVATE "_BUILDING_SATELLITE_1;_DLL;${THIS_CONFIG_DEFINITIONS}") target_compile_options(msvcp_1${D_SUFFIX}_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp_1${D_SUFFIX} SHARED) - target_link_libraries(msvcp_1${D_SUFFIX} PRIVATE msvcp_1${D_SUFFIX}_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp_1${D_SUFFIX} PRIVATE msvcp_1${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -459,7 +468,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_link_libraries(msvcp_2${D_SUFFIX}_objects PRIVATE Boost::headers Boost::disable_autolinking) add_library(msvcp_2${D_SUFFIX} SHARED) - target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_implib_objects std_init_once_begin_initialize std_init_once_complete "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects std_init_once_begin_initialize std_init_once_complete "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") @@ -481,7 +490,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO file(WRITE "${_ATOMIC_WAIT_DEF_NAME}" "${_ATOMIC_WAIT_DEF_CONTENTS}") add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${_ATOMIC_WAIT_DEF_NAME}") - target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "${_ATOMIC_WAIT_OUTPUT_NAME}") @@ -493,7 +502,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") add_library(msvcp${D_SUFFIX}_codecvt_ids SHARED) - target_link_libraries(msvcp${D_SUFFIX}_codecvt_ids PRIVATE msvcp${D_SUFFIX}_codecvt_ids_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp${D_SUFFIX}_codecvt_ids PRIVATE msvcp${D_SUFFIX}_codecvt_ids_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_codecvt_ids${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_codecvt_ids${VCLIBS_SUFFIX}") diff --git a/stl/inc/algorithm b/stl/inc/algorithm index f684affcc07..6b1e1d99d07 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -94,10 +94,6 @@ struct _Optimistic_temporary_buffer { // temporary storage with _alloca-like att #ifdef __cpp_lib_concepts namespace ranges { - // CONCEPT _Convertible_from - template - concept _Convertible_from = convertible_to<_From, _To>; - #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-attributes" @@ -137,23 +133,6 @@ namespace ranges { } }; - // STRUCT TEMPLATE in_out_result - template - struct in_out_result { - [[no_unique_address]] _In in; - [[no_unique_address]] _Out out; - - template <_Convertible_from _IIn, _Convertible_from _OOut> - constexpr operator in_out_result<_IIn, _OOut>() const& { - return {in, out}; - } - - template <_Convertible_from<_In> _IIn, _Convertible_from<_Out> _OOut> - constexpr operator in_out_result<_IIn, _OOut>() && { - return {_STD move(in), _STD move(out)}; - } - }; - // STRUCT TEMPLATE in_in_out_result template struct in_in_out_result { @@ -1925,7 +1904,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); auto _ULast = _Get_final_iterator_unwrapped<_It1>(_UFirst, _STD move(_Last)); _Seek_wrapped(_First, _ULast); - _Result = _RANGES _Move_backward_common(_STD move(_UFirst), _STD move(_ULast), _STD move(_Result)); + _Result = _Move_backward_common(_STD move(_UFirst), _STD move(_ULast), _STD move(_Result)); return {_STD move(_First), _STD move(_Result)}; } @@ -1933,7 +1912,7 @@ namespace ranges { requires indirectly_movable, _It> constexpr move_backward_result, _It> operator()(_Rng&& _Range, _It _Result) const { auto _ULast = _Get_final_iterator_unwrapped(_Range); - _Result = _RANGES _Move_backward_common(_Ubegin(_Range), _ULast, _STD move(_Result)); + _Result = _Move_backward_common(_Ubegin(_Range), _ULast, _STD move(_Result)); return {_Rewrap_iterator(_Range, _STD move(_ULast)), _STD move(_Result)}; } // clang-format on @@ -6402,7 +6381,7 @@ namespace ranges { // FUNCTION TEMPLATE make_heap template _CONSTEXPR20 void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { - // make nontrivial [_First, _Last) into a heap + // make [_First, _Last) into a heap using _Diff = _Iter_diff_t<_RanIt>; _Diff _Bottom = _Last - _First; for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen @@ -6431,8 +6410,8 @@ namespace ranges { template requires sortable<_It, _Pr, _Pj> constexpr void _Make_heap_common(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) { - // make nontrivial [_First, _Last) into a heap with respect to _Pred and _Proj // clang-format on + // make [_First, _Last) into a heap with respect to _Pred and _Proj using _Diff = iter_difference_t<_It>; const _Diff _Bottom = _Last - _First; for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen @@ -6452,6 +6431,7 @@ namespace ranges { template _Se, class _Pr = ranges::less, class _Pj = identity> requires sortable<_It, _Pr, _Pj> constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_STD move(_First)); auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last)); @@ -6460,9 +6440,11 @@ namespace ranges { return _First; } + // clang-format off template requires sortable, _Pr, _Pj> constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on if constexpr (common_range<_Rng>) { _Make_heap_common(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); return _RANGES end(_Range); @@ -6472,7 +6454,6 @@ namespace ranges { return _Rewrap_iterator(_Range, _STD move(_ULast)); } } - // clang-format on }; inline constexpr _Make_heap_fn make_heap{_Not_quite_object::_Construct_tag{}}; @@ -6665,8 +6646,8 @@ namespace ranges { template requires sortable<_It, _Pr, _Pj> constexpr void _Sort_heap_common(const _It _First, _It _Last, _Pr _Pred, _Pj _Proj) { - // order heap by repeatedly popping // clang-format on + // order heap by repeatedly popping for (; _Last - _First >= 2; --_Last) { _RANGES _Pop_heap_unchecked(_First, _Last, _Pred, _Proj); } @@ -6680,6 +6661,7 @@ namespace ranges { template _Se, class _Pr = ranges::less, class _Pj = identity> requires sortable<_It, _Pr, _Pj> constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_STD move(_First)); auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last)); @@ -6688,9 +6670,11 @@ namespace ranges { return _First; } + // clang-format off template requires sortable, _Pr, _Pj> constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on if constexpr (common_range<_Rng>) { _Sort_heap_common(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); return _RANGES end(_Range); @@ -6700,7 +6684,6 @@ namespace ranges { return _Rewrap_iterator(_Range, _STD move(_ULast)); } } - // clang-format on }; inline constexpr _Sort_heap_fn sort_heap{_Not_quite_object::_Construct_tag{}}; @@ -7628,6 +7611,7 @@ void sort(_ExPo&& _Exec, const _RanIt _First, const _RanIt _Last) noexcept /* te // order [_First, _Last) _STD sort(_STD forward<_ExPo>(_Exec), _First, _Last, less{}); } +#endif // _HAS_CXX17 #ifdef __cpp_lib_concepts namespace ranges { @@ -7635,6 +7619,7 @@ namespace ranges { template requires sortable<_It, _Pr, _Pj> constexpr void _Insertion_sort_common(const _It _First, const _It _Last, _Pr _Pred, _Pj _Proj) { + // clang-format on // insertion sort [_First, _Last) if (_First == _Last) { // empty range is sorted @@ -7643,7 +7628,7 @@ namespace ranges { for (auto _Mid = _First; ++_Mid != _Last;) { // order next element iter_value_t<_It> _Val = _RANGES iter_move(_Mid); - auto _Hole = _Mid; + auto _Hole = _Mid; for (auto _Prev = _Hole;;) { --_Prev; @@ -7660,9 +7645,11 @@ namespace ranges { } } + // clang-format off template requires sortable<_It, _Pr, _Pj> - constexpr void _Med3_unchecked(_It _First, _It _Mid, _It _Last, _Pr _Pred, _Pj _Proj) { + constexpr void _Med3_common(_It _First, _It _Mid, _It _Last, _Pr _Pred, _Pj _Proj) { + // clang-format on // sort median of three elements to middle if (_STD invoke(_Pred, _STD invoke(_Proj, *_Mid), _STD invoke(_Proj, *_First))) { _RANGES iter_swap(_Mid, _First); @@ -7680,33 +7667,37 @@ namespace ranges { } } + // clang-format off template requires sortable<_It, _Pr, _Pj> - constexpr void _Guess_median_unchecked(_It _First, _It _Mid, _It _Last, _Pr _Pred, _Pj _Proj) { + constexpr void _Guess_median_common(_It _First, _It _Mid, _It _Last, _Pr _Pred, _Pj _Proj) { + // clang-format on // sort median element to middle using _Diff = iter_difference_t<_It>; const _Diff _Count = _Last - _First; if (_Count > 40) { // Tukey's ninther const _Diff _Step = (_Count + 1) >> 3; // +1 can't overflow because range was made inclusive in caller const _Diff _Two_step = _Step << 1; // note: intentionally discards low-order bit - _Med3_unchecked(_First, _First + _Step, _First + _Two_step, _Pred, _Proj); - _Med3_unchecked(_Mid - _Step, _Mid, _Mid + _Step, _Pred, _Proj); - _Med3_unchecked(_Last - _Two_step, _Last - _Step, _Last, _Pred, _Proj); - _Med3_unchecked(_First + _Step, _Mid, _Last - _Step, _Pred, _Proj); + _Med3_common(_First, _First + _Step, _First + _Two_step, _Pred, _Proj); + _Med3_common(_Mid - _Step, _Mid, _Mid + _Step, _Pred, _Proj); + _Med3_common(_Last - _Two_step, _Last - _Step, _Last, _Pred, _Proj); + _Med3_common(_First + _Step, _Mid, _Last - _Step, _Pred, _Proj); } else { - _Med3_unchecked(_First, _Mid, _Last, _Pred, _Proj); + _Med3_common(_First, _Mid, _Last, _Pred, _Proj); } } + // clang-format off template requires sortable<_It, _Pr, _Pj> - _NODISCARD constexpr subrange<_It> _Partition_by_median_guess_unchecked( + _NODISCARD constexpr subrange<_It> _Partition_by_median_guess_common( _It _First, _It _Last, _Pr _Pred, _Pj _Proj) { + // clang-format on // Choose a pivot, partition [_First, _Last) into elements less than pivot, elements equal to pivot, and // elements greater than pivot; return the equal partition as a subrange. _It _Mid = _First + ((_Last - _First) >> 1); // shift for codegen - _RANGES _Guess_median_unchecked(_First, _Mid, _RANGES prev(_Last), _Pred, _Proj); + _Guess_median_common(_First, _Mid, _RANGES prev(_Last), _Pred, _Proj); _It _Pfirst = _Mid; _It _Plast = _RANGES next(_Pfirst); @@ -7716,8 +7707,7 @@ namespace ranges { --_Pfirst; } - while (_Plast < _Last - && !_STD invoke(_Pred, _STD invoke(_Proj, *_Plast), _STD invoke(_Proj, *_Pfirst)) + while (_Plast < _Last && !_STD invoke(_Pred, _STD invoke(_Proj, *_Plast), _STD invoke(_Proj, *_Pfirst)) && !_STD invoke(_Pred, _STD invoke(_Proj, *_Pfirst), _STD invoke(_Proj, *_Plast))) { ++_Plast; } @@ -7775,10 +7765,76 @@ namespace ranges { } } } - // clang-format on + + // VARIABLE ranges::sort + class _Sort_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, class _Pr = ranges::less, class _Pj = identity> + requires sortable<_It, _Pr, _Pj> + constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on + _Adl_verify_range(_First, _Last); + auto _UFirst = _Get_unwrapped(_STD move(_First)); + auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last)); + _Seek_wrapped(_First, _ULast); + const auto _Count = _ULast - _UFirst; + _Sort_common(_STD move(_UFirst), _STD move(_ULast), _Count, _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _First; + } + + // clang-format off + template + requires sortable, _Pr, _Pj> + constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on + auto _UFirst = _Ubegin(_Range); + auto _ULast = _Get_final_iterator_unwrapped(_Range); + const auto _Count = _ULast - _UFirst; + _Sort_common(_STD move(_UFirst), _ULast, _Count, _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _Rewrap_iterator(_Range, _STD move(_ULast)); + } + + private: + template + static constexpr void _Sort_common(_It _First, _It _Last, iter_difference_t<_It> _Ideal, _Pr _Pred, _Pj _Proj) { + // sort [_First, _Last) with respect to _Pred and _Proj + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); + + for (;;) { + if (_Last - _First <= _ISORT_MAX) { // small + _Insertion_sort_common(_STD move(_First), _STD move(_Last), _Pred, _Proj); + return; + } + + if (_Ideal <= 0) { // heap sort if too many divisions + _Make_heap_common(_First, _Last, _Pred, _Proj); + _Sort_heap_common(_STD move(_First), _STD move(_Last), _Pred, _Proj); + return; + } + + // divide and conquer by quicksort + auto [_Mid_first, _Mid_last] = _Partition_by_median_guess_common(_First, _Last, _Pred, _Proj); + + _Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions + + if (_Mid_first - _First < _Last - _Mid_last) { // loop on second half + _Sort_common(_First, _STD move(_Mid_first), _Ideal, _Pred, _Proj); + _First = _STD move(_Mid_last); + } else { // loop on first half + _Sort_common(_STD move(_Mid_last), _Last, _Ideal, _Pred, _Proj); + _Last = _STD move(_Mid_first); + } + } + } + }; + + inline constexpr _Sort_fn sort{_Not_quite_object::_Construct_tag{}}; } // namespace ranges #endif // __cpp_lib_concepts -#endif // _HAS_CXX17 // FUNCTION TEMPLATE stable_sort template @@ -8184,7 +8240,7 @@ namespace ranges { } while (_ISORT_MAX < _Last - _First) { // divide and conquer, ordering partition containing Nth - subrange<_It> _Mid = _RANGES _Partition_by_median_guess_unchecked(_First, _Last, _Pred, _Proj); + subrange<_It> _Mid = _Partition_by_median_guess_common(_First, _Last, _Pred, _Proj); if (_Mid.end() <= _Nth) { _First = _Mid.end(); @@ -8196,7 +8252,7 @@ namespace ranges { } // sort any remainder - _RANGES _Insertion_sort_common(_STD move(_First), _STD move(_Last), _STD move(_Pred), _STD move(_Proj)); + _Insertion_sort_common(_STD move(_First), _STD move(_Last), _STD move(_Pred), _STD move(_Proj)); } }; diff --git a/stl/inc/coroutine b/stl/inc/coroutine index fdf1a641e5e..2c939373da9 100644 --- a/stl/inc/coroutine +++ b/stl/inc/coroutine @@ -76,11 +76,11 @@ struct coroutine_handle { return __builtin_coro_done(_Ptr); } - void operator()() const noexcept { // strengthened + void operator()() const { __builtin_coro_resume(_Ptr); } - void resume() const noexcept { // strengthened + void resume() const { __builtin_coro_resume(_Ptr); } diff --git a/stl/inc/deque b/stl/inc/deque index 0006d35ae8c..8800b649baa 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -836,10 +836,10 @@ public: if (_Off <= _Mysize() / 2) { // closer to front, push to front then rotate emplace_front(_STD forward<_Valty>(_Val)...); - _STD rotate(begin(), begin() + 1, begin() + static_cast(1 + _Off)); + _STD rotate(begin(), _Next_iter(begin()), begin() + static_cast(1 + _Off)); } else { // closer to back, push to back then rotate emplace_back(_STD forward<_Valty>(_Val)...); - _STD rotate(begin() + static_cast(_Off), end() - 1, end()); + _STD rotate(begin() + static_cast(_Off), _Prev_iter(end()), end()); } return begin() + static_cast(_Off); } @@ -1064,7 +1064,7 @@ public: _STL_VERIFY(!empty(), "back() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return *(_Unchecked_end() - 1); + return *_Prev_iter(_Unchecked_end()); } _NODISCARD const_reference back() const noexcept /* strengthened */ { @@ -1072,7 +1072,7 @@ public: _STL_VERIFY(!empty(), "back() called on empty deque"); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return *(_Unchecked_end() - 1); + return *_Prev_iter(_Unchecked_end()); } void push_front(const _Ty& _Val) { @@ -1197,10 +1197,10 @@ public: if (_Off <= _Mysize() / 2) { // closer to front, push to front then copy push_front(_Val); - _STD rotate(begin(), begin() + 1, begin() + static_cast(1 + _Off)); + _STD rotate(begin(), _Next_iter(begin()), begin() + static_cast(1 + _Off)); } else { // closer to back, push to back then copy push_back(_Val); - _STD rotate(begin() + static_cast(_Off), end() - 1, end()); + _STD rotate(begin() + static_cast(_Off), _Prev_iter(end()), end()); } return begin() + static_cast(_Off); diff --git a/stl/inc/experimental/coroutine b/stl/inc/experimental/coroutine index a4068e07191..c6ed2a2a292 100644 --- a/stl/inc/experimental/coroutine +++ b/stl/inc/experimental/coroutine @@ -95,7 +95,7 @@ namespace experimental { return _Ptr; } - void operator()() const noexcept { + void operator()() const { resume(); } diff --git a/stl/inc/memory b/stl/inc/memory index a273a674b99..3b77c4313b3 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -26,6 +26,39 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN +#ifdef __cpp_lib_concepts +namespace ranges { + // clang-format off + // CONCEPT _No_throw_input_iterator + template + concept _No_throw_input_iterator = input_iterator<_It> + && is_lvalue_reference_v> + && same_as>, iter_value_t<_It>>; + + // CONCEPT _No_throw_sentinel_for + template + concept _No_throw_sentinel_for = sentinel_for<_Se, _It>; + + // CONCEPT _No_throw_forward_iterator + template + concept _No_throw_forward_iterator = _No_throw_input_iterator<_It> + && forward_iterator<_It> + && _No_throw_sentinel_for<_It, _It>; + + // CONCEPT _No_throw_input_range + template + concept _No_throw_input_range = range<_Rng> + && _No_throw_input_iterator> + && _No_throw_sentinel_for, iterator_t<_Rng>>; + + // CONCEPT _No_throw_forward_range + template + concept _No_throw_forward_range = _No_throw_input_range<_Rng> + && _No_throw_forward_iterator>; + // clang-format on +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_copy_n #if _HAS_IF_CONSTEXPR template @@ -97,6 +130,71 @@ _NoThrowFwdIt uninitialized_move(const _InIt _First, const _InIt _Last, _NoThrow return _Dest; } +#ifdef __cpp_lib_concepts +namespace ranges { + // ALIAS TEMPLATE uninitialized_move_result + template + using uninitialized_move_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::uninitialized_move + class _Uninitialized_move_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se1, _No_throw_forward_iterator _It2, _No_throw_sentinel_for<_It2> _Se2> + requires constructible_from, iter_rvalue_reference_t<_It1>> + uninitialized_move_result<_It1, _It2> operator()(_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2) const { + // clang-format on + _Adl_verify_range(_First1, _Last1); + _Adl_verify_range(_First2, _Last2); + auto _UResult = + _Uninitialized_move_unchecked(_Get_unwrapped(_STD move(_First1)), _Get_unwrapped(_STD move(_Last1)), + _Get_unwrapped(_STD move(_First2)), _Get_unwrapped(_STD move(_Last2))); + + _Seek_wrapped(_First1, _STD move(_UResult.in)); + _Seek_wrapped(_First2, _STD move(_UResult.out)); + return {_STD move(_First1), _STD move(_First2)}; + } + + // clang-format off + template + requires constructible_from, range_rvalue_reference_t<_Rng1>> + uninitialized_move_result, borrowed_iterator_t<_Rng2>> operator()( + _Rng1&& _Range1, _Rng2&& _Range2) const { + // clang-format on + auto _First1 = _RANGES begin(_Range1); + auto _UResult = _Uninitialized_move_unchecked( + _Get_unwrapped(_STD move(_First1)), _Uend(_Range1), _Ubegin(_Range2), _Uend(_Range2)); + + _Seek_wrapped(_First1, _STD move(_UResult.in)); + return {_STD move(_First1), _Rewrap_iterator(_Range2, _STD move(_UResult.out))}; + } + + private: + template + _NODISCARD static uninitialized_move_result<_It1, _It2> _Uninitialized_move_unchecked( + _It1 _IFirst, const _Se1 _ILast, _It2 _OFirst, const _Se2 _OLast) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It1>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It1>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It2>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se2, _It2>); + _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It1>>); + + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { + _Backout._Emplace_back(_RANGES iter_move(_IFirst)); + } + + return {_STD move(_IFirst), _Backout._Release()}; + } + }; + + inline constexpr _Uninitialized_move_fn uninitialized_move{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_move_n template pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { diff --git a/stl/inc/random b/stl/inc/random index f3748cb2fb6..ebb66b92c05 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -4528,10 +4528,7 @@ public: struct param_type : _Mypbase { // parameter package using distribution_type = piecewise_constant_distribution; - param_type() { - _Bvec.push_back(0); - _Bvec.push_back(1); - } + param_type() : _Bvec{0, 1} {} template param_type(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2) : _Mypbase(_Noinit), _Bvec(_First1, _Last1) { @@ -4539,6 +4536,8 @@ public: for (size_t _Idx = 0; _Idx < _Bvec.size() - 1; ++_Idx) { this->_Pvec.push_back(static_cast(*_First2++)); } + } else { // default construct + _Bvec = {0, 1}; } _Init(); @@ -4548,18 +4547,12 @@ public: param_type(initializer_list<_Ty> _Ilist, _Fn _Func) : _Mypbase(_Noinit) { if (2 <= _Ilist.size()) { _Bvec.assign(_Ilist); - } else { // default construct - _Bvec.push_back(0); - _Bvec.push_back(1); - } - - _Ty _Low = _Bvec.front(); - _Ty _Range = _Bvec.back() - _Low; - size_t _Count = _Bvec.size() - 1; - _Range /= static_cast<_Ty>(_Count); - for (size_t _Idx = 0; _Idx < _Count; ++_Idx) { - _Pvec.push_back(_Func(_Low + _Idx * _Range)); + for (size_t _Idx = 0; _Idx < _Bvec.size() - 1; ++_Idx) { + this->_Pvec.push_back(_Func(_Ty{0.5} * (_Bvec[_Idx] + _Bvec[_Idx + 1]))); + } + } else { // default construct + _Bvec = {0, 1}; } _Init(); @@ -4726,11 +4719,12 @@ public: using result_type = _Ty; struct param_type : _Mypbase { // parameter package + // TRANSITION, ABI: stores probability densities (N + 1 elements) in _Mybase::_Pvec + // this breaks invariants of discrete_distribution::param_type using distribution_type = piecewise_linear_distribution; - param_type() { - _Bvec.push_back(0); - _Bvec.push_back(1); + param_type() : _Bvec{0, 1} { + this->_Pvec.push_back(1.0); } template @@ -4739,6 +4733,8 @@ public: for (size_t _Idx = 0; _Idx < _Bvec.size(); ++_Idx) { this->_Pvec.push_back(static_cast(*_First2++)); } + } else { // default construct + _Bvec = {0, 1}; } _Init(); @@ -4748,18 +4744,12 @@ public: param_type(initializer_list<_Ty> _Ilist, _Fn _Func) : _Mypbase(_Noinit) { if (2 <= _Ilist.size()) { _Bvec.assign(_Ilist); - } else { // default construct - _Bvec.push_back(0); - _Bvec.push_back(1); - } - _Ty _Low = _Bvec.front(); - _Ty _Range = _Bvec.back() - _Low; - size_t _Count = _Bvec.size(); - - _Range /= static_cast<_Ty>(_Count); - for (size_t _Idx = 0; _Idx < _Count; ++_Idx) { - this->_Pvec.push_back(_Func(_Low + _Idx * _Range)); + for (const auto& _Bval : _Bvec) { + this->_Pvec.push_back(_Func(_Bval)); + } + } else { // default construct + _Bvec = {0, 1}; } _Init(); @@ -4769,12 +4759,12 @@ public: param_type(size_t _Count, _Ty _Low, _Ty _High, _Fn _Func) : _Mypbase(_Noinit) { _Ty _Range = _High - _Low; _STL_ASSERT(_Ty{0} < _Range, "invalid range for piecewise_linear_distribution"); - if (_Count < 2) { - _Count = 2; + if (_Count < 1) { + _Count = 1; } _Range /= static_cast(_Count); - for (size_t _Idx = 0; _Idx < _Count; ++_Idx) { // compute _Bvec and _Pvec + for (size_t _Idx = 0; _Idx <= _Count; ++_Idx) { // compute _Bvec and _Pvec _Ty _Bval = _Low + _Idx * _Range; _Bvec.push_back(_Bval); this->_Pvec.push_back(_Func(_Bval)); @@ -4799,20 +4789,27 @@ public: return _Ans; } + _NODISCARD double _Piece_probability(const size_t _Idx) const { + return 0.5 * (this->_Pvec[_Idx] + this->_Pvec[_Idx + 1]) + * static_cast(_Bvec[_Idx + 1] - _Bvec[_Idx]); + } + void _Init(bool _Renorm = true) { // initialize size_t _Size = this->_Pvec.size(); size_t _Idx; if (_Renorm) { - if (this->_Pvec.empty()) { - this->_Pvec.push_back(1.0); // make empty vector degenerate + if (this->_Pvec.empty()) { // make empty vector degenerate + this->_Pvec = {1.0, 1.0}; } else { // normalize probabilities double _Sum = 0; + _STL_ASSERT(0.0 <= this->_Pvec[0], "invalid probability for " + "piecewise_linear_distribution"); for (_Idx = 1; _Idx < _Size; ++_Idx) { // sum all probabilities _STL_ASSERT(0.0 <= this->_Pvec[_Idx], "invalid probability for " "piecewise_linear_distribution"); - _Sum += 0.5 * (this->_Pvec[_Idx - 1] + this->_Pvec[_Idx]); + _Sum += _Piece_probability(_Idx - 1); } _STL_ASSERT(0.0 < _Sum, "invalid probability vector for " @@ -4825,9 +4822,9 @@ public: } } - this->_Pcdf.assign(1, 0.5 * (this->_Pvec[0] + this->_Pvec[1])); + this->_Pcdf.assign(1, _Piece_probability(0)); for (_Idx = 2; _Idx < _Size; ++_Idx) { - this->_Pcdf.push_back(0.5 * (this->_Pvec[_Idx - 1] + this->_Pvec[_Idx]) + this->_Pcdf[_Idx - 2]); + this->_Pcdf.push_back(_Piece_probability(_Idx - 1) + this->_Pcdf[_Idx - 2]); } } @@ -4894,14 +4891,14 @@ public: _In(_Istr, _Val); _Par0._Pvec.push_back(_Val); } - _Par0._Init(false); // don't renormalize, just compute CDF - _Par._Bvec.clear(); - for (size_t _Idx = _Par._Pvec.size(); 0 < _Idx; --_Idx) { // get a value and add to intervals vector + _Par0._Bvec.clear(); + for (size_t _Idx = _Par0._Pvec.size(); 0 < _Idx; --_Idx) { // get a value and add to intervals vector double _Val; _In(_Istr, _Val); - _Par._Bvec.push_back(_Val); + _Par0._Bvec.push_back(_Val); } + _Par0._Init(false); // don't renormalize, just compute CDF return _Istr; } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index abb94ba7ac0..c5744776e0c 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -263,9 +263,19 @@ _Pointer _Refancy(_Pointer _Ptr) noexcept { } // FUNCTION TEMPLATE _Destroy_in_place +template +/* _CONSTEXPR20_DYNALLOC */ void _Destroy_range(_NoThrowFwdIt _First, _NoThrowSentinel _Last) noexcept; + template -void _Destroy_in_place(_Ty& _Obj) noexcept { - _Obj.~_Ty(); +/* _CONSTEXPR20_DYNALLOC */ void _Destroy_in_place(_Ty& _Obj) noexcept { +#if _HAS_IF_CONSTEXPR + if constexpr (is_array_v<_Ty>) { + _Destroy_range(_Obj, _Obj + extent_v<_Ty>); + } else +#endif // _HAS_IF_CONSTEXPR + { + _Obj.~_Ty(); + } } // FUNCTION TEMPLATE _Const_cast @@ -948,7 +958,8 @@ void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { // FUNCTION TEMPLATE _Destroy_range WITH ALLOC template -void _Destroy_range(_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept { +/* _CONSTEXPR20_DYNALLOC */ void _Destroy_range( + _Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept { // note that this is an optimization for debug mode codegen; in release mode the BE removes all of this using _Ty = typename _Alloc::value_type; if _CONSTEXPR_IF (!conjunction_v, _Uses_default_destroy<_Alloc, _Ty*>>) { @@ -959,8 +970,8 @@ void _Destroy_range(_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Las } // FUNCTION TEMPLATE _Destroy_range -template -void _Destroy_range(_NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept { +template +/* _CONSTEXPR20_DYNALLOC */ void _Destroy_range(_NoThrowFwdIt _First, const _NoThrowSentinel _Last) noexcept { // note that this is an optimization for debug mode codegen; in release mode the BE removes all of this if _CONSTEXPR_IF (!is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) { for (; _First != _Last; ++_First) { @@ -1414,29 +1425,64 @@ struct _Uninitialized_backout { // struct to undo partially constructed ranges i _NoThrowFwdIt _First; _NoThrowFwdIt _Last; - explicit _Uninitialized_backout(_NoThrowFwdIt _Dest) : _First(_Dest), _Last(_Dest) {} + constexpr explicit _Uninitialized_backout(_NoThrowFwdIt _Dest) : _First(_Dest), _Last(_Dest) {} - _Uninitialized_backout(_NoThrowFwdIt _First_, _NoThrowFwdIt _Last_) : _First(_First_), _Last(_Last_) {} + constexpr _Uninitialized_backout(_NoThrowFwdIt _First_, _NoThrowFwdIt _Last_) : _First(_First_), _Last(_Last_) {} _Uninitialized_backout(const _Uninitialized_backout&) = delete; _Uninitialized_backout& operator=(const _Uninitialized_backout&) = delete; - ~_Uninitialized_backout() { + /* _CONSTEXPR20_DYNALLOC */ ~_Uninitialized_backout() { _Destroy_range(_First, _Last); } template - void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment + /* _CONSTEXPR20_DYNALLOC */ void _Emplace_back(_Types&&... _Vals) { + // construct a new element at *_Last and increment _Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...); ++_Last; } - _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last + /* _CONSTEXPR20_DYNALLOC */ _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last _First = _Last; return _Last; } }; +#ifdef __cpp_lib_concepts +namespace ranges { + // CONCEPT _Convertible_from + template + concept _Convertible_from = convertible_to<_From, _To>; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-attributes" +#endif // __clang__ + + // STRUCT TEMPLATE in_out_result + template + struct in_out_result { + [[no_unique_address]] _In in; + [[no_unique_address]] _Out out; + + template <_Convertible_from _IIn, _Convertible_from _OOut> + constexpr operator in_out_result<_IIn, _OOut>() const& { + return {in, out}; + } + + template <_Convertible_from<_In> _IIn, _Convertible_from<_Out> _OOut> + constexpr operator in_out_result<_IIn, _OOut>() && { + return {_STD move(in), _STD move(out)}; + } + }; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE _Uninitialized_move_unchecked #if _HAS_IF_CONSTEXPR template diff --git a/stl/inc/yvals.h b/stl/inc/yvals.h index ea0b53f4571..1a70aa17ea4 100644 --- a/stl/inc/yvals.h +++ b/stl/inc/yvals.h @@ -306,22 +306,6 @@ _STL_DISABLE_CLANG_WARNINGS #define _LOCK_DEBUG 3 #define _LOCK_AT_THREAD_EXIT 4 -#ifndef _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE -#if _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 -#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 1 -#else // ^^^ _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 // _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 vvv -#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 0 -#endif // ^^^ _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 ^^^ -#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE - -#ifndef _ALLOW_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE_MISMATCH -#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE -#pragma detect_mismatch("_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE", "1") -#else -#pragma detect_mismatch("_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE", "0") -#endif -#endif // !_ALLOW_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE_MISMATCH - #ifdef __cplusplus _STD_BEGIN enum _Uninitialized { // tag for suppressing initialization diff --git a/stl/msbuild/stl_1/stl_1.files.settings.targets b/stl/msbuild/stl_1/stl_1.files.settings.targets index d186b4e07aa..8c423bd34ec 100644 --- a/stl/msbuild/stl_1/stl_1.files.settings.targets +++ b/stl/msbuild/stl_1/stl_1.files.settings.targets @@ -11,6 +11,11 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception "> nativecpp + + nativecpp + diff --git a/stl/msbuild/stl_2/stl_2.files.settings.targets b/stl/msbuild/stl_2/stl_2.files.settings.targets index 9492e7032a3..4f28e08a72d 100644 --- a/stl/msbuild/stl_2/stl_2.files.settings.targets +++ b/stl/msbuild/stl_2/stl_2.files.settings.targets @@ -11,6 +11,11 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception "> nativecpp + + nativecpp + diff --git a/stl/msbuild/stl_atomic_wait/stl_atomic_wait.files.settings.targets b/stl/msbuild/stl_atomic_wait/stl_atomic_wait.files.settings.targets index 0de6759e9cd..e7cc52c398d 100644 --- a/stl/msbuild/stl_atomic_wait/stl_atomic_wait.files.settings.targets +++ b/stl/msbuild/stl_atomic_wait/stl_atomic_wait.files.settings.targets @@ -11,5 +11,10 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception "> nativecpp + + nativecpp + diff --git a/stl/msbuild/stl_codecvt_ids/stl_codecvt_ids.files.settings.targets b/stl/msbuild/stl_codecvt_ids/stl_codecvt_ids.files.settings.targets index 48cae4bf3fc..b4a50d87ea3 100644 --- a/stl/msbuild/stl_codecvt_ids/stl_codecvt_ids.files.settings.targets +++ b/stl/msbuild/stl_codecvt_ids/stl_codecvt_ids.files.settings.targets @@ -11,6 +11,11 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception "> nativecpp + + nativecpp + diff --git a/stl/src/atomic_wait.cpp b/stl/src/atomic_wait.cpp index d16f53f2197..0a45b12aee7 100644 --- a/stl/src/atomic_wait.cpp +++ b/stl/src/atomic_wait.cpp @@ -88,6 +88,14 @@ namespace { #endif // _DEBUG } +#ifndef _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE +#if _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 +#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 1 +#else // ^^^ _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 // _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 vvv +#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 0 +#endif // ^^^ _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 ^^^ +#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE + #if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE #define __crtWaitOnAddress WaitOnAddress diff --git a/stl/src/dllmain_satellite.cpp b/stl/src/dllmain_satellite.cpp new file mode 100644 index 00000000000..af2e024c1fe --- /dev/null +++ b/stl/src/dllmain_satellite.cpp @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +// DllMain for 'satellite' DLLs which don't need TLS. + +extern "C" BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID) { + if (ul_reason_for_call == DLL_PROCESS_ATTACH) { + if (!DisableThreadLibraryCalls(hModule)) { + return FALSE; + } + } + + return TRUE; +} diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 25ee7b5d449..5d3dc61e136 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -775,6 +775,15 @@ std/iterators/predef.iterators/insert.iterators/insert.iterator/types.pass.cpp F std/numerics/complex.number/cmplx.over/conj.pass.cpp:0 FAIL std/numerics/complex.number/cmplx.over/proj.pass.cpp:0 FAIL +# Assertion failed: std::abs(skew - x_skew) < 0.01 +# Random number generation test with too strict pass criteria (test8 failure probability ~= 0.04) +std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.pconst/eval.pass.cpp FAIL + +# Assertion failed: std::abs(f(u[i], a, m, bk, c) - double(i)/N) < .001 +# Random number generation test with too strict pass criteria (test6 failure probability > 0.2) +std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/eval_param.pass.cpp FAIL +std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/eval.pass.cpp FAIL + # Assertion failed: (std::lerp(T(2.3), T(2.3), inf) == T(2.3)) # Asserts `(std::lerp(T(2.3), T(2.3), inf) == T(2.3))` and `std::isnan(std::lerp(T( 0), T( 0), inf))` # They shouldn't behave differently. Both of them should probably return NaN. @@ -817,22 +826,6 @@ std/numerics/rand/rand.dis/rand.dist.pois/rand.dist.pois.gamma/min.pass.cpp FAIL std/numerics/rand/rand.dis/rand.dist.pois/rand.dist.pois.poisson/eval_param.pass.cpp FAIL std/numerics/rand/rand.dis/rand.dist.pois/rand.dist.pois.poisson/eval.pass.cpp FAIL std/numerics/rand/rand.dis/rand.dist.pois/rand.dist.pois.weibull/max.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.pconst/ctor_init_func.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.pconst/ctor_iterator.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.pconst/eval.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.pconst/param_ctor_init_func.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.pconst/param_ctor_iterator.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/ctor_default.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/ctor_func.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/ctor_init_func.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/ctor_iterator.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/ctor_param.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/eval_param.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/eval.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/param_ctor_default.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/param_ctor_func.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/param_ctor_init_func.pass.cpp FAIL -std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/param_ctor_iterator.pass.cpp FAIL std/numerics/rand/rand.dis/rand.dist.uni/rand.dist.uni.real/param_ctor.pass.cpp FAIL # Not yet analyzed, likely STL bugs. Various assertions. diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 116e6e92f08..9d43be173d3 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -775,6 +775,15 @@ iterators\predef.iterators\insert.iterators\insert.iterator\types.pass.cpp numerics\complex.number\cmplx.over\conj.pass.cpp numerics\complex.number\cmplx.over\proj.pass.cpp +# Assertion failed: std::abs(skew - x_skew) < 0.01 +# Random number generation test with too strict pass criteria (test8 failure probability ~= 0.04) +numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.pconst\eval.pass.cpp + +# Assertion failed: std::abs(f(u[i], a, m, bk, c) - double(i)/N) < .001 +# Random number generation test with too strict pass criteria (test6 failure probability > 0.2) +numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\eval_param.pass.cpp +numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\eval.pass.cpp + # Assertion failed: (std::lerp(T(2.3), T(2.3), inf) == T(2.3)) # Asserts `(std::lerp(T(2.3), T(2.3), inf) == T(2.3))` and `std::isnan(std::lerp(T( 0), T( 0), inf))` # They shouldn't behave differently. Both of them should probably return NaN. @@ -817,22 +826,6 @@ numerics\rand\rand.dis\rand.dist.pois\rand.dist.pois.gamma\min.pass.cpp numerics\rand\rand.dis\rand.dist.pois\rand.dist.pois.poisson\eval_param.pass.cpp numerics\rand\rand.dis\rand.dist.pois\rand.dist.pois.poisson\eval.pass.cpp numerics\rand\rand.dis\rand.dist.pois\rand.dist.pois.weibull\max.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.pconst\ctor_init_func.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.pconst\ctor_iterator.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.pconst\eval.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.pconst\param_ctor_init_func.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.pconst\param_ctor_iterator.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\ctor_default.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\ctor_func.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\ctor_init_func.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\ctor_iterator.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\ctor_param.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\eval_param.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\eval.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\param_ctor_default.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\param_ctor_func.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\param_ctor_init_func.pass.cpp -numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\param_ctor_iterator.pass.cpp numerics\rand\rand.dis\rand.dist.uni\rand.dist.uni.real\param_ctor.pass.cpp # Not yet analyzed, likely STL bugs. Various assertions. diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index de785c12555..1c03e882c5e 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -415,8 +415,7 @@ namespace test { ++ptr_; } - [[nodiscard]] constexpr friend std::remove_cv_t iter_move(iterator const& i) - requires at_least && std::constructible_from, Element> { + [[nodiscard]] constexpr friend Element&& iter_move(iterator const& i) requires at_least { return std::move(*i.ptr_); } diff --git a/tests/std/test.lst b/tests/std/test.lst index fb1f14add67..cf0318fa98d 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -298,9 +298,11 @@ tests\P0896R4_ranges_alg_set_intersection tests\P0896R4_ranges_alg_set_symmetric_difference tests\P0896R4_ranges_alg_set_union tests\P0896R4_ranges_alg_shuffle +tests\P0896R4_ranges_alg_sort tests\P0896R4_ranges_alg_swap_ranges tests\P0896R4_ranges_alg_transform_binary tests\P0896R4_ranges_alg_transform_unary +tests\P0896R4_ranges_alg_uninitialized_move tests\P0896R4_ranges_alg_unique tests\P0896R4_ranges_alg_unique_copy tests\P0896R4_ranges_algorithm_machinery diff --git a/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp b/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp index b0abff0aebc..bece898adbf 100644 --- a/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp +++ b/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp @@ -282,7 +282,7 @@ constexpr bool can_addressof = false; template constexpr bool can_addressof()))>> = true; -void test_LWG_2598() { +void test_LWG_2598() { // COMPILE-ONLY STATIC_ASSERT(can_addressof); STATIC_ASSERT(can_addressof); STATIC_ASSERT(can_addressof); @@ -292,3 +292,20 @@ void test_LWG_2598() { STATIC_ASSERT(!can_addressof); STATIC_ASSERT(!can_addressof); } + +// Also test DevCom-1134328, in which `deque::_Unchecked_iterator{} - 1` finds +// operator-(const S&, int) by argument-dependent lookup causing overload resolution +// to fail due to ambiguity when compiling 64-bit. +struct S { + S() = default; + + template + S(T&&); +}; + +S operator-(const S&, int); + +void test_DevCom_1134328() { // COMPILE-ONLY + deque d{nullptr}; + (void) d.back(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_sort/env.lst b/tests/std/tests/P0896R4_ranges_alg_sort/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_sort/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_sort/test.cpp b/tests/std/tests/P0896R4_ranges_alg_sort/test.cpp new file mode 100644 index 00000000000..88c838a4eba --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_sort/test.cpp @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using P = pair; + +// Validate dangling story +STATIC_ASSERT(same_as{})), ranges::dangling>); +STATIC_ASSERT(same_as{})), int*>); + +struct instantiator { + static constexpr array input = {P{-1200257975, 0}, P{-1260655766, 1}, P{-1298559576, 2}, P{-1459960308, 3}, + P{-2095681771, 4}, P{-441494788, 5}, P{-47163201, 6}, P{-912489821, 7}, P{1429106719, 8}, P{1668617627, 9}}; + + template + static constexpr void call() { +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 + if constexpr (!ranges::contiguous_range) +#endif // TRANSITION, VSO-938163 + { + using ranges::sort, ranges::is_sorted, ranges::iterator_t, ranges::less; + + { // Validate range overload + auto buff = input; + const R range{buff}; + const same_as> auto result = sort(range, less{}, get_first); + assert(result == range.end()); + assert(is_sorted(range, less{}, get_first)); + } + + { // Validate iterator overload + auto buff = input; + const R range{buff}; + const same_as> auto result = sort(range.begin(), range.end(), less{}, get_first); + assert(result == range.end()); + assert(is_sorted(range.begin(), range.end(), less{}, get_first)); + } + + { // Validate empty range + const R range{}; + const same_as> auto result = sort(range, less{}, get_first); + assert(result == range.end()); + assert(is_sorted(range, less{}, get_first)); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_random(), true)); + test_random(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp new file mode 100644 index 00000000000..773378f42f4 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp @@ -0,0 +1,181 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate that uninitialized_move_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_move_result>); +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_move_result>); +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_move_result>); +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_move_result>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 29; + int val = 10; + + int_wrapper() { + ++constructions; + } + int_wrapper(int x) : val{x} { + ++constructions; + } + + int_wrapper(int_wrapper&& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + + val = exchange(that.val, -1); + ++constructions; + } + + ~int_wrapper() { + ++destructions; + } + + int_wrapper& operator=(int_wrapper&& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + val = exchange(that.val, -1); + return *this; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(movable && !copyable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_input[] = {-1, -1, -1}; + + template + static void call() { + using ranges::uninitialized_move, ranges::uninitialized_move_result, ranges::equal, ranges::equal_to, + ranges::iterator_t; + + { // Validate range overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = + uninitialized_move(wrapped_input, wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + + { // Validate iterator overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = uninitialized_move( + wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + static constexpr int expected_input[] = {-1, -1, int_wrapper::magic_throwing_val, 12345}; + + template + static void call() { + // Validate only range overload (one is plenty since they both use the same backend) + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_move(wrapped_input, wrapped_output); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. + + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); +} diff --git a/tests/std/tests/P0896R4_ranges_algorithm_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_algorithm_machinery/test.cpp index ddb4888f0a3..c0184d73292 100644 --- a/tests/std/tests/P0896R4_ranges_algorithm_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_algorithm_machinery/test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -983,3 +984,128 @@ namespace gh_1089 { } } } // namespace gh_1089 + +namespace special_memory_concepts { + // Validate the concepts from [special.mem.concepts] used to constrain the specialized memory algorithms + // NB: Non-portable tests of internal machinery + using ranges::_No_throw_input_iterator, ranges::_No_throw_sentinel_for, ranges::_No_throw_input_range, + ranges::_No_throw_forward_iterator, ranges::_No_throw_forward_range; + using std::forward_iterator, std::input_iterator, std::sentinel_for; + + enum class iterator_status : int { not_input, not_lvalue_reference, different_reference_and_value, input, forward }; + + template + struct iterator_archetype { + using iterator_concept = std::conditional_t>; + using difference_type = int; + using value_type = std::conditional_t; + + // clang-format off + int operator*() const requires (I == iterator_status::not_lvalue_reference); + int& operator*() const requires (I != iterator_status::not_lvalue_reference); + + iterator_archetype& operator++(); + void operator++(int) requires (I != iterator_status::forward); + iterator_archetype operator++(int) requires (I == iterator_status::forward); + + bool operator==(std::default_sentinel_t) const; + bool operator==(iterator_archetype const&) const requires (I == iterator_status::forward); + // clang-format on + }; + // Verify iterator_archetype + STATIC_ASSERT(!input_iterator>); + STATIC_ASSERT(input_iterator>); + STATIC_ASSERT(input_iterator>); + STATIC_ASSERT(input_iterator>); + STATIC_ASSERT(!forward_iterator>); + STATIC_ASSERT(forward_iterator>); + + template + inline constexpr bool has_lvalue_reference = std::is_lvalue_reference_v>; + STATIC_ASSERT(has_lvalue_reference>); + STATIC_ASSERT(!has_lvalue_reference>); + STATIC_ASSERT(has_lvalue_reference>); + STATIC_ASSERT(has_lvalue_reference>); + STATIC_ASSERT(has_lvalue_reference>); + + template + inline constexpr bool same_reference_value = + std::same_as>, std::iter_value_t>; + STATIC_ASSERT(same_reference_value>); + STATIC_ASSERT(same_reference_value>); + STATIC_ASSERT(!same_reference_value>); + STATIC_ASSERT(same_reference_value>); + STATIC_ASSERT(same_reference_value>); + + // Validate _No_throw_input_iterator + STATIC_ASSERT(!_No_throw_input_iterator>); + STATIC_ASSERT(!_No_throw_input_iterator>); + STATIC_ASSERT(!_No_throw_input_iterator>); + STATIC_ASSERT(_No_throw_input_iterator>); + STATIC_ASSERT(_No_throw_input_iterator>); + + enum class sentinel_status : int { no, yes }; + + template + struct sentinel_archetype { + // clang-format off + template + bool operator==(iterator_archetype const&) const requires (I != sentinel_status::no); + // clang-format on + }; + // Verify sentinel_archetype + STATIC_ASSERT(!sentinel_for, iterator_archetype>); + STATIC_ASSERT(sentinel_for, iterator_archetype>); + + // Validate _No_throw_sentinel_for + STATIC_ASSERT( + !_No_throw_sentinel_for, iterator_archetype>); + STATIC_ASSERT( + _No_throw_sentinel_for, iterator_archetype>); + STATIC_ASSERT(!_No_throw_sentinel_for, + iterator_archetype>); + STATIC_ASSERT(_No_throw_sentinel_for, + iterator_archetype>); + + // Validate _No_throw_forward_iterator + STATIC_ASSERT(!_No_throw_forward_iterator>); + STATIC_ASSERT(!_No_throw_forward_iterator>); + STATIC_ASSERT(!_No_throw_forward_iterator>); + STATIC_ASSERT(!_No_throw_forward_iterator>); + STATIC_ASSERT(_No_throw_forward_iterator>); + + enum class range_status : int { not_range, not_input, input, forward }; + + template + struct range_archetype { + using It = std::conditional_t, + std::conditional_t, + iterator_archetype>>>; + using Se = std::conditional_t, + std::default_sentinel_t>>; + + It begin() const; + Se end() const; + }; + // Verify range_archetype + STATIC_ASSERT(!ranges::range>); + STATIC_ASSERT(ranges::range>); + STATIC_ASSERT(ranges::range>); + STATIC_ASSERT(ranges::range>); + + // Validate _No_throw_input_range; note that the distinction betweeen range and + // no-throw-sentinel-for, iterator_t> is purely semantic, so we can't test them separately. + STATIC_ASSERT(!_No_throw_input_range>); + STATIC_ASSERT(!_No_throw_input_range>); + STATIC_ASSERT(_No_throw_input_range>); + STATIC_ASSERT(_No_throw_input_range>); + + // Validate _No_throw_forward_range + STATIC_ASSERT(!_No_throw_forward_range>); + STATIC_ASSERT(!_No_throw_forward_range>); + STATIC_ASSERT(!_No_throw_forward_range>); + STATIC_ASSERT(_No_throw_forward_range>); +} // namespace special_memory_concepts diff --git a/tests/std/tests/P0896R4_ranges_subrange/test.cpp b/tests/std/tests/P0896R4_ranges_subrange/test.cpp index d8bfe739a2a..961505a64ce 100644 --- a/tests/std/tests/P0896R4_ranges_subrange/test.cpp +++ b/tests/std/tests/P0896R4_ranges_subrange/test.cpp @@ -14,7 +14,7 @@ #include #include -#include "range_algorithm_support.hpp" +#include #define ASSERT(...) assert((__VA_ARGS__)) diff --git a/tests/tr1/include/tspec_random.h b/tests/tr1/include/tspec_random.h index 9580a50b323..278493dd7ef 100644 --- a/tests/tr1/include/tspec_random.h +++ b/tests/tr1/include/tspec_random.h @@ -135,4 +135,5 @@ void test_random() { // test all of the distributions TESTR(student_t_distribution); TESTR(discrete_distribution); TESTR(piecewise_constant_distribution); + TESTR(piecewise_linear_distribution); } diff --git a/tests/tr1/include/tspec_random_defs.h b/tests/tr1/include/tspec_random_defs.h index bfc2b02940b..d4283411993 100644 --- a/tests/tr1/include/tspec_random_defs.h +++ b/tests/tr1/include/tspec_random_defs.h @@ -309,13 +309,13 @@ One_arg weibull_distribution_vals[] = { {FLIT(99.0), FLIT(0.0), FLIT(0.0)}, }; -int _Random_test_fun(double x) { - return (int) x; +int _Random_test_fun_1(double x) { + return (int) x - 50; } typedef double piecewise_constant_distribution_type; piecewise_constant_distribution piecewise_constant_distribution_dist( - 100, 50.0, 100.0, _Random_test_fun); + 8, 50.0, 100.0, _Random_test_fun_1); int piecewise_constant_distribution_smaller_ok = 0; int piecewise_constant_distribution_larger_ok = 0; @@ -325,15 +325,38 @@ One_arg piecewise_constant_distribution_vals[] = { {FLIT(22.0), FLIT(0.0), FLIT(0.0)}, {FLIT(33.0), FLIT(0.0), FLIT(0.0)}, {FLIT(44.0), FLIT(0.0), FLIT(0.0)}, - {FLIT(55.0), FLIT(0.014765100671140939452), FLIT(0.0)}, - {FLIT(66.0), FLIT(0.017718120805369125953), FLIT(0.0)}, - {FLIT(77.0), FLIT(0.02067114093959731419), FLIT(0.0)}, - {FLIT(88.0), FLIT(0.023624161073825502428), FLIT(0.0)}, - {FLIT(99.0), FLIT(0.026577181208053690665), FLIT(0.0)}, + {FLIT(55.0), FLIT(0.0024489795918367346), FLIT(0.0)}, + {FLIT(66.0), FLIT(0.012244897959183673), FLIT(0.0)}, + {FLIT(77.0), FLIT(0.022857142857142857), FLIT(0.0)}, + {FLIT(88.0), FLIT(0.0326530612244898), FLIT(0.0)}, + {FLIT(99.0), FLIT(0.037551020408163265), FLIT(0.0)}, +}; + +typedef double piecewise_linear_distribution_type; +piecewise_linear_distribution piecewise_linear_distribution_dist( + 8, 50.0, 100.0, _Random_test_fun_1); +int piecewise_linear_distribution_smaller_ok = 0; +int piecewise_linear_distribution_larger_ok = 0; + +One_arg piecewise_linear_distribution_vals[] = { + {FLIT(0.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(11.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(22.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(33.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(44.0), FLIT(0.0), FLIT(0.0)}, + {FLIT(55.0), FLIT(0.004467005076142132), FLIT(0.0)}, + {FLIT(66.0), FLIT(0.013401015228426396), FLIT(0.0)}, + {FLIT(77.0), FLIT(0.02233502538071066), FLIT(0.0)}, + {FLIT(88.0), FLIT(0.03126903553299493), FLIT(0.0)}, + {FLIT(99.0), FLIT(0.04020304568527919), FLIT(0.0)}, }; +int _Random_test_fun_2(double x) { + return (int) x; +} + typedef unsigned int discrete_distribution_type; -discrete_distribution discrete_distribution_dist(100, 70, 90, _Random_test_fun); +discrete_distribution discrete_distribution_dist(100, 70, 90, _Random_test_fun_2); int discrete_distribution_smaller_ok = 0; int discrete_distribution_larger_ok = 0; diff --git a/tests/tr1/tests/random5/test.cpp b/tests/tr1/tests/random5/test.cpp index 00564ec8ed7..5b692afa771 100644 --- a/tests/tr1/tests/random5/test.cpp +++ b/tests/tr1/tests/random5/test.cpp @@ -461,10 +461,23 @@ static void tpiecewise_constant() { CHECK(st); dist_t dist0; - CHECK_INT(dist0.probabilities().size(), 1); - CHECK_DOUBLE(dist0.probabilities()[0], 1.0); + CHECK_INT(dist0.densities().size(), 1); + CHECK_DOUBLE(dist0.densities()[0], 1.0); + CHECK_INT(dist0.intervals().size(), 2); + CHECK_DOUBLE(dist0.intervals()[0], 0.0); + CHECK_DOUBLE(dist0.intervals()[1], 1.0); dist0.reset(); + STD vector ends_not_enough = {0.5}; + STD vector vec_not_enough = {0.5}; + dist_t dist0_2(ends_not_enough.begin(), ends_not_enough.end(), vec_not_enough.begin()); + CHECK_INT(dist0_2.densities().size(), 1); + CHECK_DOUBLE(dist0_2.densities()[0], 1.0); + CHECK_INT(dist0_2.intervals().size(), 2); + CHECK_DOUBLE(dist0_2.intervals()[0], 0.0); + CHECK_DOUBLE(dist0_2.intervals()[1], 1.0); + + STD vector ends; ends.push_back(0.0); ends.push_back(1.0); @@ -486,9 +499,10 @@ static void tpiecewise_constant() { dist_t dist2(10, 1.0, 2.0, myfn); CHECK_INT(dist2.densities().size(), 10); - double arr[] = {1.0, 1.1, 1.2, 1.3, 1.4}; + double arr[] = {1.0, 1.5, 2.0, 3.0, 4.0}; dist_t dist3(STD initializer_list(&arr[0], &arr[5]), myfn); CHECK_INT(dist3.densities().size(), 4); + CHECK_DOUBLE(dist3.densities()[0], 0.2777777777777778); dist_t::param_type::distribution_type::param_type par0 = dist1.param(); CHECK(!(par0 != dist1.param())); @@ -520,10 +534,24 @@ static void tpiecewise_linear() { CHECK(st); dist_t dist0; - CHECK_INT(dist0.probabilities().size(), 1); - CHECK_DOUBLE(dist0.probabilities()[0], 1.0); + CHECK_INT(dist0.densities().size(), 2); + CHECK_DOUBLE(dist0.densities()[0], 1.0); + CHECK_DOUBLE(dist0.densities()[1], 1.0); + CHECK_INT(dist0.intervals().size(), 2); + CHECK_DOUBLE(dist0.intervals()[0], 0.0); + CHECK_DOUBLE(dist0.intervals()[1], 1.0); dist0.reset(); + STD vector ends_not_enough = {0.5}; + STD vector vec_not_enough = {0.5}; + dist_t dist0_2(ends_not_enough.begin(), ends_not_enough.end(), vec_not_enough.begin()); + CHECK_INT(dist0_2.densities().size(), 2); + CHECK_DOUBLE(dist0_2.densities()[0], 1.0); + CHECK_DOUBLE(dist0_2.densities()[1], 1.0); + CHECK_INT(dist0_2.intervals().size(), 2); + CHECK_DOUBLE(dist0_2.intervals()[0], 0.0); + CHECK_DOUBLE(dist0_2.intervals()[1], 1.0); + STD vector ends; ends.push_back(0.0); ends.push_back(1.0); @@ -533,26 +561,31 @@ static void tpiecewise_linear() { STD vector vec(5, 1.0); dist_t dist1(ends.begin(), ends.end(), vec.begin()); CHECK_INT(dist1.densities().size(), 5); + CHECK_DOUBLE(dist1.densities()[0], 0.25); CHECK_INT(dist1.intervals().size(), 5); CHECK_DOUBLE(dist1.intervals()[0], 0.0); STD stringstream str; str << dist1; str >> dist0; CHECK_INT(dist0.densities().size(), 5); + CHECK_DOUBLE(dist0.densities()[0], 0.25); dist_t dist2(10, 1.0, 2.0, myfn); - CHECK_INT(dist2.densities().size(), 10); + CHECK_INT(dist2.densities().size(), 11); - double arr[] = {1.0, 1.1, 1.2, 1.3, 1.4}; + double arr[] = {1.0, 1.5, 2.0, 3.0, 4.0}; dist_t dist3(STD initializer_list(&arr[0], &arr[5]), myfn); CHECK_INT(dist3.densities().size(), 5); + CHECK_DOUBLE(dist3.densities()[0], 0.13333333333333333); dist_t::param_type::distribution_type::param_type par0 = dist1.param(); CHECK(!(par0 != dist1.param())); dist0.param(par0); + CHECK(dist0.densities() == par0.densities()); CHECK(dist0.intervals() == par0.intervals()); ends = par0.intervals(); + vec = par0.densities(); CHECK(par0 == dist_t::param_type(ends.begin(), ends.end(), vec.begin())); CHECK(dist2.param() == dist_t::param_type(10, 1.0, 2.0, myfn));