Skip to content

Commit

Permalink
Implement constexpr algorithms.
Browse files Browse the repository at this point in the history
Resolves microsoftGH-6, microsoftGH-38, and drive-by fixes microsoftGH-414.

Constexprizes the following algorithms and enables all relevant libc++ tests:

* adjacent_find
* all_of
* any_of
* binary_search
* copy
* copy_backward
* copy_if
* copy_n
* count
* count_if
* equal
* equal_range
* exchange
* fill
* fill_n
* find
* find_end
* find_first_of
* find_if
* find_if_not
* for_each
* for_each_n
* generate
* generate_n
* includes
* is_heap
* is_heap
* is_heap_until
* is_partitioned
* is_permutation
* is_sorted
* is_sorted_until
* iter_swap
* lexicographical_compare
* lower_bound
* make_heap
* merge
* mismatch
* move
* move_backward
* next_permutation
* none_of
* nth_element
* partial_sort
* partial_sort_copy
* partition
* partition_copy
* partition_point
* pop_heap
* prev_permutation
* push_heap
* remove
* remove_copy
* remove_copy_if
* remove_if
* replace
* replace_copy
* replace_copy_if
* replace_if
* reverse_copy
* revese
* rotate
* rotate_copy
* search
* search_n
* set_difference
* set_intersection
* set_symmetric_difference
* set_union
* sort
* sort_heap
* swap
* swap_ranges
* transform
* unique
* unique_copy
* upper_bound

This commit also contains the contents of microsoft#423 to workaround DevCom-883631, it will be rebased and that content removed once that is merged (the other one needs to be merged first).

Specific notes:

`<xutility>`:
* The `_Ptr_copy_cat` family are moved down next to std::copy as that is their first consumer.
* The core language loop for `copy_n` is fairly long and so it was extracted into its own function, `_Copy_n_core` (note similar name schema to `_Copy_memmove`)
* `reverse` was changed to use early-returns for its optimization passes; this removes the nice thing of having if constexpr not instantiate the loop. However, this form allows the loop to not be duplicated.
  • Loading branch information
BillyONeal committed Jan 16, 2020
1 parent d862650 commit e2c4cc8
Show file tree
Hide file tree
Showing 9 changed files with 650 additions and 507 deletions.
2 changes: 1 addition & 1 deletion llvm-project
Submodule llvm-project updated 1537 files
389 changes: 228 additions & 161 deletions stl/inc/algorithm

Large diffs are not rendered by default.

57 changes: 29 additions & 28 deletions stl/inc/numeric
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,26 @@ _NODISCARD _CONSTEXPR20_ICE _Ty reduce(const _InIt _First, const _InIt _Last, _T
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
if constexpr (_Plus_on_arithmetic_ranges_reduction_v<_Unwrapped_t<const _InIt&>, _Ty, _BinOp>) {
#ifdef __cpp_lib_is_constant_evaluated
// TRANSITION, DevCom-878972
if (_STD is_constant_evaluated()) {
for (; _UFirst != _ULast; ++_UFirst) {
_Val = _Reduce_op(_STD move(_Val), *_UFirst); // Requirement missing from N4713
}
return _Val;
} else
#endif // __cpp_lib_is_constant_evaluated
{
if constexpr (_Plus_on_arithmetic_ranges_reduction_v<_Unwrapped_t<const _InIt&>, _Ty, _BinOp>) {
(void) _Reduce_op; // TRANSITION, VSO-486357
return _Reduce_plus_arithmetic_ranges(_UFirst, _ULast, _Val);
} else {
if (_STD is_constant_evaluated()) {
for (; _UFirst != _ULast; ++_UFirst) {
_Val = _Reduce_op(_STD move(_Val), *_UFirst); // Requirement missing from N4713
}

return _Val;
} else
#endif
{
(void) _Reduce_op; // TRANSITION, VSO-486357
return _Reduce_plus_arithmetic_ranges(_UFirst, _ULast, _Val);
}
} else {
for (; _UFirst != _ULast; ++_UFirst) {
_Val = _Reduce_op(_STD move(_Val), *_UFirst); // Requirement missing from N4713
}

return _Val;
}
}

Expand Down Expand Up @@ -211,28 +212,28 @@ _NODISCARD _CONSTEXPR20_ICE _Ty transform_reduce(
auto _UFirst1 = _Get_unwrapped(_First1);
const auto _ULast1 = _Get_unwrapped(_Last1);
auto _UFirst2 = _Get_unwrapped_n(_First2, _Idl_distance<_InIt1>(_UFirst1, _ULast1));
if constexpr (_Default_ops_transform_reduce_v<_Unwrapped_t<const _InIt1&>, _Unwrapped_t<const _InIt2&>, _Ty,
_BinOp1, _BinOp2>) {
#ifdef __cpp_lib_is_constant_evaluated
// TRANSITION, DevCom-878972
if (_STD is_constant_evaluated()) {
for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) {
_Val = _Reduce_op(_STD move(_Val), _Transform_op(*_UFirst1, *_UFirst2)); // Requirement missing from N4713
}
return _Val;
} else
#endif // __cpp_lib_is_constant_evaluated
{
if constexpr (_Default_ops_transform_reduce_v<_Unwrapped_t<const _InIt1&>, _Unwrapped_t<const _InIt2&>, _Ty,
_BinOp1, _BinOp2>) {
(void) _Reduce_op; // TRANSITION, VSO-486357
(void) _Transform_op; // TRANSITION, VSO-486357
return _Transform_reduce_arithmetic_defaults(_UFirst1, _ULast1, _UFirst2, _STD move(_Val));
} else {
// TRANSITION, DevCom-878972
if (_STD is_constant_evaluated()) {
for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) {
_Val =
_Reduce_op(_STD move(_Val), _Transform_op(*_UFirst1, *_UFirst2)); // Requirement missing from N4713
}
return _Val;
} else
#endif // __cpp_lib_is_constant_evaluated
{
(void) _Reduce_op; // TRANSITION, VSO-486357
(void) _Transform_op; // TRANSITION, VSO-486357
return _Transform_reduce_arithmetic_defaults(_UFirst1, _ULast1, _UFirst2, _STD move(_Val));
}
} else {
for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) {
_Val = _Reduce_op(_STD move(_Val), _Transform_op(*_UFirst1, *_UFirst2)); // Requirement missing from N4713
}
return _Val;
}
}

Expand Down
4 changes: 2 additions & 2 deletions stl/inc/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -1949,10 +1949,10 @@ template <class _Ty, enable_if_t<is_move_constructible_v<_Ty> && is_move_assigna
#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv
template <class _Ty, int _Enabled = 0>
#endif // _HAS_CXX17
void swap(_Ty&, _Ty&) noexcept(is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>);
_CONSTEXPR20 void swap(_Ty&, _Ty&) noexcept(is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>);

template <class _Ty, size_t _Size, enable_if_t<_Is_swappable<_Ty>::value, int> = 0>
void swap(_Ty (&)[_Size], _Ty (&)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value);
_CONSTEXPR20 void swap(_Ty (&)[_Size], _Ty (&)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value);

// STRUCT TEMPLATE _Swappable_with_helper
template <class _Ty1, class _Ty2, class = void>
Expand Down
10 changes: 5 additions & 5 deletions stl/inc/utility
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ _Post_equal_to_(_Left < _Right ? _Right : _Left) constexpr const _Ty& _Max_value

// FUNCTION TEMPLATE iter_swap (from <algorithm>)
template <class _FwdIt1, class _FwdIt2>
void iter_swap(_FwdIt1 _Left, _FwdIt2 _Right) { // swap *_Left and *_Right
_CONSTEXPR20 void iter_swap(_FwdIt1 _Left, _FwdIt2 _Right) { // swap *_Left and *_Right
swap(*_Left, *_Right);
}

// FUNCTION TEMPLATE swap
template <class _Ty, size_t _Size, enable_if_t<_Is_swappable<_Ty>::value, int> _Enabled>
void swap(_Ty (&_Left)[_Size], _Ty (&_Right)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value) {
_CONSTEXPR20 void swap(_Ty (&_Left)[_Size], _Ty (&_Right)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value) {
if (&_Left != &_Right) {
_Ty* _First1 = _Left;
_Ty* _Last1 = _First1 + _Size;
Expand All @@ -61,15 +61,15 @@ template <class _Ty, enable_if_t<is_move_constructible_v<_Ty> && is_move_assigna
#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv
template <class _Ty, int _Enabled>
#endif // _HAS_CXX17
void swap(_Ty& _Left, _Ty& _Right) noexcept(is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) {
_CONSTEXPR20 void swap(_Ty& _Left, _Ty& _Right) noexcept(is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) {
_Ty _Tmp = _STD move(_Left);
_Left = _STD move(_Right);
_Right = _STD move(_Tmp);
}

// FUNCTION TEMPLATE _Swap_adl
template <class _Ty>
void _Swap_adl(_Ty& _Left, _Ty& _Right) noexcept(_Is_nothrow_swappable<_Ty>::value) {
_CONSTEXPR20 void _Swap_adl(_Ty& _Left, _Ty& _Right) noexcept(_Is_nothrow_swappable<_Ty>::value) {
swap(_Left, _Right);
}

Expand Down Expand Up @@ -566,7 +566,7 @@ _NODISCARD constexpr const _Ty2&& get(

// FUNCTION TEMPLATE exchange
template <class _Ty, class _Other = _Ty>
_Ty exchange(_Ty& _Val, _Other&& _New_val) noexcept(
_CONSTEXPR20 _Ty exchange(_Ty& _Val, _Other&& _New_val) noexcept(
conjunction_v<is_nothrow_move_constructible<_Ty>, is_nothrow_assignable<_Ty&, _Other>>) /* strengthened */ {
// assign _New_val to _Val, return previous _Val
_Ty _Old_val = static_cast<_Ty&&>(_Val);
Expand Down
6 changes: 4 additions & 2 deletions stl/inc/xmemory
Original file line number Diff line number Diff line change
Expand Up @@ -1997,7 +1997,8 @@ struct _Alloc_temporary {

// FUNCTION TEMPLATE remove
template <class _FwdIt, class _Ty>
_NODISCARD _FwdIt remove(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { // remove each matching _Val
_NODISCARD _CONSTEXPR20 _FwdIt remove(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val) {
// remove each matching _Val
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
Expand All @@ -2018,7 +2019,8 @@ _NODISCARD _FwdIt remove(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { /

// FUNCTION TEMPLATE remove_if
template <class _FwdIt, class _Pr>
_NODISCARD _FwdIt remove_if(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { // remove each satisfying _Pred
_NODISCARD _CONSTEXPR20 _FwdIt remove_if(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) {
// remove each satisfying _Pred
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
Expand Down
Loading

0 comments on commit e2c4cc8

Please sign in to comment.