add a range trait to check swappability for range elements
parent
c6697c9ff4
commit
dbbef8c7ac
|
@ -23,8 +23,8 @@ namespace ostd {
|
|||
* Given a predicate `pred`, this rearranges the range so that items for
|
||||
* which the predicate returns true are in the first part of the range.
|
||||
*
|
||||
* The range must be at least ostd::forward_range_tag. The items are swapped,
|
||||
* which means the range's reference type must be swappable.
|
||||
* The range must be at least ostd::forward_range_tag. The range must also
|
||||
* meet the conditions of ostd::is_range_element_swappable.
|
||||
*
|
||||
* The predicate is applied `N` times and the swap is done at most `N` times.
|
||||
*
|
||||
|
@ -32,6 +32,10 @@ namespace ostd {
|
|||
*/
|
||||
template<typename R, typename U>
|
||||
inline R partition(R range, U pred) {
|
||||
static_assert(
|
||||
is_range_element_swappable<R>,
|
||||
"The range element accessors must allow swapping"
|
||||
);
|
||||
R ret = range;
|
||||
for (; !range.empty(); range.pop_front()) {
|
||||
if (pred(range.front())) {
|
||||
|
@ -183,8 +187,8 @@ namespace detail {
|
|||
* comparison function takes two `ostd::range_reference_t<R>` and must
|
||||
* return a boolean equivalent to `a < b` for ascending order.
|
||||
*
|
||||
* The items are swapped in the range, which means the range's reference
|
||||
* type must be swappable.
|
||||
* The items are swapped in the range, which means the range must also
|
||||
* meet the conditions of ostd::is_range_element_swappable.
|
||||
*
|
||||
* The worst-case and average performance of this algorithm os `O(n log n)`.
|
||||
* The best-case performance is `O(n)`. This happens when the range is small
|
||||
|
@ -197,6 +201,10 @@ namespace detail {
|
|||
*/
|
||||
template<typename R, typename C>
|
||||
inline R sort_cmp(R range, C compare) {
|
||||
static_assert(
|
||||
is_range_element_swappable<R>,
|
||||
"The range element accessors must allow swapping"
|
||||
);
|
||||
detail::introsort(range, compare);
|
||||
return range;
|
||||
}
|
||||
|
@ -215,6 +223,10 @@ inline auto sort_cmp(C &&compare) {
|
|||
/** @brief Like ostd::sort_cmp() using `std::less<ostd::range_value_t<R>>{}`. */
|
||||
template<typename R>
|
||||
inline R sort(R range) {
|
||||
static_assert(
|
||||
is_range_element_swappable<R>,
|
||||
"The range element accessors must allow swapping"
|
||||
);
|
||||
return sort_cmp(range, std::less<range_value_t<R>>{});
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,9 @@ namespace detail {
|
|||
constexpr bool test_range_category = range_category_test<R>::value;
|
||||
|
||||
template<typename R, bool>
|
||||
struct range_traits_base {};
|
||||
struct range_traits_base {
|
||||
static constexpr bool is_element_swappable = false;
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
struct range_traits_base<R, true> {
|
||||
|
@ -177,10 +179,18 @@ namespace detail {
|
|||
using value_type = typename R::value_type;
|
||||
using reference = typename R::reference;
|
||||
using difference_type = typename R::difference_type;
|
||||
|
||||
static constexpr bool is_element_swappable =
|
||||
std::is_convertible_v<range_category, input_range_tag> &&
|
||||
std::is_lvalue_reference_v<reference> &&
|
||||
std::is_same_v<value_type, std::remove_reference_t<reference>> &&
|
||||
std::is_swappable_v<value_type>;
|
||||
};
|
||||
|
||||
template<typename R, bool>
|
||||
struct range_traits_impl {};
|
||||
struct range_traits_impl {
|
||||
static constexpr bool is_element_swappable = false;
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
struct range_traits_impl<R, true>: range_traits_base<
|
||||
|
@ -194,7 +204,7 @@ namespace detail {
|
|||
*
|
||||
* Using range traits, you can for check various properties of the range.
|
||||
* If the provided `R` type is not a range type, the traits struct will
|
||||
* be empty. Otherwise, it will contain the following:
|
||||
* be empty. Otherwise, it will contain the following member types:
|
||||
*
|
||||
* * `range_category` - one of the category tags (see ostd::input_range_tag)
|
||||
* * `size_type` - can contain the range's length (typically `size_t`)
|
||||
|
@ -202,6 +212,22 @@ namespace detail {
|
|||
* * `reference` - the type returned from value accessors
|
||||
* * `difference_type` - the type used for distances (typically `ptrdiff_t`)
|
||||
*
|
||||
* It will always contain the following member as well:
|
||||
*
|
||||
* ~~~{.cc}
|
||||
* static constexpr bool is_element_swappable = ...;
|
||||
* ~~~
|
||||
*
|
||||
* This member will be false for non-range types and otherwise true when
|
||||
* the following conditions are met:
|
||||
*
|
||||
* * The range is an ostd::input_range_tag or better (not an output range).
|
||||
* * The `reference` member type is an lvalue reference.
|
||||
* * The `value_type` is the same as `std::remove_reference_t<reference>`.
|
||||
* * The `value_type` member is swappable (`std::is_swappable_v<value_type>`).
|
||||
*
|
||||
* If any of these four is not met, the member will also be false.
|
||||
*
|
||||
* You can read about more details [here](@ref ranges).
|
||||
*
|
||||
* @see ostd::range_category_t, ostd::range_size_t, ostd::range_value_t,
|
||||
|
@ -280,6 +306,18 @@ using range_reference_t = typename range_traits<R>::reference;
|
|||
template<typename R>
|
||||
using range_difference_t = typename range_traits<R>::difference_type;
|
||||
|
||||
/** @brief Checks whether the range's element accessors allow swapping.
|
||||
*
|
||||
* It's the same as doing
|
||||
*
|
||||
* ~~~{.cc}
|
||||
* ostd::range_traits<R>::is_element_swappable
|
||||
* ~~~
|
||||
*
|
||||
*/
|
||||
template<typename R>
|
||||
constexpr bool is_range_element_swappable = range_traits<R>::is_element_swappable;
|
||||
|
||||
// is input range
|
||||
|
||||
namespace detail {
|
||||
|
|
Loading…
Reference in New Issue