Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6121bfe
Implement ranges::stable_partition
miscco Oct 19, 2020
d6a06d1
Implement ranges::inplace_merge
miscco Oct 19, 2020
d343edd
Move some helper functions around
miscco Oct 20, 2020
a520190
Implement ranges::stable_sort
miscco Oct 21, 2020
946d77e
Do not require nodiscard on _Uninitialized_move_unchecked
miscco Oct 23, 2020
84aeed5
Apply Caseys comments
miscco Nov 4, 2020
1518b32
Don't move the results of _Pass_fn
CaseyCarter Nov 5, 2020
4742ffe
More review comments
miscco Nov 4, 2020
60daf31
More review suggestions
miscco Nov 5, 2020
5c74fdb
Move _Is_sorted_until_unchecked
miscco Nov 5, 2020
c43c4a2
Even more review comments
miscco Nov 5, 2020
68b6544
Fix bad verify
miscco Nov 6, 2020
e5eb7e8
Derp
miscco Nov 8, 2020
b12b585
Use _Rotate_unchecked rather than rotate
miscco Nov 8, 2020
ab7560e
Merge branch 'master' into ranges_stable_partition
miscco Nov 17, 2020
dacbea2
Fix breakage
miscco Nov 19, 2020
8413ab5
Merge branch 'master' into ranges_stable_partition
miscco Nov 19, 2020
6b4d68b
Merge remote-tracking branch 'origin/master' into alloc
CaseyCarter Dec 4, 2020
6b313c6
Merge branch 'master' into ranges_stable_partition
miscco Jan 6, 2021
615a7b7
Merge remote-tracking branch 'origin/master' into alloc
CaseyCarter Jan 20, 2021
464e393
Some ranges::stable_sort cleanup:
CaseyCarter Jan 22, 2021
263c9c1
Apply suggestions from code review
CaseyCarter Jan 25, 2021
6e0a595
Simple code review feedback.
StephanTLavavej Jan 26, 2021
8bc2d18
Review comments again:
CaseyCarter Jan 26, 2021
9e178a2
Apply suggestions from code review
CaseyCarter Jan 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,131 changes: 958 additions & 173 deletions stl/inc/algorithm

Large diffs are not rendered by default.

23 changes: 11 additions & 12 deletions stl/inc/execution
Original file line number Diff line number Diff line change
Expand Up @@ -2665,24 +2665,23 @@ bool _Process_sort_work_item(const _RanIt _Basis, _Pr _Pred, _Sort_work_item<_Ra
// the return value is false
// _Wi's range is completely sorted
// _Right_fork_wi is unmodified
using _Diff = _Iter_diff_t<_RanIt>;
constexpr auto _Diffsort_max = static_cast<_Diff>(_ISORT_MAX);
const auto _Size = _Wi._Size;
const auto _First = _Basis + _Wi._Offset;
const auto _Last = _First + _Size;
const auto _Ideal = _Wi._Ideal;
if (_Size <= _Diffsort_max) {
const auto _Size = _Wi._Size;
const auto _First = _Basis + _Wi._Offset;
const auto _Last = _First + _Size;
const auto _Ideal = _Wi._Ideal;
if (_Size <= _Isort_max<_RanIt>) {
_Insertion_sort_unchecked(_First, _Last, _Pred);
_Work_complete += _Size;
return false;
}

if (0 < _Ideal) { // divide and conquer by partitioning (quicksort)
const auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred);
const auto _New_ideal = static_cast<_Diff>(_Ideal / 2 + _Ideal / 4); // allow 1.5 log2(N) divisions
_Wi._Size = _Mid.first - _First;
_Wi._Ideal = _New_ideal;
_Right_fork_wi = {_Mid.second - _Basis, _Last - _Mid.second, _New_ideal};
const auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred);
const auto _New_ideal =
static_cast<_Iter_diff_t<_RanIt>>(_Ideal / 2 + _Ideal / 4); // allow 1.5 log2(N) divisions
_Wi._Size = _Mid.first - _First;
_Wi._Ideal = _New_ideal;
_Right_fork_wi = {_Mid.second - _Basis, _Last - _Mid.second, _New_ideal};
_Work_complete += _Mid.second - _Mid.first;
return true;
}
Expand Down
64 changes: 4 additions & 60 deletions stl/inc/memory
Original file line number Diff line number Diff line change
Expand Up @@ -28,35 +28,6 @@ _STL_DISABLE_CLANG_WARNINGS
_STD_BEGIN
#ifdef __cpp_lib_concepts
namespace ranges {
// clang-format off
// CONCEPT _No_throw_input_iterator
template <class _It>
concept _No_throw_input_iterator = input_iterator<_It>
&& is_lvalue_reference_v<iter_reference_t<_It>>
&& same_as<remove_cvref_t<iter_reference_t<_It>>, iter_value_t<_It>>;

// CONCEPT _No_throw_sentinel_for
template <class _Se, class _It>
concept _No_throw_sentinel_for = sentinel_for<_Se, _It>;

// CONCEPT _No_throw_forward_iterator
template <class _It>
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 <class _Rng>
concept _No_throw_input_range = range<_Rng>
&& _No_throw_input_iterator<iterator_t<_Rng>>
&& _No_throw_sentinel_for<sentinel_t<_Rng>, iterator_t<_Rng>>;

// CONCEPT _No_throw_forward_range
template <class _Rng>
concept _No_throw_forward_range = _No_throw_input_range<_Rng>
&& _No_throw_forward_iterator<iterator_t<_Rng>>;
// clang-format on

// ALIAS TEMPLATE uninitialized_copy_result
template <class _In, class _Out>
using uninitialized_copy_result = in_out_result<_In, _Out>;
Expand Down Expand Up @@ -214,10 +185,6 @@ _NoThrowFwdIt uninitialized_move(const _InIt _First, const _InIt _Last, _NoThrow

#ifdef __cpp_lib_concepts
namespace ranges {
// ALIAS TEMPLATE uninitialized_move_result
template <class _In, class _Out>
using uninitialized_move_result = in_out_result<_In, _Out>;

// VARIABLE ranges::uninitialized_move
class _Uninitialized_move_fn : private _Not_quite_object {
public:
Expand All @@ -231,9 +198,9 @@ namespace ranges {
// 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)));
auto _UResult = _RANGES _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));
Expand All @@ -247,35 +214,12 @@ namespace ranges {
_Rng1&& _Range1, _Rng2&& _Range2) const {
// clang-format on
auto _First1 = _RANGES begin(_Range1);
auto _UResult = _Uninitialized_move_unchecked(
auto _UResult = _RANGES _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 <class _It, class _Se, class _Out, class _OSe>
_NODISCARD static uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked(
_It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) {
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>);
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>);
_STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_Out>);
_STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>);
_STL_INTERNAL_STATIC_ASSERT(constructible_from<iter_value_t<_Out>, iter_rvalue_reference_t<_It>>);

if constexpr (is_same_v<_Se, _It> && _Ptr_move_cat<_It, _Out>::_Really_trivial) {
return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast);
} else {
_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{}};
Expand Down
58 changes: 58 additions & 0 deletions stl/inc/xmemory
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,64 @@ _NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _InIt _Last, _No
}
}

#ifdef __cpp_lib_concepts
namespace ranges {
// clang-format off
// CONCEPT _No_throw_input_iterator
template <class _It>
concept _No_throw_input_iterator = input_iterator<_It>
&& is_lvalue_reference_v<iter_reference_t<_It>>
&& same_as<remove_cvref_t<iter_reference_t<_It>>, iter_value_t<_It>>;

// CONCEPT _No_throw_sentinel_for
template <class _Se, class _It>
concept _No_throw_sentinel_for = sentinel_for<_Se, _It>;

// CONCEPT _No_throw_forward_iterator
template <class _It>
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 <class _Rng>
concept _No_throw_input_range = range<_Rng>
&& _No_throw_input_iterator<iterator_t<_Rng>>
&& _No_throw_sentinel_for<sentinel_t<_Rng>, iterator_t<_Rng>>;

// CONCEPT _No_throw_forward_range
template <class _Rng>
concept _No_throw_forward_range = _No_throw_input_range<_Rng>
&& _No_throw_forward_iterator<iterator_t<_Rng>>;
// clang-format on

// ALIAS TEMPLATE uninitialized_move_result
template <class _In, class _Out>
using uninitialized_move_result = in_out_result<_In, _Out>;

// FUNCTION TEMPLATE _Uninitialized_move_unchecked
// clang-format off
template <input_iterator _It, sentinel_for<_It> _Se, _No_throw_forward_iterator _Out,
_No_throw_sentinel_for<_Out> _OSe>
requires constructible_from<iter_value_t<_Out>, iter_rvalue_reference_t<_It>>
uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked(
_It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) {
// clang-format on
if constexpr (is_same_v<_Se, _It> && _Ptr_move_cat<_It, _Out>::_Really_trivial) {
return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast);
} else {
_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()};
}
}
} // namespace ranges
#endif // __cpp_lib_concepts

// STRUCT TEMPLATE _Uninitialized_backout_al
template <class _Alloc>
class _NODISCARD _Uninitialized_backout_al {
Expand Down
3 changes: 3 additions & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ tests\P0896R4_ranges_alg_generate
tests\P0896R4_ranges_alg_generate_n
tests\P0896R4_ranges_alg_heap
tests\P0896R4_ranges_alg_includes
tests\P0896R4_ranges_alg_inplace_merge
tests\P0896R4_ranges_alg_is_permutation
tests\P0896R4_ranges_alg_is_sorted
tests\P0896R4_ranges_alg_lexicographical_compare
Expand Down Expand Up @@ -324,6 +325,8 @@ 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_stable_partition
tests\P0896R4_ranges_alg_stable_sort
tests\P0896R4_ranges_alg_swap_ranges
tests\P0896R4_ranges_alg_transform_binary
tests\P0896R4_ranges_alg_transform_unary
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_inplace_merge/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\concepts_matrix.lst
60 changes: 60 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_inplace_merge/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
#include <cassert>
#include <concepts>
#include <ranges>
#include <utility>

#include <range_algorithm_support.hpp>

using namespace std;
using P = pair<int, int>;
// Validate dangling story
STATIC_ASSERT(same_as<decltype(ranges::inplace_merge(borrowed<false>{}, nullptr_to<int>)), ranges::dangling>);
STATIC_ASSERT(same_as<decltype(ranges::inplace_merge(borrowed<true>{}, nullptr_to<int>)), int*>);

struct instantiator {
static constexpr P expected[] = {P{0, 1}, P{0, 5}, P{4, 2}, P{4, 6}, P{6, 7}, P{7, 3}, P{8, 4}, P{9, 8}, P{10, 9}};

template <ranges::bidirectional_range Range>
static void call() {
using ranges::equal, ranges::is_sorted, ranges::iterator_t, ranges::inplace_merge;

{ // Validate range overload
P input[] = {P{0, 1}, P{4, 2}, P{7, 3}, P{8, 4}, P{0, 5}, P{4, 6}, P{6, 7}, P{9, 8}, P{10, 9}};
Range range{input};
const auto mid = ranges::next(range.begin(), 4);
const same_as<iterator_t<Range>> auto result = inplace_merge(range, mid, ranges::less{}, get_first);
assert(result == range.end());
assert(equal(input, expected));

// Validate empty range
const Range empty_range{};
const same_as<iterator_t<Range>> auto empty_result =
inplace_merge(empty_range, empty_range.begin(), ranges::less{}, get_first);
assert(empty_result == empty_range.begin());
}

{ // Validate iterator overload
P input[] = {P{0, 1}, P{4, 2}, P{7, 3}, P{8, 4}, P{0, 5}, P{4, 6}, P{6, 7}, P{9, 8}, P{10, 9}};
Range range{input};
const auto mid = ranges::next(range.begin(), 4);
const same_as<iterator_t<Range>> auto result =
inplace_merge(range.begin(), mid, range.end(), ranges::less{}, get_first);
assert(result == range.end());
assert(equal(input, expected));

// Validate empty range
const Range empty_range{};
const same_as<iterator_t<Range>> auto empty_result =
inplace_merge(empty_range.begin(), empty_range.begin(), empty_range.end(), ranges::less{}, get_first);
assert(empty_result == empty_range.end());
}
}
};

int main() {
test_bidi<instantiator, P>();
}
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_stable_partition/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\concepts_matrix.lst
67 changes: 67 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_stable_partition/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
#include <cassert>
#include <concepts>
#include <ranges>
#include <utility>

#include <range_algorithm_support.hpp>

using namespace std;
using P = pair<int, int>;

constexpr auto is_even = [](int i) { return i % 2 == 0; };

// Validate dangling story
STATIC_ASSERT(same_as<decltype(ranges::stable_partition(borrowed<false>{}, is_even)), ranges::dangling>);
STATIC_ASSERT(same_as<decltype(ranges::stable_partition(borrowed<true>{}, is_even)), ranges::subrange<int*>>);

struct instantiator {
template <ranges::bidirectional_range Range>
static void call() {
using ranges::is_partitioned, ranges::is_sorted, ranges::iterator_t, ranges::stable_partition, ranges::subrange;

{ // Validate range overload
P input[] = {P{0, 1}, P{1, 2}, P{0, 3}, P{1, 4}, P{0, 5}, P{1, 6}, P{0, 7}, P{1, 8}};
Range range{input};
const auto mid = ranges::next(range.begin(), 4);
const same_as<subrange<iterator_t<Range>>> auto result = stable_partition(range, is_even, get_first);
assert(result.begin() == mid);
assert(result.end() == range.end());
assert(is_partitioned(range, is_even, get_first));
assert(is_sorted(range));

// Validate empty range
const Range empty_range{};
const same_as<subrange<iterator_t<Range>>> auto empty_result =
stable_partition(empty_range, is_even, get_first);
assert(empty_result.begin() == empty_range.end());
assert(empty_result.end() == empty_range.end());
}

{ // Validate iterator overload
P input[] = {P{0, 1}, P{1, 2}, P{0, 3}, P{1, 4}, P{0, 5}, P{1, 6}, P{0, 7}, P{1, 8}};
Range range{input};
const auto mid = ranges::next(range.begin(), 4);
const same_as<subrange<iterator_t<Range>>> auto result =
stable_partition(range.begin(), range.end(), is_even, get_first);
assert(result.begin() == mid);
assert(result.end() == range.end());
assert(is_partitioned(range, is_even, get_first));
assert(is_sorted(range));

// Validate empty range
const Range empty_range{};
const same_as<subrange<iterator_t<Range>>> auto empty_result =
stable_partition(empty_range.begin(), empty_range.end(), is_even, get_first);
assert(empty_result.begin() == empty_range.end());
assert(empty_result.end() == empty_range.end());
}
}
};

int main() {
test_bidi<instantiator, P>();
}
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_stable_sort/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\concepts_matrix.lst
Loading