mirror of
https://github.com/ETLCPP/etl.git
synced 2026-07-30 16:26:17 +08:00
Add etl::stable partition (#1466)
* Added two versions of etl::stable_partition One is O(N) time , O(N) space The other is O(Nlog(N)) time * Added partition_move * Updates to tests and documentation * Review changes * std::size -> sizeof * etl::size -> ETL_OR_STL::size * Changed index array typer to std::array --------- Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com>
This commit is contained in:
parent
55429eddd2
commit
2dabc42cbb
@ -886,6 +886,22 @@ bool none_of(TIterator begin, TIterator end, TUnaryPredicate predicate)
|
||||
**Description**
|
||||
Checks if `predicate` returns `true` for no elements in the range [`begin`, `end`).
|
||||
|
||||
## next_permutation
|
||||
```cpp
|
||||
template <typename TIterator, typename TCompare>
|
||||
ETL_CONSTEXPR14 bool next_permutation(TIterator first, TIterator last, TCompare compare)
|
||||
```
|
||||
**Description**
|
||||
Creates the range [`first`, `last`) into the next permutation.
|
||||
`compare` should return `true` if its first argument is logically less that its second.
|
||||
|
||||
**Complexity**
|
||||
O(N)
|
||||
At most N/2 swaps.
|
||||
|
||||
**Return**
|
||||
`true` if there is a next permutation.
|
||||
|
||||
## is_permutation
|
||||
|
||||
```cpp
|
||||
@ -940,6 +956,70 @@ bool is_permutation(TIterator1 begin1,
|
||||
Returns `true` if there exists a permutation of the elements in the range [`begin1`, `end1`) that makes that range equal to the second range.
|
||||
Uses `predicate` to checks elements in the range.
|
||||
|
||||
## partition
|
||||
```cpp
|
||||
ETL_CONSTEXPR14 TIterator partition(TIterator first, TIterator last, TPredicate predicate)
|
||||
```
|
||||
**Description**
|
||||
Reorders elements in a range based on a predicate.
|
||||
It moves all elements that satisfy the predicate to the front, and those that do not to the back.
|
||||
Does not guarantee to keep the original relative order.
|
||||
|
||||
**Complexity**
|
||||
O(N)
|
||||
|
||||
**Return**
|
||||
An iterator to the start of the group that do not satisfy the predicate.
|
||||
|
||||
## stable_partition
|
||||
|
||||
### In-place
|
||||
```cpp
|
||||
template <typename TIterator, typename TPredicate>
|
||||
ETL_CONSTEXPR14 TIterator stable_partition(TIterator first,
|
||||
TIterator last,
|
||||
TPredicate predicate)
|
||||
```
|
||||
**Description**
|
||||
Reorders elements in a range based on a predicate.
|
||||
It moves all elements that satisfy the predicate to the front, and those that do not to the back.
|
||||
Keeps the original relative order.
|
||||
In-place
|
||||
|
||||
**Complexity**
|
||||
Recursive function.
|
||||
O(NlogN) time.
|
||||
O(NlogN) space.
|
||||
|
||||
**Return**
|
||||
An iterator to the start of the group that do not satisfy the predicate.
|
||||
|
||||
### External buffer
|
||||
```cpp
|
||||
template <typename TIterator, typename TPredicate>
|
||||
ETL_CONSTEXPR14 TIterator stable_partition(TIterator first,
|
||||
TIterator last,
|
||||
TIterator buffer_first,
|
||||
TIterator buffer_last,
|
||||
TPredicate predicate)
|
||||
```
|
||||
**Description**
|
||||
Reorders elements in a range based on a predicate.
|
||||
It moves all elements that satisfy the predicate to the front, and those that do not to the back.
|
||||
Keeps the original relative order.
|
||||
|
||||
Requires a user supplied buffer that must be at least the same size as the range [`first`, `last`).
|
||||
|
||||
**Complexity**
|
||||
Non-recursive function.
|
||||
O(N) time.
|
||||
O(N) space.
|
||||
|
||||
Raises an `etl::stable_partition_buffer_too_small` is the buffer is not large enough to accommodate the range [`first`, `last`).
|
||||
|
||||
**Return**
|
||||
An iterator to the start of the group that do not satisfy the predicate.
|
||||
|
||||
## is_partitioned
|
||||
|
||||
```cpp
|
||||
@ -978,6 +1058,32 @@ pair<TDestinationTrue, TDestinationFalse> partition_copy(TSource begin
|
||||
Copies the elements from the range [`begin`, `end`) to two different ranges depending on the value returned by the `predicate`.
|
||||
The elements that satisfy `predicate` are copied to the range beginning at `destination_true`.
|
||||
The rest of the elements are copied to the range beginning at `destination_false`.
|
||||
This partition is stable.
|
||||
|
||||
**Complexity**
|
||||
O(N)
|
||||
|
||||
## partition_move
|
||||
|
||||
```cpp
|
||||
template <typename TSource,
|
||||
typename TDestinationTrue,
|
||||
typename TDestinationFalse,
|
||||
typename TUnaryPredicate>
|
||||
pair<TDestinationTrue, TDestinationFalse> partition_move(TSource begin,
|
||||
TSource end,
|
||||
TDestinationTrue destination_true,
|
||||
TDestinationFalse destination_false,
|
||||
TUnaryPredicate predicate)
|
||||
```
|
||||
**Description**
|
||||
Moves the elements from the range [`begin`, `end`) to two different ranges depending on the value returned by the `predicate`.
|
||||
The elements that satisfy `predicate` are moved to the range beginning at `destination_true`.
|
||||
The rest of the elements are moved to the range beginning at `destination_false`.
|
||||
This partition is stable.
|
||||
|
||||
**Complexity**
|
||||
O(N)
|
||||
|
||||
## partition_transform
|
||||
**ETL extension**
|
||||
@ -1000,9 +1106,10 @@ pair<TDestinationTrue, TDestinationFalse>
|
||||
TUnaryPredicate predicate)
|
||||
```
|
||||
**Description**
|
||||
Transforms data from the source to one of two destinations.
|
||||
If `predicate` returns `true` then the source data if modified by `function_true` and stored in `destination_true`.
|
||||
If `predicate` returns `false` then the source data if modified by `function_false` and stored in `destination_false`.
|
||||
Transforms and copies data from the source to one of two destinations.
|
||||
If `predicate` returns `true` then the source data is modified by `function_true` and stored in `destination_true`.
|
||||
If `predicate` returns `false` then the source data is modified by `function_false` and stored in `destination_false`.
|
||||
This partition is stable.
|
||||
|
||||
---
|
||||
|
||||
@ -1026,9 +1133,10 @@ pair<TDestinationTrue, TDestinationFalse>
|
||||
TBinaryPredicate predicate)
|
||||
```
|
||||
**Description**
|
||||
Transforms data from the source to one of two destinations.
|
||||
If `predicate` returns `true` then the source data if modified by `function_true` and stored in `destination_true`.
|
||||
If `predicate` returns `false` then the source data if modified by `function_false` and stored in `destination_false`.
|
||||
Transforms and copies data from the source to one of two destinations.
|
||||
If `predicate` returns `true` then the source data is modified by `function_true` and stored in `destination_true`.
|
||||
If `predicate` returns `false` then the source data is modified by `function_false` and stored in `destination_false`.
|
||||
This partition is stable.
|
||||
|
||||
## rotate
|
||||
|
||||
@ -1107,7 +1215,7 @@ TOutputIterator transform_if(TInputIterator i_begin,
|
||||
```
|
||||
**Description**
|
||||
Transforms data from the source based on a predicate.
|
||||
If `predicate` returns `true` then the source data if modified by function and stored in the output range.
|
||||
If `predicate` returns `true` then the source data is modified by `function` and stored in the output range.
|
||||
If `predicate` returns `false` then the source data is ignored.
|
||||
|
||||
---
|
||||
@ -1128,7 +1236,7 @@ TOutputIterator transform_if(TInputIterator1 i_begin1,
|
||||
```
|
||||
**Description**
|
||||
Transforms data from the source based on a predicate.
|
||||
If `predicate` returns `true` then the source data if modified by function and stored in the output range.
|
||||
If `predicate` returns `true` then the source data is modified by `function` and stored in the output range.
|
||||
If `predicate` returns `false` then the source data is ignored.
|
||||
|
||||
## transform_n_if
|
||||
@ -1149,7 +1257,7 @@ TOutputIterator transform_if(TInputIterator i_begin,
|
||||
```
|
||||
**Description**
|
||||
Transforms data from the source based on a predicate for `n` items.
|
||||
If `predicate` returns `true` then the source data if modified by function and stored in the output range.
|
||||
If `predicate` returns `true` then the source data is modified by `function` and stored in the output range.
|
||||
If `predicate` returns `false` then the source data is ignored.
|
||||
|
||||
---
|
||||
@ -1171,7 +1279,7 @@ TOutputIterator transform_if(TInputIterator1 i_begin1,
|
||||
```
|
||||
**Description**
|
||||
Transforms data from the source based on a predicate for `n` items.
|
||||
If `predicate` returns `true` then the source data if modified by function and stored in the output range.
|
||||
If `predicate` returns `true` then the source data is modified by `function` and stored in the output range.
|
||||
If `predicate` returns `false` then the source data is ignored.
|
||||
|
||||
## shell_sort
|
||||
|
||||
@ -98,6 +98,22 @@ namespace etl
|
||||
//*****************************************************************************
|
||||
namespace etl
|
||||
{
|
||||
struct stable_partition_exception : etl::exception
|
||||
{
|
||||
stable_partition_exception(string_type reason_, string_type file_, numeric_type line_)
|
||||
: etl::exception(reason_, file_, line_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct stable_partition_buffer_too_small : stable_partition_exception
|
||||
{
|
||||
stable_partition_buffer_too_small(string_type file_, numeric_type line_)
|
||||
: stable_partition_exception(ETL_ERROR_TEXT("stable_partition:buffer too small", ETL_ALGORITHM_FILE_ID"A"), file_, line_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
namespace private_algorithm
|
||||
{
|
||||
template <bool use_swap>
|
||||
@ -2116,6 +2132,34 @@ namespace etl
|
||||
return ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Moves the elements from the range (begin, end) to two different ranges
|
||||
/// depending on the value returned by the predicate.<br>
|
||||
///\ingroup algorithm
|
||||
//***************************************************************************
|
||||
template <typename TSource, typename TDestinationTrue, typename TDestinationFalse, typename TUnaryPredicate>
|
||||
ETL_CONSTEXPR14 ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse> partition_move(TSource begin, TSource end, TDestinationTrue destination_true,
|
||||
TDestinationFalse destination_false, TUnaryPredicate predicate)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (predicate(*begin))
|
||||
{
|
||||
*destination_true = etl::move(*begin);
|
||||
++destination_true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*destination_false = etl::move(*begin);
|
||||
++destination_false;
|
||||
}
|
||||
|
||||
++begin;
|
||||
}
|
||||
|
||||
return ETL_OR_STD::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// copy_if
|
||||
///\ingroup algorithm
|
||||
@ -3058,7 +3102,7 @@ namespace etl
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Transforms the elements from the range (begin, end) to two different
|
||||
/// Transforms and copies the elements from the range (begin, end) to two different
|
||||
/// ranges depending on the value returned by the predicate.<br>
|
||||
///\ingroup algorithm
|
||||
//***************************************************************************
|
||||
@ -3088,7 +3132,7 @@ namespace etl
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Transforms the elements from the ranges (begin1, end1) & (begin2)
|
||||
/// Transforms and copies the elements from the ranges (begin1, end1) & (begin2)
|
||||
/// to two different ranges depending on the value returned by the predicate.
|
||||
///\ingroup algorithm
|
||||
//***************************************************************************
|
||||
@ -3531,6 +3575,85 @@ namespace etl
|
||||
return first;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// stable_partition
|
||||
/// O(NlogN) time.
|
||||
/// In-place.
|
||||
//***************************************************************************
|
||||
template <typename TIterator, typename TPredicate>
|
||||
ETL_CONSTEXPR14 TIterator stable_partition(TIterator first, TIterator last, TPredicate predicate)
|
||||
{
|
||||
typename etl::iterator_traits<TIterator>::difference_type n = etl::distance(first, last);
|
||||
|
||||
if (n <= 1)
|
||||
{
|
||||
// Empty or single-element range: trivially partitioned either way.
|
||||
return first;
|
||||
}
|
||||
|
||||
TIterator mid = first;
|
||||
etl::advance(mid, n / 2);
|
||||
|
||||
etl::stable_partition(first, mid, predicate);
|
||||
etl::stable_partition(mid, last, predicate);
|
||||
|
||||
TIterator left_partition_start = etl::find_if_not(first, last, predicate);
|
||||
TIterator right_partition_start = etl::find_if(left_partition_start, last, predicate);
|
||||
TIterator right_partition_end = etl::find_if_not(right_partition_start, last, predicate);
|
||||
|
||||
return etl::rotate(left_partition_start, right_partition_start, right_partition_end);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// stable_partition
|
||||
/// O(N) time.
|
||||
/// O(N) extra space.
|
||||
//***************************************************************************
|
||||
template <typename TIterator, typename TPredicate>
|
||||
ETL_CONSTEXPR14 TIterator stable_partition(TIterator first, TIterator last, TIterator buffer_first, TIterator buffer_last, TPredicate predicate)
|
||||
{
|
||||
typename etl::iterator_traits<TIterator>::difference_type n = etl::distance(first, last);
|
||||
|
||||
ETL_ASSERT((n <= etl::distance(buffer_first, buffer_last)), ETL_ERROR(stable_partition_buffer_too_small));
|
||||
|
||||
if (n <= 1)
|
||||
{
|
||||
// Empty or single-element range.
|
||||
return first;
|
||||
}
|
||||
|
||||
TIterator input_first = first;
|
||||
TIterator buffer_true = buffer_first;
|
||||
|
||||
// Find where the partition point will be in the buffer.
|
||||
typename etl::iterator_traits<TIterator>::difference_type true_count = etl::count_if(first, last, predicate);
|
||||
TIterator buffer_false = buffer_first + true_count;
|
||||
|
||||
// Move them to the correct places in the temporary buffer.
|
||||
while (first != last)
|
||||
{
|
||||
if (predicate(*first))
|
||||
{
|
||||
*buffer_true++ = etl::move(*first);
|
||||
}
|
||||
else
|
||||
{
|
||||
*buffer_false++ = etl::move(*first);
|
||||
}
|
||||
|
||||
++first;
|
||||
}
|
||||
|
||||
// Move them back to the original range.
|
||||
TIterator buffer_end = buffer_first;
|
||||
etl::advance(buffer_end, n);
|
||||
etl::move(buffer_first, buffer_end, input_first);
|
||||
|
||||
etl::advance(input_first, true_count);
|
||||
|
||||
return input_first;
|
||||
}
|
||||
|
||||
//*********************************************************
|
||||
namespace private_algorithm
|
||||
{
|
||||
|
||||
@ -2853,18 +2853,78 @@ namespace
|
||||
int data4[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int data5[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
std::partition_copy(std::begin(data1), std::end(data1), std::begin(data2), std::begin(data3),
|
||||
std::bind(std::greater<int>(), std::placeholders::_1, 4));
|
||||
etl::partition_copy(std::begin(data1), std::end(data1), std::begin(data4), std::begin(data5),
|
||||
std::bind(std::greater<int>(), std::placeholders::_1, 4));
|
||||
bool complete = false;
|
||||
|
||||
bool are_equal;
|
||||
while (!complete)
|
||||
{
|
||||
std::partition_copy(std::begin(data1), std::end(data1), std::begin(data2), std::begin(data3),
|
||||
std::bind(std::greater<int>(), std::placeholders::_1, 4));
|
||||
etl::partition_copy(std::begin(data1), std::end(data1), std::begin(data4), std::begin(data5),
|
||||
std::bind(std::greater<int>(), std::placeholders::_1, 4));
|
||||
|
||||
are_equal = std::equal(std::begin(data2), std::end(data2), std::begin(data4));
|
||||
CHECK(are_equal);
|
||||
bool are_equal;
|
||||
|
||||
are_equal = std::equal(std::begin(data3), std::end(data3), std::begin(data5));
|
||||
CHECK(are_equal);
|
||||
are_equal = std::equal(std::begin(data2), std::end(data2), std::begin(data4));
|
||||
CHECK(are_equal);
|
||||
|
||||
are_equal = std::equal(std::begin(data3), std::end(data3), std::begin(data5));
|
||||
CHECK(are_equal);
|
||||
|
||||
complete = !std::next_permutation(std::begin(data1), std::end(data1));
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(partition_move)
|
||||
{
|
||||
std::array<int, 8> indexes = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
TestDataM<int> std_input[] = {TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0),
|
||||
TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0)};
|
||||
TestDataM<int> etl_input[] = {TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0),
|
||||
TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0)};
|
||||
TestDataM<int> std_true[] = {TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0),
|
||||
TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0)};
|
||||
TestDataM<int> std_false[] = {TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0),
|
||||
TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0)};
|
||||
TestDataM<int> etl_true[] = {TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0),
|
||||
TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0)};
|
||||
TestDataM<int> etl_false[] = {TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0),
|
||||
TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0)};
|
||||
|
||||
auto compare = [](const TestDataM<int>& element)
|
||||
{
|
||||
return (element.value > 4);
|
||||
};
|
||||
|
||||
bool complete = false;
|
||||
|
||||
while (!complete)
|
||||
{
|
||||
// Rebuild the input arrays.
|
||||
for (size_t i = 0; i < indexes.size(); ++i)
|
||||
{
|
||||
std_input[i].value = indexes[i];
|
||||
etl_input[i].value = indexes[i];
|
||||
}
|
||||
|
||||
// Simulate what etl::partition_move should do using stable_partition and move.
|
||||
auto boundary = std::stable_partition(std::begin(std_input), std::end(std_input), compare);
|
||||
std::move(std::begin(std_input), boundary, std::begin(std_true));
|
||||
std::move(boundary, std::end(std_input), std::begin(std_false));
|
||||
|
||||
// Execute etl::partition_move.
|
||||
etl::partition_move(std::begin(etl_input), std::end(etl_input), std::begin(etl_true), std::begin(etl_false), compare);
|
||||
bool are_equal;
|
||||
|
||||
are_equal = std::equal(std::begin(std_true), std::end(std_true), std::begin(etl_true));
|
||||
CHECK(are_equal);
|
||||
|
||||
are_equal = std::equal(std::begin(std_false), std::end(std_false), std::begin(etl_false));
|
||||
CHECK(are_equal);
|
||||
|
||||
complete = !std::next_permutation(std::begin(indexes), std::end(indexes));
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -4291,6 +4351,181 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(stable_partition_in_place_bidirectional_iterator_container)
|
||||
{
|
||||
// 40,320 permutations.
|
||||
std::array<int, 8> initial_data = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
std::array<int, 8> std_data = initial_data;
|
||||
std::array<int, 8> etl_data = initial_data;
|
||||
|
||||
bool complete = false;
|
||||
|
||||
while (!complete)
|
||||
{
|
||||
auto std_pivot = std::stable_partition(std_data.begin(), std_data.end(), [](int i) { return etl::is_even(i); });
|
||||
auto etl_pivot = etl::stable_partition(etl_data.begin(), etl_data.end(), [](int i) { return etl::is_even(i); });
|
||||
|
||||
auto std_distance = std::distance(std_data.begin(), std_pivot);
|
||||
auto etl_distance = std::distance(etl_data.begin(), etl_pivot);
|
||||
|
||||
CHECK_EQUAL(*std_pivot, *etl_pivot);
|
||||
CHECK_EQUAL(std_distance, etl_distance);
|
||||
|
||||
for (auto itr = std_data.begin(); itr != std_pivot; ++itr)
|
||||
{
|
||||
CHECK_TRUE((etl::is_even(*itr)));
|
||||
}
|
||||
|
||||
for (auto itr = std_pivot; itr != std_data.end(); ++itr)
|
||||
{
|
||||
CHECK_FALSE((etl::is_even(*itr)));
|
||||
}
|
||||
|
||||
complete = !std::next_permutation(initial_data.begin(), initial_data.end());
|
||||
|
||||
std_data = initial_data;
|
||||
etl_data = initial_data;
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(stable_partition_in_place_bidirectional_iterator_container_for_move_only_elements)
|
||||
{
|
||||
// 40,320 permutations.
|
||||
std::array<TestDataM<int>, 8> initial_data = {TestDataM<int>(0), TestDataM<int>(1), TestDataM<int>(2), TestDataM<int>(3),
|
||||
TestDataM<int>(4), TestDataM<int>(5), TestDataM<int>(6), TestDataM<int>(7)};
|
||||
|
||||
std::array<TestDataM<int>, 8> std_data = std::move(initial_data);
|
||||
std::array<TestDataM<int>, 8> etl_data = std::move(initial_data);
|
||||
|
||||
bool complete = false;
|
||||
|
||||
while (!complete)
|
||||
{
|
||||
auto std_pivot = std::stable_partition(std_data.begin(), std_data.end(), [](const TestDataM<int>& t) { return etl::is_even(t.value); });
|
||||
auto etl_pivot = etl::stable_partition(etl_data.begin(), etl_data.end(), [](const TestDataM<int>& t) { return etl::is_even(t.value); });
|
||||
|
||||
auto std_distance = std::distance(std_data.begin(), std_pivot);
|
||||
auto etl_distance = std::distance(etl_data.begin(), etl_pivot);
|
||||
|
||||
CHECK_EQUAL(*std_pivot, *etl_pivot);
|
||||
CHECK_EQUAL(std_distance, etl_distance);
|
||||
|
||||
for (auto itr = std_data.begin(); itr != std_pivot; ++itr)
|
||||
{
|
||||
CHECK_TRUE((etl::is_even(itr->value)));
|
||||
}
|
||||
|
||||
for (auto itr = std_pivot; itr != std_data.end(); ++itr)
|
||||
{
|
||||
CHECK_FALSE((etl::is_even(itr->value)));
|
||||
}
|
||||
|
||||
complete = !std::next_permutation(initial_data.begin(), initial_data.end());
|
||||
|
||||
std_data = std::move(initial_data);
|
||||
etl_data = std::move(initial_data);
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(stable_partition_external_buffer_bidirectional_iterator_container)
|
||||
{
|
||||
// 40,320 permutations.
|
||||
std::array<int, 8> initial_data = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
std::array<int, 8> buffer = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
std::array<int, 8> std_data = initial_data;
|
||||
std::array<int, 8> etl_data = initial_data;
|
||||
|
||||
bool complete = false;
|
||||
|
||||
while (!complete)
|
||||
{
|
||||
auto std_pivot = std::stable_partition(std_data.begin(), std_data.end(), [](int i) { return etl::is_even(i); });
|
||||
auto etl_pivot = etl::stable_partition(etl_data.begin(), etl_data.end(), buffer.begin(), buffer.end(), [](int i) { return etl::is_even(i); });
|
||||
|
||||
auto std_distance = std::distance(std_data.begin(), std_pivot);
|
||||
auto etl_distance = std::distance(etl_data.begin(), etl_pivot);
|
||||
|
||||
CHECK_EQUAL(*std_pivot, *etl_pivot);
|
||||
CHECK_EQUAL(std_distance, etl_distance);
|
||||
|
||||
for (auto itr = std_data.begin(); itr != std_pivot; ++itr)
|
||||
{
|
||||
CHECK_TRUE((etl::is_even(*itr)));
|
||||
}
|
||||
|
||||
for (auto itr = std_pivot; itr != std_data.end(); ++itr)
|
||||
{
|
||||
CHECK_FALSE((etl::is_even(*itr)));
|
||||
}
|
||||
|
||||
complete = !std::next_permutation(initial_data.begin(), initial_data.end());
|
||||
|
||||
std_data = initial_data;
|
||||
etl_data = initial_data;
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(stable_partition_external_buffer_bidirectional_iterator_container_for_move_only_elements)
|
||||
{
|
||||
// 40,320 permutations.
|
||||
std::array<TestDataM<int>, 8> initial_data = {TestDataM<int>(0), TestDataM<int>(1), TestDataM<int>(2), TestDataM<int>(3),
|
||||
TestDataM<int>(4), TestDataM<int>(5), TestDataM<int>(6), TestDataM<int>(7)};
|
||||
|
||||
std::array<TestDataM<int>, 8> buffer = {TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0),
|
||||
TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0), TestDataM<int>(0)};
|
||||
|
||||
std::array<TestDataM<int>, 8> std_data = std::move(initial_data);
|
||||
std::array<TestDataM<int>, 8> etl_data = std::move(initial_data);
|
||||
|
||||
bool complete = false;
|
||||
|
||||
while (!complete)
|
||||
{
|
||||
auto std_pivot = std::stable_partition(std_data.begin(), std_data.end(), [](const TestDataM<int>& t) { return etl::is_even(t.value); });
|
||||
auto etl_pivot = etl::stable_partition(etl_data.begin(), etl_data.end(), buffer.begin(), buffer.end(),
|
||||
[](const TestDataM<int>& t) { return etl::is_even(t.value); });
|
||||
|
||||
auto std_distance = std::distance(std_data.begin(), std_pivot);
|
||||
auto etl_distance = std::distance(etl_data.begin(), etl_pivot);
|
||||
|
||||
CHECK_EQUAL(std_pivot->value, etl_pivot->value);
|
||||
CHECK_EQUAL(std_distance, etl_distance);
|
||||
|
||||
for (auto itr = std_data.begin(); itr != std_pivot; ++itr)
|
||||
{
|
||||
CHECK_TRUE((etl::is_even(itr->value)));
|
||||
}
|
||||
|
||||
for (auto itr = std_pivot; itr != std_data.end(); ++itr)
|
||||
{
|
||||
CHECK_FALSE((etl::is_even(itr->value)));
|
||||
}
|
||||
|
||||
complete = !std::next_permutation(initial_data.begin(), initial_data.end());
|
||||
|
||||
std_data = std::move(initial_data);
|
||||
etl_data = std::move(initial_data);
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(stable_partition_external_buffer_too_small)
|
||||
{
|
||||
int buffer[7];
|
||||
int etl_data[8];
|
||||
|
||||
CHECK_THROW((etl::stable_partition(std::begin(etl_data), std::end(etl_data), std::begin(buffer), std::end(buffer),
|
||||
[](int i) { return etl::is_even(i); })),
|
||||
etl::stable_partition_buffer_too_small);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(nth_element_with_default_less_than_comparison)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user