зеркало из https://github.com/microsoft/STL.git
Several range algorithms (#565)
* Several range algorithms In `<algorithm>`, implement: * the generic algorithm result types from P2106R0 (lines 75-227) * `ranges::for_each` and its result alias `for_each_result` (lines 289-322) * `ranges::for_each_n` and its result alias `for_each_result_n` (lines 324-351) from P1243R4 * `ranges::find` (lines 353-384) * `ranges::find_if` (lines 396-426) * `ranges::find_if_not` (lines 454-484) * `ranges::count` (lines 526-568) * `ranges::count_if` (lines 587-617) * `ranges::mismatch` and its result alias `mismatch_result` (lines 798-891) * `ranges::equal` (lines 893-980) * `ranges::all_of` (lines 1006-1033) * `ranges::any_of` (lines 1060-1087) * `ranges::none_of` (lines 1114-1141) * `ranges::copy` and its result alias `copy_result` (lines 1143-1175) * `ranges::copy_n` and its result alias `copy_n_result` (lines 1177-1207) * `ranges::copy_if` and its result alias `copy_if_result` (lines 1262-1302) In `<concepts>`: * implement LWG-3194 which includes the resolution of LWG-3151 (lines 51-53) * LWG-3175 has been merged, remove conditional implementation (line 183) * replace `boolean` concept with _`boolean-testable`_ concept from P1964R2 (lines 198-237, 283) * move `movable` (pun intended) into synopsis order (lines 254-256) * Modify concept `copyable` per P2102R0 (lines 260-261) * Implement concept `equivalence_relation` from P1716R3 (lines 290-293) In `<xutility>`: * promote `identity` from `<functional>` for visibility in `<algorithm>` (lines 160-168) * promote `common_range` from `<ranges>` for visibility in `<algorithm>` (lines 3091-3095) * remove LWG-3247 and LWG-3299 annotations (lines 622, 626, and 963) * prefix `indirectly_` to the names of `readable_traits`, `readable`, and `writable` (a great many lines); and modify `iter_value_t` (lines 366-367), `iter_reference_t` (lines ), `iter_difference_t`, `iter_rvalue_reference_t`, `indirectly_readable` (lines 688-701) and `indirectly_swappable` per P1878R1 * define alias template `_Make_unsigned_like_t` to implement P1522R1's _`make-unsigned-like-t`_ (it does nothing interesting yet, since we provide no integer-class types) (lines 727-729) * implement the "Indirect callable" concepts `indirectly_unary_invocable`, `indirectly_regular_unary_invocable`, `indirect_unary_predicate`, `indirect_binary_predicate`, `indirect_equivalence_relation`, `indirect_strict_weak_order`, and helpers `indirect_result_t` and `projected` (lines 852-926) * implement `indirectly_copyable` and `indirectly_copyable_storable` concepts (lines 939-952) * implement `indirectly_swappable`, `indirectly_comparable`, `permutable`, `mergeable`, and `sortable` concepts (lines 1032-1061) * rename `safe_range` and `enable_safe_range` to `borrowed_range` and `enable_borrowed_range` per LWG-3379 (lines 2168-2173 and 2327-2330) * remove "Implements D2091R0" comments (various lines in 2175-2710) * add `ranges::data` to the list of access CPOs that hard error for arrays of incomplete element types (lines 2204-2205 and 2277-2278) * `ranges::empty` rejects arrays of unbound bound per P2091R0 (lines 2664-2692) * implement concept `_Not_same_as` (the exposition-only _`not-same-as`_ from the working draft) (lines 3087-3089) * implement `ranges::dangling` (lines 3097-3102) * implement `ranges::borrowed_iterator_t` (lines 3104-3106) In `<yvals_core.h>`: * Indicate implementation of: * P1207R4 Movability of Single-Pass Iterators * P1248R1 Fixing Relations * P1474R1 Helpful Pointers For contiguous_iterator * P1716R3 Range Comparison Algorithms Are Over-Constrained * P1878R1 Constraining Readable Types * P1964R2 Replacing `boolean` with _`boolean-testable`_ * P2091R0 Fixing Issues With Range Access CPOs * P2102R0 Make "implicit expression variations" More Explicit * and partial implementation of: * P1243R4 Rangify New Algorithms * remove conditional definition of `_HAS_STD_BOOLEAN` (we never has `std::boolean` now) `tests/std/include/instantiate_algorithms.hpp`: * define non-movable type `Immobile`, and use it to ensure that standard algorithms neither copy nor move random number generators nor uniform random bit generators Add header `tests/std/include/range_algorithm_support.hpp` with support machinery for the ranges algorithm tests. It notably defines: * `is_permissive` for determining whether we are compiling in MSVC's permissive mode (lines 18-37) * A class template `borrowed<bool>` whose specializations always model `range` and model `borrowed_range` iff the template parameter is `true` (lines 39-46) * Function objects `get_first` and `get_second` which project the pertinent member from `pair` arguments (lines 48-54) * A class template `move_only_range<T>` which adapts a `contiguous_range` of `T` into a move-only `view` with move-only `input_iterator`s (lines 56-150) * A "phony" iterator class template `test_iterator` with tunable category, value type, and difference capability for instantiation tests (lines 152-363) * A similar "phony" class template `test_range` with tunable category, size, and commonality (i.e., is the sentinel type the same as the iterator type) (lines 365-423) * "phony" predicate and projection types for instantiation tests (lines 425-442) * combinatoric instantiation machinery for instantiation tests that instantiate with all interesting kinds of output iterators or input ranges (lines 444-529) A new compile-only test `tests/std/tests/P0896R4_ranges_algorithm_machinery` which covers: * `indirectly_unary_invocable`/`indirectly_regular_unary_invocable` * `indirect_unary_predicate`/`indirect_binary_predicate`/`indirect_result_t` * `projected` * `indirectly_copyable`/`indirectly_swappable`/`indirectly_comparable` * `dangling`/`borrowed_iterator_t` * the result types `in_found_result`/`in_fun_result`/`in_in_result`/`in_out_result`/`in_in_out_result`/`in_out_out_result`/`min_max_result` Very simple smoke and instantiation tests for the 15 new algorithms in: * `tests/std/tests/P0896R4_ranges_alg_all_of` * `tests/std/tests/P0896R4_ranges_alg_any_of` * `tests/std/tests/P0896R4_ranges_alg_copy` * `tests/std/tests/P0896R4_ranges_alg_copy_if` * `tests/std/tests/P0896R4_ranges_alg_copy_n` * `tests/std/tests/P0896R4_ranges_alg_count` * `tests/std/tests/P0896R4_ranges_alg_count_if` * `tests/std/tests/P0896R4_ranges_alg_equal` * `tests/std/tests/P0896R4_ranges_alg_find` * `tests/std/tests/P0896R4_ranges_alg_find_if` * `tests/std/tests/P0896R4_ranges_alg_find_if_not` * `tests/std/tests/P0896R4_ranges_alg_for_each` * `tests/std/tests/P0896R4_ranges_alg_for_each_n` * `tests/std/tests/P0896R4_ranges_alg_mismatch` * `tests/std/tests/P0896R4_ranges_alg_none_of` Resolves: * #537 `<concepts>`: LWG-3175 has been accepted, so we should remove commented-out code * #540 LWG-3194 `ConvertibleTo` prose does not match code * #546 LWG-3379 `safe` in several library names is misleading * #559 P1964R2 "Replacing `boolean` with _`boolean-testable`_" * #561 P2102R0 "Making 'Implicit Expression Variations' More Explicit" * #563 P2091R0 "Fixing Issues With Range Access CPOs"
This commit is contained in:
Родитель
369008308c
Коммит
930b843f31
|
@ -72,6 +72,160 @@ struct _Optimistic_temporary_buffer { // temporary storage with _alloca-like att
|
|||
aligned_union_t<0, _Ty> _Stack_space[_Optimistic_count];
|
||||
};
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// CONCEPT _Convertible_from
|
||||
template <class _To, class _From>
|
||||
concept _Convertible_from = convertible_to<_From, _To>;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunknown-attributes"
|
||||
#endif // __clang__
|
||||
|
||||
// STRUCT TEMPLATE in_fun_result
|
||||
template <class _In, class _Fn>
|
||||
struct in_fun_result {
|
||||
[[no_unique_address]] _In in;
|
||||
[[no_unique_address]] _Fn fun;
|
||||
|
||||
// clang-format off
|
||||
template <_Convertible_from<const _In&> _IIn, _Convertible_from<const _Fn&> _FFn>
|
||||
constexpr operator in_fun_result<_IIn, _FFn>() const & {
|
||||
return {in, fun};
|
||||
}
|
||||
|
||||
template <_Convertible_from<_In> _IIn, _Convertible_from<_Fn> _FFn>
|
||||
constexpr operator in_fun_result<_IIn, _FFn>() && {
|
||||
return {_STD move(in), _STD move(fun)};
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// STRUCT TEMPLATE in_in_result
|
||||
template <class _In1, class _In2>
|
||||
struct in_in_result {
|
||||
[[no_unique_address]] _In1 in1;
|
||||
[[no_unique_address]] _In2 in2;
|
||||
|
||||
// clang-format off
|
||||
template <_Convertible_from<const _In1&> _IIn1, _Convertible_from<const _In2&> _IIn2>
|
||||
constexpr operator in_in_result<_IIn1, _IIn2>() const & {
|
||||
return {in1, in2};
|
||||
}
|
||||
|
||||
template <_Convertible_from<_In1> _IIn1, _Convertible_from<_In2> _IIn2>
|
||||
constexpr operator in_in_result<_IIn1, _IIn2>() && {
|
||||
return {_STD move(in1), _STD move(in2)};
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// STRUCT TEMPLATE in_out_result
|
||||
template <class _In, class _Out>
|
||||
struct in_out_result {
|
||||
[[no_unique_address]] _In in;
|
||||
[[no_unique_address]] _Out out;
|
||||
|
||||
// clang-format off
|
||||
template <_Convertible_from<const _In&> _IIn, _Convertible_from<const _Out&> _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)};
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// STRUCT TEMPLATE in_in_out_result
|
||||
template <class _In1, class _In2, class _Out>
|
||||
struct in_in_out_result {
|
||||
[[no_unique_address]] _In1 in1;
|
||||
[[no_unique_address]] _In2 in2;
|
||||
[[no_unique_address]] _Out out;
|
||||
|
||||
// clang-format off
|
||||
template <_Convertible_from<const _In1&> _IIn1, _Convertible_from<const _In2&> _IIn2,
|
||||
_Convertible_from<const _Out&> _OOut>
|
||||
constexpr operator in_in_out_result<_IIn1, _IIn2, _OOut>() const & {
|
||||
return {in1, in2, out};
|
||||
}
|
||||
|
||||
template <_Convertible_from<_In1> _IIn1, _Convertible_from<_In2> _IIn2, _Convertible_from<_Out> _OOut>
|
||||
constexpr operator in_in_out_result<_IIn1, _IIn2, _OOut>() && {
|
||||
return {_STD move(in1), _STD move(in2), _STD move(out)};
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// STRUCT TEMPLATE in_out_out_result
|
||||
template <class _In, class _Out1, class _Out2>
|
||||
struct in_out_out_result {
|
||||
[[no_unique_address]] _In in;
|
||||
[[no_unique_address]] _Out1 out1;
|
||||
[[no_unique_address]] _Out2 out2;
|
||||
|
||||
// clang-format off
|
||||
template <_Convertible_from<const _In&> _IIn, _Convertible_from<const _Out1&> _OOut1,
|
||||
_Convertible_from<const _Out2&> _OOut2>
|
||||
constexpr operator in_out_out_result<_IIn, _OOut1, _OOut2>() const & {
|
||||
return {in, out1, out2};
|
||||
}
|
||||
|
||||
template <_Convertible_from<_In> _IIn, _Convertible_from<_Out1> _OOut1, _Convertible_from<_Out2> _OOut2>
|
||||
constexpr operator in_out_out_result<_IIn, _OOut1, _OOut2>() && {
|
||||
return {_STD move(in), _STD move(out1), _STD move(out2)};
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// STRUCT TEMPLATE min_max_result
|
||||
template <class _Ty>
|
||||
struct min_max_result {
|
||||
[[no_unique_address]] _Ty min;
|
||||
[[no_unique_address]] _Ty max;
|
||||
|
||||
// clang-format off
|
||||
template <_Convertible_from<const _Ty&> _Ty2>
|
||||
constexpr operator min_max_result<_Ty2>() const & {
|
||||
return {min, max};
|
||||
}
|
||||
|
||||
template <_Convertible_from<_Ty> _Ty2>
|
||||
constexpr operator min_max_result<_Ty2>() && {
|
||||
return {_STD move(min), _STD move(max)};
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// STRUCT TEMPLATE in_found_result
|
||||
template <class _In>
|
||||
struct in_found_result {
|
||||
[[no_unique_address]] _In in;
|
||||
bool found;
|
||||
|
||||
// clang-format off
|
||||
template <_Convertible_from<const _In&> _IIn>
|
||||
constexpr operator in_found_result<_IIn>() const & {
|
||||
return {in, found};
|
||||
}
|
||||
|
||||
template <_Convertible_from<_In> _IIn>
|
||||
constexpr operator in_found_result<_IIn>() && {
|
||||
return {_STD move(in), found};
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif // __clang__
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE for_each
|
||||
template <class _InIt, class _Fn>
|
||||
_CONSTEXPR20 _Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) { // perform function for each element [_First, _Last)
|
||||
|
@ -132,12 +286,148 @@ _SourceTy* for_each_n(
|
|||
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// ALIAS TEMPLATE for_each_result
|
||||
template <class _It, class _Fn>
|
||||
using for_each_result = in_fun_result<_It, _Fn>;
|
||||
|
||||
// VARIABLE ranges::for_each
|
||||
class _For_each_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||
indirectly_unary_invocable<projected<_It, _Pj>> _Fn>
|
||||
constexpr for_each_result<_It, _Fn> operator()(_It _First, _Se _Last, _Fn _Func, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
_C_invoke(_Func, _C_invoke(_Proj, *_UFirst));
|
||||
}
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
||||
return {_STD move(_First), _STD move(_Func)};
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Pj = identity,
|
||||
indirectly_unary_invocable<projected<iterator_t<_Rng>, _Pj>> _Fn>
|
||||
constexpr for_each_result<borrowed_iterator_t<_Rng>, _Fn> operator()(
|
||||
_Rng&& _Range, _Fn _Func, _Pj _Proj = {}) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Func), _Pass_fn(_Proj));
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _For_each_fn for_each{_Not_quite_object::_Construct_tag{}};
|
||||
|
||||
// ALIAS TEMPLATE for_each_n_result
|
||||
template <class _It, class _Fn>
|
||||
using for_each_n_result = in_fun_result<_It, _Fn>;
|
||||
|
||||
// VARIABLE ranges::for_each_n
|
||||
class _For_each_n_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
template <input_iterator _It, class _Pj = identity, indirectly_unary_invocable<projected<_It, _Pj>> _Fn>
|
||||
constexpr for_each_n_result<_It, _Fn> operator()(
|
||||
_It _First, iter_difference_t<_It> _Count, _Fn _Func, _Pj _Proj = {}) const {
|
||||
if (0 < _Count) {
|
||||
auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count);
|
||||
do {
|
||||
_C_invoke(_Func, _C_invoke(_Proj, *_UFirst));
|
||||
--_Count;
|
||||
++_UFirst;
|
||||
} while (0 < _Count);
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
||||
}
|
||||
|
||||
return {_STD move(_First), _STD move(_Func)};
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _For_each_n_fn for_each_n{_Not_quite_object::_Construct_tag{}};
|
||||
|
||||
// VARIABLE ranges::find
|
||||
class _Find_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, class _Ty, class _Pj = identity>
|
||||
requires indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty*>
|
||||
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
// Performance note: investigate using _Find_unchecked when same_as<_Pj, identity>
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
if (_C_invoke(_Proj, *_UFirst) == _Val) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
||||
return _First;
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Ty, class _Pj = identity>
|
||||
requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Rng>, _Pj>, const _Ty*>
|
||||
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(
|
||||
_Rng&& _Range, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Val, _Pass_fn(_Proj));
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Find_fn find{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
#if _HAS_CXX17
|
||||
// PARALLEL FUNCTION TEMPLATE find_if
|
||||
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
||||
_NODISCARD _FwdIt find_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::find_if
|
||||
class _Find_if_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
||||
return _First;
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Find_if_fn find_if{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE find_if_not
|
||||
template <class _InIt, class _Pr>
|
||||
_NODISCARD _CONSTEXPR20 _InIt find_if_not(_InIt _First, const _InIt _Last, _Pr _Pred) {
|
||||
|
@ -160,6 +450,42 @@ template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_E
|
|||
_NODISCARD _FwdIt find_if_not(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::find_if_not
|
||||
class _Find_if_not_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
if (!_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
||||
return _First;
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Find_if_not_fn find_if_not{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE adjacent_find
|
||||
template <class _FwdIt, class _Pr>
|
||||
_NODISCARD _CONSTEXPR20 _FwdIt adjacent_find(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
||||
|
@ -196,6 +522,45 @@ _NODISCARD _FwdIt adjacent_find(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt
|
|||
}
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::count
|
||||
class _Count_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, class _Ty, class _Pj = identity>
|
||||
requires indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty*>
|
||||
_NODISCARD constexpr iter_difference_t<_It> operator()(
|
||||
_It _First, _Se _Last, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
iter_difference_t<_It> _Count = 0;
|
||||
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
if (_C_invoke(_Proj, *_UFirst) == _Val) {
|
||||
++_Count;
|
||||
}
|
||||
}
|
||||
|
||||
return _Count;
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Ty, class _Pj = identity>
|
||||
requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Rng>, _Pj>, const _Ty*>
|
||||
_NODISCARD constexpr range_difference_t<_Rng> operator()(_Rng&& _Range, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Val, _Pass_fn(_Proj));
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Count_fn count{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE count_if
|
||||
template <class _InIt, class _Pr>
|
||||
_NODISCARD _CONSTEXPR20 _Iter_diff_t<_InIt> count_if(_InIt _First, _InIt _Last, _Pr _Pred) {
|
||||
|
@ -219,6 +584,42 @@ _NODISCARD _Iter_diff_t<_FwdIt> count_if(
|
|||
_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::count_if
|
||||
class _Count_if_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||
_NODISCARD constexpr iter_difference_t<_It> operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
iter_difference_t<_It> _Count = 0;
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) {
|
||||
++_Count;
|
||||
}
|
||||
}
|
||||
|
||||
return _Count;
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||
_NODISCARD constexpr range_difference_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Count_if_fn count_if{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE mismatch
|
||||
template <class _InIt1, class _InIt2, class _Pr>
|
||||
_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _Pr _Pred) {
|
||||
|
@ -394,6 +795,194 @@ _NODISCARD pair<_FwdIt1, _FwdIt2> mismatch(
|
|||
}
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// ALIAS TEMPLATE mismatch_result
|
||||
template <class _In1, class _In2>
|
||||
using mismatch_result = in_in_result<_In1, _In2>;
|
||||
|
||||
// VARIABLE ranges::mismatch
|
||||
class _Mismatch_fn : private _Not_quite_object {
|
||||
private:
|
||||
template <class _It1, class _It2, class _Pr, class _Pj1, class _Pj2>
|
||||
_NODISCARD static constexpr mismatch_result<_It1, _It2> _Mismatch_n(
|
||||
_It1 _First1, _It2 _First2, iter_difference_t<_It1> _Count, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) {
|
||||
auto _UFirst1 = _Get_unwrapped(_STD move(_First1));
|
||||
auto _UFirst2 = _Get_unwrapped(_STD move(_First2));
|
||||
|
||||
for (; _Count != 0; ++_UFirst1, (void) ++_UFirst2, --_Count) {
|
||||
if (!_C_invoke(_Pred, _C_invoke(_Proj1, *_UFirst1), _C_invoke(_Proj2, *_UFirst2))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_Seek_wrapped(_First1, _STD move(_UFirst1));
|
||||
_Seek_wrapped(_First2, _STD move(_UFirst2));
|
||||
return {_STD move(_First1), _STD move(_First2)};
|
||||
}
|
||||
|
||||
template <class _It1, class _Se1, class _It2, class _Se2, class _Pr, class _Pj1, class _Pj2>
|
||||
_NODISCARD static constexpr mismatch_result<_It1, _It2> _Mismatch_4(
|
||||
_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) {
|
||||
auto _UFirst1 = _Get_unwrapped(_STD move(_First1));
|
||||
const auto _ULast1 = _Get_unwrapped(_STD move(_Last1));
|
||||
auto _UFirst2 = _Get_unwrapped(_STD move(_First2));
|
||||
const auto _ULast2 = _Get_unwrapped(_STD move(_Last2));
|
||||
|
||||
for (; _UFirst1 != _ULast1 && _UFirst2 != _ULast2; ++_UFirst1, (void) ++_UFirst2) {
|
||||
if (!_C_invoke(_Pred, _C_invoke(_Proj1, *_UFirst1), _C_invoke(_Proj2, *_UFirst2))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_Seek_wrapped(_First1, _STD move(_UFirst1));
|
||||
_Seek_wrapped(_First2, _STD move(_UFirst2));
|
||||
return {_STD move(_First1), _STD move(_First2)};
|
||||
}
|
||||
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It1, sentinel_for<_It1> _Se1, input_iterator _It2, sentinel_for<_It2> _Se2,
|
||||
class _Pr = ranges::equal_to, class _Pj1 = identity, class _Pj2 = identity>
|
||||
requires indirectly_comparable<_It1, _It2, _Pr, _Pj1, _Pj2>
|
||||
_NODISCARD constexpr mismatch_result<_It1, _It2> operator()(_It1 _First1, _Se1 _Last1,
|
||||
_It2 _First2, _Se2 _Last2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
|
||||
_Adl_verify_range(_First1, _Last1);
|
||||
_Adl_verify_range(_First2, _Last2);
|
||||
|
||||
if constexpr (sized_sentinel_for<_Se1, _It1> && sized_sentinel_for<_Se2, _It2>) {
|
||||
iter_difference_t<_It1> _Count1 = _Last1 - _First1;
|
||||
const iter_difference_t<_It2> _Count2 = _Last2 - _First2;
|
||||
if (_Count1 > _Count2) {
|
||||
_Count1 = static_cast<decltype(_Count1)>(_Count2);
|
||||
}
|
||||
|
||||
return _Mismatch_n(_STD move(_First1), _STD move(_First2), _Count1,
|
||||
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
} else {
|
||||
return _Mismatch_4(_STD move(_First1), _STD move(_Last1), _STD move(_First2), _STD move(_Last2),
|
||||
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
}
|
||||
}
|
||||
|
||||
template <input_range _Rng1, input_range _Rng2, class _Pr = ranges::equal_to, class _Pj1 = identity,
|
||||
class _Pj2 = identity>
|
||||
requires indirectly_comparable<iterator_t<_Rng1>, iterator_t<_Rng2>, _Pr, _Pj1, _Pj2>
|
||||
_NODISCARD constexpr mismatch_result<borrowed_iterator_t<_Rng1>, borrowed_iterator_t<_Rng2>> operator()(
|
||||
_Rng1&& _Range1, _Rng2&& _Range2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
|
||||
if constexpr (sized_range<_Rng1> && sized_range<_Rng2>) {
|
||||
range_difference_t<_Rng1> _Count1 = _RANGES distance(_Range1);
|
||||
const range_difference_t<_Rng2> _Count2 = _RANGES distance(_Range2);
|
||||
if (_Count1 > _Count2) {
|
||||
_Count1 = static_cast<range_difference_t<_Rng1>>(_Count2);
|
||||
}
|
||||
|
||||
return _Mismatch_n(_RANGES begin(_Range1), _RANGES begin(_Range2), _Count1,
|
||||
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
} else {
|
||||
return _Mismatch_4(_RANGES begin(_Range1), _RANGES end(_Range1),
|
||||
_RANGES begin(_Range2), _RANGES end(_Range2),
|
||||
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Mismatch_fn mismatch{_Not_quite_object::_Construct_tag{}};
|
||||
|
||||
// VARIABLE ranges::equal
|
||||
class _Equal_fn : private _Not_quite_object {
|
||||
private:
|
||||
template <class _It1, class _It2, class _Size, class _Pr, class _Pj1, class _Pj2>
|
||||
_NODISCARD static constexpr bool _Equal_count(
|
||||
_It1 _First1, _It2 _First2, _Size _Count, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) {
|
||||
for (; _Count != 0; ++_First1, (void) ++_First2, --_Count) {
|
||||
if (!_C_invoke(_Pred, _C_invoke(_Proj1, *_First1), _C_invoke(_Proj2, *_First2))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class _It1, class _Se1, class _It2, class _Se2, class _Pr, class _Pj1, class _Pj2>
|
||||
_NODISCARD static constexpr bool _Equal_4(
|
||||
_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) {
|
||||
for (;;) {
|
||||
if (_First1 == _Last1) {
|
||||
return _First2 == _Last2;
|
||||
} else if (_First2 == _Last2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_C_invoke(_Pred, _C_invoke(_Proj1, *_First1), _C_invoke(_Proj2, *_First2))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++_First1;
|
||||
++_First2;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It1, sentinel_for<_It1> _Se1, input_iterator _It2, sentinel_for<_It2> _Se2,
|
||||
class _Pr = ranges::equal_to, class _Pj1 = identity, class _Pj2 = identity>
|
||||
requires indirectly_comparable<_It1, _It2, _Pr, _Pj1, _Pj2>
|
||||
_NODISCARD constexpr bool operator()(_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred = {},
|
||||
_Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
|
||||
_Adl_verify_range(_First1, _Last1);
|
||||
_Adl_verify_range(_First2, _Last2);
|
||||
auto _UFirst1 = _Get_unwrapped(_STD move(_First1));
|
||||
auto _ULast1 = _Get_unwrapped(_STD move(_Last1));
|
||||
auto _UFirst2 = _Get_unwrapped(_STD move(_First2));
|
||||
auto _ULast2 = _Get_unwrapped(_STD move(_Last2));
|
||||
|
||||
if constexpr (sized_sentinel_for<_Se1, _It1> && sized_sentinel_for<_Se2, _It2>) {
|
||||
const auto _Count = _ULast1 - _UFirst1;
|
||||
if (_Count != _ULast2 - _UFirst2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _Equal_count(_STD move(_UFirst1), _STD move(_UFirst2), _Count,
|
||||
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
} else {
|
||||
return _Equal_4(_STD move(_UFirst1), _STD move(_ULast1), _STD move(_UFirst2), _STD move(_ULast2),
|
||||
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
}
|
||||
}
|
||||
|
||||
template <input_range _Rng1, input_range _Rng2, class _Pr = ranges::equal_to, class _Pj1 = identity,
|
||||
class _Pj2 = identity>
|
||||
requires indirectly_comparable<iterator_t<_Rng1>, iterator_t<_Rng2>, _Pr, _Pj1, _Pj2>
|
||||
_NODISCARD constexpr bool operator()(
|
||||
_Rng1&& _Range1, _Rng2&& _Range2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
|
||||
if constexpr (sized_range<_Rng1> && sized_range<_Rng2>) {
|
||||
using _Size1 = _Make_unsigned_like_t<range_size_t<_Rng1>>;
|
||||
const auto _Count = static_cast<_Size1>(_RANGES size(_Range1));
|
||||
using _Size2 = _Make_unsigned_like_t<range_size_t<_Rng2>>;
|
||||
if (_Count != static_cast<_Size2>(_RANGES size(_Range2))) {
|
||||
return false;
|
||||
}
|
||||
return _Equal_count(_Get_unwrapped(_RANGES begin(_Range1)), _Get_unwrapped(_RANGES begin(_Range2)),
|
||||
_Count, _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
} else {
|
||||
return _Equal_4(_Get_unwrapped(_RANGES begin(_Range1)), _Get_unwrapped(_RANGES end(_Range1)),
|
||||
_Get_unwrapped(_RANGES begin(_Range2)), _Get_unwrapped(_RANGES end(_Range2)),
|
||||
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Equal_fn equal{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE all_of
|
||||
template <class _InIt, class _Pr>
|
||||
_NODISCARD _CONSTEXPR20 bool all_of(_InIt _First, _InIt _Last, _Pr _Pred) { // test if all elements satisfy _Pred
|
||||
|
@ -414,6 +1003,39 @@ template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_E
|
|||
_NODISCARD bool all_of(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::all_of
|
||||
class _All_of_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||
_NODISCARD constexpr bool operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
if (!_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||
_NODISCARD constexpr bool operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _All_of_fn all_of{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE any_of
|
||||
template <class _InIt, class _Pr>
|
||||
_NODISCARD _CONSTEXPR20 bool any_of(const _InIt _First, const _InIt _Last, _Pr _Pred) {
|
||||
|
@ -435,6 +1057,39 @@ template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_E
|
|||
_NODISCARD bool any_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::any_of
|
||||
class _Any_of_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||
_NODISCARD constexpr bool operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||
_NODISCARD constexpr bool operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _Any_of_fn any_of{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE none_of
|
||||
template <class _InIt, class _Pr>
|
||||
_NODISCARD _CONSTEXPR20 bool none_of(const _InIt _First, const _InIt _Last, _Pr _Pred) {
|
||||
|
@ -456,6 +1111,105 @@ template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_E
|
|||
_NODISCARD bool none_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::none_of
|
||||
class _None_of_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||
_NODISCARD constexpr bool operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||
_NODISCARD constexpr bool operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _None_of_fn none_of{_Not_quite_object::_Construct_tag{}};
|
||||
|
||||
// ALIAS TEMPLATE copy_result
|
||||
template <class _In, class _Out>
|
||||
using copy_result = in_out_result<_In, _Out>;
|
||||
|
||||
// VARIABLE ranges::copy
|
||||
class _Copy_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, weakly_incrementable _Out>
|
||||
requires indirectly_copyable<_It, _Out>
|
||||
constexpr copy_result<_It, _Out> operator()(_It _First, _Se _Last, _Out _Result) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
for (; _UFirst != _ULast; ++_UFirst, (void) ++_Result) {
|
||||
*_Result = *_UFirst;
|
||||
}
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
||||
return {_STD move(_First), _STD move(_Result)};
|
||||
}
|
||||
|
||||
template <input_range _Rng, weakly_incrementable _Out>
|
||||
requires indirectly_copyable<iterator_t<_Rng>, _Out>
|
||||
constexpr copy_result<borrowed_iterator_t<_Rng>, _Out> operator()(_Rng&& _Range, _Out _Result) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Result));
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Copy_fn copy{_Not_quite_object::_Construct_tag{}};
|
||||
|
||||
// ALIAS TEMPLATE copy_n_result
|
||||
template <class _In, class _Out>
|
||||
using copy_n_result = in_out_result<_In, _Out>;
|
||||
|
||||
// VARIABLE ranges::copy_n
|
||||
class _Copy_n_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It, weakly_incrementable _Out>
|
||||
requires indirectly_copyable<_It, _Out>
|
||||
constexpr copy_n_result<_It, _Out> operator()(_It _First, iter_difference_t<_It> _Count, _Out _Result) const {
|
||||
auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count);
|
||||
for (; _Count > 0; ++_UFirst, (void) ++_Result, --_Count) {
|
||||
*_Result = *_UFirst;
|
||||
}
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
||||
return {_STD move(_First), _STD move(_Result)};
|
||||
}
|
||||
|
||||
template <input_range _Rng, weakly_incrementable _Out>
|
||||
requires indirectly_copyable<iterator_t<_Rng>, _Out>
|
||||
constexpr copy_n_result<borrowed_iterator_t<_Rng>, _Out> operator()(_Rng&& _Range, _Out _Result) const {
|
||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Result));
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Copy_n_fn copy_n{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE copy_if
|
||||
template <class _InIt, class _OutIt, class _Pr>
|
||||
_CONSTEXPR20 _OutIt copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy each satisfying _Pred
|
||||
|
@ -505,6 +1259,52 @@ _DestTy* copy_if(
|
|||
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// ALIAS TEMPLATE copy_if_result
|
||||
template <class _In, class _Out>
|
||||
using copy_if_result = in_out_result<_In, _Out>;
|
||||
|
||||
// VARIABLE ranges::copy_if
|
||||
class _Copy_if_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <input_iterator _It, sentinel_for<_It> _Se, weakly_incrementable _Out, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||
requires indirectly_copyable<_It, _Out>
|
||||
constexpr copy_if_result<_It, _Out> operator()(
|
||||
_It _First, _Se _Last, _Out _Result, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) {
|
||||
*_Result = *_UFirst;
|
||||
++_Result;
|
||||
}
|
||||
}
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
||||
return {_STD move(_First), _STD move(_Result)};
|
||||
}
|
||||
|
||||
template <input_range _Rng, weakly_incrementable _Out, class _Pj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||
requires indirectly_copyable<iterator_t<_Rng>, _Out>
|
||||
constexpr copy_if_result<borrowed_iterator_t<_Rng>, _Out> operator()(
|
||||
_Rng&& _Range, _Out _Result, _Pr _Pred, _Pj _Proj = {}) const {
|
||||
return (*this)(
|
||||
_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Result), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Copy_if_fn copy_if{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE partition_copy
|
||||
template <class _InIt, class _OutIt1, class _OutIt2, class _Pr>
|
||||
_CONSTEXPR20 pair<_OutIt1, _OutIt2> partition_copy(
|
||||
|
|
|
@ -48,11 +48,9 @@ concept derived_from = __is_base_of(_Base, _Derived)
|
|||
// CONCEPT convertible_to
|
||||
template <class _From, class _To>
|
||||
concept convertible_to = __is_convertible_to(_From, _To)
|
||||
#if 1 // Implement the PR of LWG-3151
|
||||
&& requires { static_cast<_To>(_STD declval<_From>()); };
|
||||
#else // ^^^ LWG-3151 / N4810 vvv
|
||||
&& requires(_From (&_Fn)()) { static_cast<_To>(_Fn()); };
|
||||
#endif // select LWG-3151 vs. N4810
|
||||
&& requires(add_rvalue_reference_t<_From> (&_Fn)()) {
|
||||
static_cast<_To>(_Fn());
|
||||
};
|
||||
|
||||
// CONCEPT common_reference_with
|
||||
template <class _Ty1, class _Ty2>
|
||||
|
@ -181,12 +179,7 @@ concept swappable = requires(_Ty& __x, _Ty& __y) {
|
|||
|
||||
// CONCEPT swappable_with
|
||||
template <class _Ty1, class _Ty2>
|
||||
concept swappable_with =
|
||||
#if 1 // Implement the PR of LWG-3175
|
||||
common_reference_with<_Ty1, _Ty2>
|
||||
#else // ^^^ LWG-3175 / N4810 vvv
|
||||
common_reference_with<const remove_reference_t<_Ty1>&, const remove_reference_t<_Ty2>&>
|
||||
#endif // select LWG-3175 vs. N4810
|
||||
concept swappable_with = common_reference_with<_Ty1, _Ty2>
|
||||
&& requires(_Ty1&& __t, _Ty2&& __u) {
|
||||
_RANGES swap(static_cast<_Ty1&&>(__t), static_cast<_Ty1&&>(__t));
|
||||
_RANGES swap(static_cast<_Ty2&&>(__u), static_cast<_Ty2&&>(__u));
|
||||
|
@ -201,41 +194,22 @@ concept copy_constructible = move_constructible<_Ty>
|
|||
&& constructible_from<_Ty, const _Ty&> && convertible_to<const _Ty&, _Ty>
|
||||
&& constructible_from<_Ty, const _Ty> && convertible_to<const _Ty, _Ty>;
|
||||
|
||||
// CONCEPT movable
|
||||
// CONCEPT _Boolean_testable
|
||||
template <class _Ty>
|
||||
concept movable = is_object_v<_Ty> && move_constructible<_Ty> && assignable_from<_Ty&, _Ty> && swappable<_Ty>;
|
||||
concept _Boolean_testable_impl = convertible_to<_Ty, bool>;
|
||||
|
||||
// CONCEPT boolean
|
||||
#if _HAS_STD_BOOLEAN
|
||||
#define _STL_BOOLEAN_CONCEPT boolean
|
||||
#else
|
||||
#define _STL_BOOLEAN_CONCEPT _Boolean
|
||||
#endif
|
||||
template <class _Ty>
|
||||
concept _STL_BOOLEAN_CONCEPT = movable<remove_cvref_t<_Ty>>
|
||||
&& requires(const remove_reference_t<_Ty>& __x, const remove_reference_t<_Ty>& __y, const bool __b) {
|
||||
{ __x } -> convertible_to<bool>;
|
||||
{ !__x } -> convertible_to<bool>;
|
||||
{ __x && __y } -> same_as<bool>;
|
||||
{ __x && __b } -> same_as<bool>;
|
||||
{ __b && __y } -> same_as<bool>;
|
||||
{ __x || __y } -> same_as<bool>;
|
||||
{ __x || __b } -> same_as<bool>;
|
||||
{ __b || __y } -> same_as<bool>;
|
||||
{ __x == __y } -> convertible_to<bool>;
|
||||
{ __x == __b } -> convertible_to<bool>;
|
||||
{ __b == __y } -> convertible_to<bool>;
|
||||
{ __x != __y } -> convertible_to<bool>;
|
||||
{ __x != __b } -> convertible_to<bool>;
|
||||
{ __b != __y } -> convertible_to<bool>;
|
||||
concept _Boolean_testable = _Boolean_testable_impl<_Ty>
|
||||
&& requires (_Ty&& __t) {
|
||||
{ !static_cast<_Ty&&>(__t) } -> _Boolean_testable_impl;
|
||||
};
|
||||
|
||||
// CONCEPT _Weakly_equality_comparable_with
|
||||
template <class _Ty1, class _Ty2>
|
||||
concept _Half_equality_comparable =
|
||||
requires(const remove_reference_t<_Ty1>& __x, const remove_reference_t<_Ty2>& __y) {
|
||||
{ __x == __y } -> _STL_BOOLEAN_CONCEPT;
|
||||
{ __x != __y } -> _STL_BOOLEAN_CONCEPT;
|
||||
{ __x == __y } -> _Boolean_testable;
|
||||
{ __x != __y } -> _Boolean_testable;
|
||||
};
|
||||
|
||||
template <class _Ty1, class _Ty2>
|
||||
|
@ -257,10 +231,10 @@ concept equality_comparable_with = equality_comparable<_Ty1> && equality_compara
|
|||
// CONCEPT _Partially_ordered_with
|
||||
template <class _Ty1, class _Ty2>
|
||||
concept _Half_ordered = requires(const remove_reference_t<_Ty1>& __t, const remove_reference_t<_Ty2>& __u) {
|
||||
{ __t < __u } -> _STL_BOOLEAN_CONCEPT;
|
||||
{ __t > __u } -> _STL_BOOLEAN_CONCEPT;
|
||||
{ __t <= __u } -> _STL_BOOLEAN_CONCEPT;
|
||||
{ __t >= __u } -> _STL_BOOLEAN_CONCEPT;
|
||||
{ __t < __u } -> _Boolean_testable;
|
||||
{ __t > __u } -> _Boolean_testable;
|
||||
{ __t <= __u } -> _Boolean_testable;
|
||||
{ __t >= __u } -> _Boolean_testable;
|
||||
};
|
||||
|
||||
template <class _Ty1, class _Ty2>
|
||||
|
@ -277,9 +251,20 @@ concept totally_ordered_with = totally_ordered<_Ty1> && totally_ordered<_Ty2>
|
|||
&& totally_ordered<common_reference_t<const remove_reference_t<_Ty1>&, const remove_reference_t<_Ty2>&>>
|
||||
&& _Partially_ordered_with<_Ty1, _Ty2>;
|
||||
|
||||
// CONCEPT movable
|
||||
template <class _Ty>
|
||||
concept movable = is_object_v<_Ty>
|
||||
&& move_constructible<_Ty>
|
||||
&& assignable_from<_Ty&, _Ty>
|
||||
&& swappable<_Ty>;
|
||||
|
||||
// CONCEPT copyable
|
||||
template <class _Ty>
|
||||
concept copyable = copy_constructible<_Ty> && movable<_Ty> && assignable_from<_Ty&, const _Ty&>;
|
||||
concept copyable = copy_constructible<_Ty>
|
||||
&& movable<_Ty>
|
||||
&& assignable_from<_Ty&, _Ty&>
|
||||
&& assignable_from<_Ty&, const _Ty&>
|
||||
&& assignable_from<_Ty&, const _Ty>;
|
||||
|
||||
// CONCEPT semiregular
|
||||
template <class _Ty>
|
||||
|
@ -301,13 +286,21 @@ concept regular_invocable = invocable<_FTy, _ArgTys...>;
|
|||
|
||||
// CONCEPT predicate
|
||||
template <class _FTy, class... _ArgTys>
|
||||
concept predicate = regular_invocable<_FTy, _ArgTys...> && _STL_BOOLEAN_CONCEPT<invoke_result_t<_FTy, _ArgTys...>>;
|
||||
concept predicate = regular_invocable<_FTy, _ArgTys...>
|
||||
&& _Boolean_testable<invoke_result_t<_FTy, _ArgTys...>>;
|
||||
|
||||
// CONCEPT relation
|
||||
template <class _FTy, class _Ty1, class _Ty2>
|
||||
concept relation = predicate<_FTy, _Ty1, _Ty1> && predicate<_FTy, _Ty2, _Ty2> && predicate<_FTy, _Ty1, _Ty2>
|
||||
concept relation =
|
||||
predicate<_FTy, _Ty1, _Ty1>
|
||||
&& predicate<_FTy, _Ty2, _Ty2>
|
||||
&& predicate<_FTy, _Ty1, _Ty2>
|
||||
&& predicate<_FTy, _Ty2, _Ty1>;
|
||||
|
||||
// CONCEPT equivalence_relation
|
||||
template <class _FTy, class _Ty1, class _Ty2>
|
||||
concept equivalence_relation = relation<_FTy, _Ty1, _Ty2>;
|
||||
|
||||
// CONCEPT strict_weak_order
|
||||
template <class _FTy, class _Ty1, class _Ty2>
|
||||
concept strict_weak_order = relation<_FTy, _Ty1, _Ty2>;
|
||||
|
|
|
@ -658,18 +658,6 @@ _NODISCARD _Mem_fn<_Rx _Ty::*> mem_fn(_Rx _Ty::*_Pm) noexcept {
|
|||
return _Mem_fn<_Rx _Ty::*>(_Pm);
|
||||
}
|
||||
|
||||
#if _HAS_CXX20
|
||||
// STRUCT identity
|
||||
struct identity {
|
||||
template <class _Ty>
|
||||
_NODISCARD constexpr _Ty&& operator()(_Ty&& _Left) const noexcept {
|
||||
return _STD forward<_Ty>(_Left);
|
||||
}
|
||||
|
||||
using is_transparent = int;
|
||||
};
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
#if _HAS_CXX17
|
||||
// FUNCTION TEMPLATE not_fn
|
||||
struct _Not_fn_tag {
|
||||
|
|
|
@ -25,15 +25,12 @@ namespace ranges {
|
|||
// Much machinery defined in <xutility>
|
||||
|
||||
// clang-format off
|
||||
// CONCEPT ranges::common_range
|
||||
template <class _Rng>
|
||||
concept common_range = range<_Rng> && same_as<iterator_t<_Rng>, sentinel_t<_Rng>>;
|
||||
|
||||
// CONCEPT ranges::viewable_range
|
||||
template <class _Rng>
|
||||
concept viewable_range = range<_Rng> && (safe_range<_Rng> || view<remove_cvref_t<_Rng>>);
|
||||
// clang-format on
|
||||
concept viewable_range = range<_Rng>
|
||||
&& (borrowed_range<_Rng> || view<remove_cvref_t<_Rng>>);
|
||||
} // namespace ranges
|
||||
|
||||
_STD_END
|
||||
|
||||
#pragma pop_macro("new")
|
||||
|
|
|
@ -260,7 +260,7 @@ class span;
|
|||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
template <class _Ty, size_t _Extent>
|
||||
inline constexpr bool enable_safe_range<span<_Ty, _Extent>> = true;
|
||||
inline constexpr bool enable_borrowed_range<span<_Ty, _Extent>> = true;
|
||||
} // namespace ranges
|
||||
|
||||
// VARIABLE TEMPLATE _Is_span_v
|
||||
|
@ -293,7 +293,7 @@ concept _Is_span_compatible_range =
|
|||
&& !_Is_std_array_v<remove_cvref_t<_Rng>>
|
||||
&& _RANGES contiguous_range<_Rng>
|
||||
&& _RANGES sized_range<_Rng>
|
||||
&& (_RANGES safe_range<_Rng> || is_const_v<_Ty>)
|
||||
&& (_RANGES borrowed_range<_Rng> || is_const_v<_Ty>)
|
||||
&& is_convertible_v<remove_reference_t<_RANGES range_reference_t<_Rng>>(*)[], _Ty(*)[]>;
|
||||
// clang-format on
|
||||
#else // ^^^ __cpp_lib_concepts / !__cpp_lib_concepts vvv
|
||||
|
|
|
@ -1576,7 +1576,7 @@ private:
|
|||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
template <class _Elem, class _Traits>
|
||||
inline constexpr bool enable_safe_range<basic_string_view<_Elem, _Traits>> = true;
|
||||
inline constexpr bool enable_borrowed_range<basic_string_view<_Elem, _Traits>> = true;
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
|
|
259
stl/inc/xutility
259
stl/inc/xutility
|
@ -155,6 +155,16 @@ _NODISCARD constexpr auto to_address(const _Ptr& _Val) noexcept {
|
|||
return _STD to_address(_Val.operator->()); // plain pointer overload must come first
|
||||
}
|
||||
}
|
||||
|
||||
// STRUCT identity
|
||||
struct identity {
|
||||
template <class _Ty>
|
||||
_NODISCARD constexpr _Ty&& operator()(_Ty&& _Left) const noexcept {
|
||||
return _STD forward<_Ty>(_Left);
|
||||
}
|
||||
|
||||
using is_transparent = int;
|
||||
};
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
// FUNCTION TEMPLATE _Pass_fn
|
||||
|
@ -312,10 +322,10 @@ template <class>
|
|||
struct iterator_traits;
|
||||
|
||||
template <class _Ty>
|
||||
using iter_difference_t = typename conditional_t<_Is_from_primary<iterator_traits<_Ty>>, incrementable_traits<_Ty>,
|
||||
iterator_traits<_Ty>>::difference_type;
|
||||
using iter_difference_t = typename conditional_t<_Is_from_primary<iterator_traits<remove_cvref_t<_Ty>>>,
|
||||
incrementable_traits<remove_cvref_t<_Ty>>, iterator_traits<remove_cvref_t<_Ty>>>::difference_type;
|
||||
|
||||
// STRUCT TEMPLATE readable_traits
|
||||
// STRUCT TEMPLATE indirectly_readable_traits
|
||||
template <class>
|
||||
struct _Cond_value_type {};
|
||||
|
||||
|
@ -328,32 +338,32 @@ struct _Cond_value_type<_Ty> {
|
|||
// clang-format on
|
||||
|
||||
template <class>
|
||||
struct readable_traits {};
|
||||
struct indirectly_readable_traits {};
|
||||
|
||||
template <class _Ty>
|
||||
struct readable_traits<_Ty*> : _Cond_value_type<_Ty> {};
|
||||
struct indirectly_readable_traits<_Ty*> : _Cond_value_type<_Ty> {};
|
||||
|
||||
// clang-format off
|
||||
template <class _Ty>
|
||||
requires is_array_v<_Ty>
|
||||
struct readable_traits<_Ty> {
|
||||
struct indirectly_readable_traits<_Ty> {
|
||||
using value_type = remove_cv_t<remove_extent_t<_Ty>>;
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
template <class _Ty>
|
||||
struct readable_traits<const _Ty> : readable_traits<_Ty> {};
|
||||
struct indirectly_readable_traits<const _Ty> : indirectly_readable_traits<_Ty> {};
|
||||
|
||||
template <_Has_member_value_type _Ty>
|
||||
struct readable_traits<_Ty> : _Cond_value_type<typename _Ty::value_type> {};
|
||||
struct indirectly_readable_traits<_Ty> : _Cond_value_type<typename _Ty::value_type> {};
|
||||
|
||||
template <_Has_member_element_type _Ty>
|
||||
struct readable_traits<_Ty> : _Cond_value_type<typename _Ty::element_type> {};
|
||||
struct indirectly_readable_traits<_Ty> : _Cond_value_type<typename _Ty::element_type> {};
|
||||
|
||||
// ALIAS TEMPLATE iter_value_t
|
||||
template <class _Ty>
|
||||
using iter_value_t = typename conditional_t<_Is_from_primary<iterator_traits<_Ty>>, readable_traits<_Ty>,
|
||||
iterator_traits<_Ty>>::value_type;
|
||||
using iter_value_t = typename conditional_t<_Is_from_primary<iterator_traits<remove_cvref_t<_Ty>>>,
|
||||
indirectly_readable_traits<remove_cvref_t<_Ty>>, iterator_traits<remove_cvref_t<_Ty>>>::value_type;
|
||||
|
||||
// ALIAS TEMPLATE iter_reference_t
|
||||
template <_Dereferenceable _Ty>
|
||||
|
@ -411,11 +421,13 @@ concept _Cpp17_iterator = copyable<_It> && requires(_It __i) {
|
|||
};
|
||||
|
||||
template <class _It>
|
||||
concept _Cpp17_input_iterator = _Cpp17_iterator<_It> && equality_comparable<_It>
|
||||
&& _Has_member_difference_type<incrementable_traits<_It>> && _Has_member_value_type<readable_traits<_It>>
|
||||
concept _Cpp17_input_iterator = _Cpp17_iterator<_It>
|
||||
&& equality_comparable<_It>
|
||||
&& _Has_member_difference_type<incrementable_traits<_It>>
|
||||
&& _Has_member_value_type<indirectly_readable_traits<_It>>
|
||||
&& requires(_It __i) {
|
||||
typename common_reference_t<iter_reference_t<_It>&&, typename readable_traits<_It>::value_type&>;
|
||||
typename common_reference_t<decltype(*__i++)&&, typename readable_traits<_It>::value_type&>;
|
||||
typename common_reference_t<iter_reference_t<_It>&&, typename indirectly_readable_traits<_It>::value_type&>;
|
||||
typename common_reference_t<decltype(*__i++)&&, typename indirectly_readable_traits<_It>::value_type&>;
|
||||
requires signed_integral<typename incrementable_traits<_It>::difference_type>;
|
||||
};
|
||||
|
||||
|
@ -544,7 +556,7 @@ struct _Iter_traits_category2<false> {
|
|||
// clang-format off
|
||||
template <class _It>
|
||||
concept _Cpp17_forward_delta = constructible_from<_It> && is_lvalue_reference_v<iter_reference_t<_It>>
|
||||
&& same_as<remove_cvref_t<iter_reference_t<_It>>, typename readable_traits<_It>::value_type>
|
||||
&& same_as<remove_cvref_t<iter_reference_t<_It>>, typename indirectly_readable_traits<_It>::value_type>
|
||||
&& requires(_It __i) {
|
||||
{ __i++ } -> convertible_to<const _It&>;
|
||||
requires same_as<decltype(*__i++), iter_reference_t<_It>>;
|
||||
|
@ -569,7 +581,7 @@ template <class _It>
|
|||
struct _Iterator_traits_base<_It> {
|
||||
using iterator_category = typename _Iter_traits_category<_Has_member_iterator_category<_It>>::template _Apply<_It>;
|
||||
using difference_type = typename incrementable_traits<_It>::difference_type;
|
||||
using value_type = typename readable_traits<_It>::value_type;
|
||||
using value_type = typename indirectly_readable_traits<_It>::value_type;
|
||||
using pointer = typename _Iter_traits_pointer<(
|
||||
_Has_member_pointer<_It> ? _Itraits_pointer_strategy::_Use_member
|
||||
: _Has_op_arrow<_It&> ? _Itraits_pointer_strategy::_Use_decltype
|
||||
|
@ -607,12 +619,13 @@ namespace ranges {
|
|||
};
|
||||
|
||||
namespace _Iter_move {
|
||||
void iter_move(); // Block unqualified lookup per LWG-3247
|
||||
void iter_move(); // Block unqualified name lookup
|
||||
|
||||
// clang-format off
|
||||
template <class _Ty>
|
||||
concept _Has_ADL = _Has_class_or_enum_type<_Ty> // Per LWG-3299
|
||||
&& requires(_Ty&& __t) { iter_move(static_cast<_Ty&&>(__t)); };
|
||||
concept _Has_ADL = _Has_class_or_enum_type<_Ty> && requires(_Ty&& __t) {
|
||||
iter_move(static_cast<_Ty&&>(__t));
|
||||
};
|
||||
|
||||
template <class _Ty>
|
||||
concept _Can_deref = requires(_Ty&& __t) {
|
||||
|
@ -673,24 +686,29 @@ template <class _Ty>
|
|||
}
|
||||
using iter_rvalue_reference_t = decltype(_RANGES iter_move(_STD declval<_Ty&>()));
|
||||
|
||||
// CONCEPT readable
|
||||
// CONCEPT indirectly_readable
|
||||
template <class _It>
|
||||
concept readable = requires {
|
||||
concept _Indirectly_readable_impl = requires(const _It __i) {
|
||||
typename iter_value_t<_It>;
|
||||
typename iter_reference_t<_It>;
|
||||
typename iter_rvalue_reference_t<_It>;
|
||||
{ *__i } -> same_as<iter_reference_t<_It>>;
|
||||
{ _RANGES iter_move(__i) } -> same_as<iter_rvalue_reference_t<_It>>;
|
||||
} && common_reference_with<iter_reference_t<_It>&&, iter_value_t<_It>&>
|
||||
&& common_reference_with<iter_reference_t<_It>&&, iter_rvalue_reference_t<_It>&&>
|
||||
&& common_reference_with<iter_rvalue_reference_t<_It>&&, const iter_value_t<_It>&>;
|
||||
|
||||
template <class _It>
|
||||
concept indirectly_readable = _Indirectly_readable_impl<remove_cvref_t<_It>>;
|
||||
// clang-format on
|
||||
|
||||
// ALIAS TEMPLATE iter_common_reference_t
|
||||
template <readable _Ty>
|
||||
template <indirectly_readable _Ty>
|
||||
using iter_common_reference_t = common_reference_t<iter_reference_t<_Ty>, iter_value_t<_Ty>&>;
|
||||
|
||||
// CONCEPT writable
|
||||
// CONCEPT indirectly_writable
|
||||
template <class _It, class _Ty>
|
||||
concept writable = requires(_It&& __i, _Ty&& __t) {
|
||||
concept indirectly_writable = requires(_It&& __i, _Ty&& __t) {
|
||||
*__i = static_cast<_Ty&&>(__t);
|
||||
*static_cast<_It&&>(__i) = static_cast<_Ty&&>(__t);
|
||||
const_cast<const iter_reference_t<_It>&&>(*__i) = static_cast<_Ty&&>(__t);
|
||||
|
@ -707,6 +725,10 @@ concept weakly_incrementable = default_initializable<_Ty> && movable<_Ty> && req
|
|||
__i++;
|
||||
};
|
||||
|
||||
// ALIAS TEMPLATE _Make_unsigned_like_t
|
||||
template <class _Ty>
|
||||
using _Make_unsigned_like_t = make_unsigned_t<_Ty>;
|
||||
|
||||
// CONCEPT incrementable
|
||||
template <class _Ty>
|
||||
concept incrementable = regular<_Ty> && weakly_incrementable<_Ty> && requires(_Ty __t) {
|
||||
|
@ -782,14 +804,16 @@ using _Iter_concept = typename _Iter_concept_impl<_It>::type;
|
|||
// clang-format off
|
||||
// CONCEPT input_iterator
|
||||
template <class _It>
|
||||
concept input_iterator = input_or_output_iterator<_It> && readable<_It> && requires { typename _Iter_concept<_It>; }
|
||||
concept input_iterator = input_or_output_iterator<_It> && indirectly_readable<_It>
|
||||
&& requires { typename _Iter_concept<_It>; }
|
||||
&& derived_from<_Iter_concept<_It>, input_iterator_tag>;
|
||||
|
||||
// CONCEPT output_iterator
|
||||
template <class _It, class _Ty>
|
||||
concept output_iterator = input_or_output_iterator<_It> && writable<_It, _Ty> && requires(_It __i, _Ty&& __t) {
|
||||
*__i++ = static_cast<_Ty&&>(__t);
|
||||
};
|
||||
concept output_iterator = input_or_output_iterator<_It> && indirectly_writable<_It, _Ty>
|
||||
&& requires(_It __i, _Ty&& __t) {
|
||||
*__i++ = static_cast<_Ty&&>(__t);
|
||||
};
|
||||
|
||||
// CONCEPT forward_iterator
|
||||
template <class _It>
|
||||
|
@ -827,15 +851,94 @@ concept contiguous_iterator = random_access_iterator<_It>
|
|||
{ _STD to_address(__i) } -> same_as<add_pointer_t<iter_reference_t<_It>>>;
|
||||
};
|
||||
|
||||
// CONCEPT indirectly_unary_invocable
|
||||
template <class _Fn, class _It>
|
||||
concept indirectly_unary_invocable = indirectly_readable<_It>
|
||||
&& copy_constructible<_Fn>
|
||||
&& invocable<_Fn&, iter_value_t<_It>&>
|
||||
&& invocable<_Fn&, iter_reference_t<_It>>
|
||||
&& invocable<_Fn&, iter_common_reference_t<_It>>
|
||||
&& common_reference_with<
|
||||
invoke_result_t<_Fn&, iter_value_t<_It>&>,
|
||||
invoke_result_t<_Fn&, iter_reference_t<_It>>>;
|
||||
|
||||
// CONCEPT indirectly_regular_unary_invocable
|
||||
template <class _Fn, class _It>
|
||||
concept indirectly_regular_unary_invocable = indirectly_readable<_It>
|
||||
&& copy_constructible<_Fn>
|
||||
&& regular_invocable<_Fn&, iter_value_t<_It>&>
|
||||
&& regular_invocable<_Fn&, iter_reference_t<_It>>
|
||||
&& regular_invocable<_Fn&, iter_common_reference_t<_It>>
|
||||
&& common_reference_with<
|
||||
invoke_result_t<_Fn&, iter_value_t<_It>&>,
|
||||
invoke_result_t<_Fn&, iter_reference_t<_It>>>;
|
||||
|
||||
// CONCEPT indirect_unary_predicate
|
||||
template <class _Fn, class _It>
|
||||
concept indirect_unary_predicate = indirectly_readable<_It>
|
||||
&& copy_constructible<_Fn>
|
||||
&& predicate<_Fn&, iter_value_t<_It>&>
|
||||
&& predicate<_Fn&, iter_reference_t<_It>>
|
||||
&& predicate<_Fn&, iter_common_reference_t<_It>>;
|
||||
|
||||
// CONCEPT indirect_binary_predicate
|
||||
template <class _Fn, class _It1, class _It2>
|
||||
concept indirect_binary_predicate = indirectly_readable<_It1>
|
||||
&& indirectly_readable<_It2>
|
||||
&& copy_constructible<_Fn>
|
||||
&& predicate<_Fn&, iter_value_t<_It1>&, iter_value_t<_It2>&>
|
||||
&& predicate<_Fn&, iter_value_t<_It1>&, iter_reference_t<_It2>>
|
||||
&& predicate<_Fn&, iter_reference_t<_It1>, iter_value_t<_It2>&>
|
||||
&& predicate<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>>
|
||||
&& predicate<_Fn&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
|
||||
|
||||
// ALIAS TEMPLATE indirect_result_t
|
||||
template <class _Fn, class... _Its>
|
||||
requires (indirectly_readable<_Its> && ...)
|
||||
&& invocable<_Fn, iter_reference_t<_Its>...>
|
||||
using indirect_result_t = invoke_result_t<_Fn, iter_reference_t<_Its>...>;
|
||||
// clang-format on
|
||||
|
||||
// STRUCT TEMPLATE projected
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 5046) // '%s': Symbol involving type with internal linkage not defined
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wundefined-internal" // function '%s' has internal linkage but is not defined
|
||||
#endif // __clang__
|
||||
|
||||
template <indirectly_readable _It, indirectly_regular_unary_invocable<_It> _Proj>
|
||||
struct projected {
|
||||
using value_type = remove_cvref_t<indirect_result_t<_Proj&, _It>>;
|
||||
indirect_result_t<_Proj&, _It> operator*() const;
|
||||
};
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif // __clang__
|
||||
#pragma warning(pop)
|
||||
|
||||
template <weakly_incrementable _It, class _Proj>
|
||||
struct incrementable_traits<projected<_It, _Proj>> {
|
||||
using difference_type = iter_difference_t<_It>;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
// CONCEPT indirectly_movable
|
||||
template <class _In, class _Out>
|
||||
concept indirectly_movable = readable<_In> && writable<_Out, iter_rvalue_reference_t<_In>>;
|
||||
concept indirectly_movable = indirectly_readable<_In> && indirectly_writable<_Out, iter_rvalue_reference_t<_In>>;
|
||||
|
||||
// CONCEPT indirectly_movable_storable
|
||||
template <class _In, class _Out>
|
||||
concept indirectly_movable_storable = indirectly_movable<_In, _Out> && writable<_Out, iter_value_t<_In>>
|
||||
&& movable<iter_value_t<_In>> && constructible_from<iter_value_t<_In>, iter_rvalue_reference_t<_In>>
|
||||
concept indirectly_movable_storable = indirectly_movable<_In, _Out>
|
||||
&& indirectly_writable<_Out, iter_value_t<_In>>
|
||||
&& movable<iter_value_t<_In>>
|
||||
&& constructible_from<iter_value_t<_In>, iter_rvalue_reference_t<_In>>
|
||||
&& assignable_from<iter_value_t<_In>&, iter_rvalue_reference_t<_In>>;
|
||||
|
||||
// CONCEPT indirectly_copyable
|
||||
template <class _In, class _Out>
|
||||
concept indirectly_copyable = indirectly_readable<_In> && indirectly_writable<_Out, iter_reference_t<_In>>;
|
||||
// clang-format on
|
||||
|
||||
// CUSTOMIZATION POINT OBJECT iter_swap
|
||||
|
@ -846,13 +949,14 @@ namespace ranges {
|
|||
|
||||
// clang-format off
|
||||
template <class _Ty1, class _Ty2>
|
||||
concept _Has_ADL = (_Has_class_or_enum_type<_Ty1> || _Has_class_or_enum_type<_Ty2>) // Per LWG-3299
|
||||
concept _Has_ADL = (_Has_class_or_enum_type<_Ty1> || _Has_class_or_enum_type<_Ty2>)
|
||||
&& requires(_Ty1&& __t1, _Ty2&& __t2) {
|
||||
iter_swap(static_cast<_Ty1&&>(__t1), static_cast<_Ty2&&>(__t2));
|
||||
};
|
||||
|
||||
template <class _Ty1, class _Ty2>
|
||||
concept _Can_swap_references = readable<remove_reference_t<_Ty1>> && readable<remove_reference_t<_Ty2>>
|
||||
concept _Can_swap_references = indirectly_readable<remove_reference_t<_Ty1>>
|
||||
&& indirectly_readable<remove_reference_t<_Ty2>>
|
||||
&& swappable_with<iter_reference_t<_Ty1>, iter_reference_t<_Ty2>>;
|
||||
// clang-format on
|
||||
|
||||
|
@ -912,6 +1016,25 @@ namespace ranges {
|
|||
}
|
||||
} // namespace ranges
|
||||
|
||||
// clang-format off
|
||||
// CONCEPT indirectly_swappable
|
||||
template <class _It1, class _It2 = _It1>
|
||||
concept indirectly_swappable = indirectly_readable<_It1> && indirectly_readable<_It2>
|
||||
&& requires(const _It1 __i1, const _It2 __i2) {
|
||||
_RANGES iter_swap(__i1, __i1);
|
||||
_RANGES iter_swap(__i2, __i2);
|
||||
_RANGES iter_swap(__i1, __i2);
|
||||
_RANGES iter_swap(__i2, __i1);
|
||||
};
|
||||
|
||||
// CONCEPT indirectly_comparable
|
||||
template <class _It1, class _It2, class _Rel, class _Proj1 = identity, class _Proj2 = identity>
|
||||
concept indirectly_comparable =
|
||||
indirect_binary_predicate<_Rel,
|
||||
projected<_It1, _Proj1>,
|
||||
projected<_It2, _Proj2>>;
|
||||
// clang-format on
|
||||
|
||||
// ALIAS TEMPLATE _Iter_ref_t
|
||||
template <class _Iter>
|
||||
using _Iter_ref_t = iter_reference_t<_Iter>;
|
||||
|
@ -2018,14 +2141,14 @@ namespace ranges {
|
|||
inline constexpr bool _Has_complete_elements<_Ty> = true;
|
||||
// clang-format on
|
||||
|
||||
// VARIABLE TEMPLATE ranges::enable_safe_range
|
||||
// VARIABLE TEMPLATE ranges::enable_borrowed_range
|
||||
template <class>
|
||||
inline constexpr bool enable_safe_range = false;
|
||||
inline constexpr bool enable_borrowed_range = false;
|
||||
|
||||
template <class _Rng>
|
||||
concept _Should_range_access = is_lvalue_reference_v<_Rng> || enable_safe_range<remove_cvref_t<_Rng>>;
|
||||
concept _Should_range_access = is_lvalue_reference_v<_Rng> || enable_borrowed_range<remove_cvref_t<_Rng>>;
|
||||
|
||||
// CUSTOMIZATION POINT OBJECT ranges::begin (Implements D2091R0)
|
||||
// CUSTOMIZATION POINT OBJECT ranges::begin
|
||||
namespace _Begin {
|
||||
template <class _Ty>
|
||||
void begin(_Ty&) = delete;
|
||||
|
@ -2054,8 +2177,8 @@ namespace ranges {
|
|||
if constexpr (is_array_v<remove_reference_t<_Ty>>) {
|
||||
static_assert(_Has_complete_elements<_Ty>,
|
||||
"The range access customization point objects "
|
||||
"std::ranges::begin, std::ranges::end, std::ranges::rbegin, and std::ranges::rend "
|
||||
"do not accept arrays with incomplete element types.");
|
||||
"std::ranges::begin, std::ranges::end, std::ranges::rbegin, std::ranges::rend, "
|
||||
"and std::ranges::data do not accept arrays with incomplete element types.");
|
||||
return {_St::_Array, true};
|
||||
} else if constexpr (_Has_member<_Ty>) {
|
||||
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty>().begin()))};
|
||||
|
@ -2092,11 +2215,11 @@ namespace ranges {
|
|||
inline constexpr _Begin::_Cpo begin;
|
||||
}
|
||||
|
||||
// ALIAS TEMPLATE ranges::iterator_t (Implements D2091R0)
|
||||
// ALIAS TEMPLATE ranges::iterator_t
|
||||
template <class _Ty>
|
||||
using iterator_t = decltype(_RANGES begin(_STD declval<_Ty&>()));
|
||||
|
||||
// CUSTOMIZATION POINT OBJECT ranges::end (Implements D2091R0)
|
||||
// CUSTOMIZATION POINT OBJECT ranges::end
|
||||
namespace _End {
|
||||
template <class _Ty>
|
||||
void end(_Ty&) = delete;
|
||||
|
@ -2127,8 +2250,8 @@ namespace ranges {
|
|||
if constexpr (is_array_v<_UnRef>) {
|
||||
static_assert(_Has_complete_elements<_UnRef>,
|
||||
"The range access customization point objects "
|
||||
"std::ranges::begin, std::ranges::end, std::ranges::rbegin, and std::ranges::rend "
|
||||
"do not accept arrays with incomplete element types.");
|
||||
"std::ranges::begin, std::ranges::end, std::ranges::rbegin, std::ranges::rend, "
|
||||
"and std::ranges::data do not accept arrays with incomplete element types.");
|
||||
if constexpr (extent_v<_UnRef> != 0) {
|
||||
return {_St::_Array, true};
|
||||
} else {
|
||||
|
@ -2177,10 +2300,10 @@ namespace ranges {
|
|||
_RANGES end(__r);
|
||||
};
|
||||
|
||||
// CONCEPT ranges::safe_range
|
||||
// CONCEPT ranges::borrowed_range
|
||||
// clang-format off
|
||||
template <class _Rng>
|
||||
concept safe_range = range<_Rng> && _Should_range_access<_Rng>;
|
||||
concept borrowed_range = range<_Rng> && _Should_range_access<_Rng>;
|
||||
// clang-format on
|
||||
|
||||
// ALIAS TEMPLATE ranges::sentinel_t
|
||||
|
@ -2235,7 +2358,7 @@ namespace ranges {
|
|||
inline constexpr _Cend_fn cend;
|
||||
}
|
||||
|
||||
// CUSTOMIZATION POINT OBJECT ranges::rbegin (Implements D2091R0)
|
||||
// CUSTOMIZATION POINT OBJECT ranges::rbegin
|
||||
namespace _Rbegin {
|
||||
template <class _Ty>
|
||||
void rbegin(_Ty&) = delete;
|
||||
|
@ -2304,7 +2427,7 @@ namespace ranges {
|
|||
inline constexpr _Rbegin::_Cpo rbegin;
|
||||
}
|
||||
|
||||
// CUSTOMIZATION POINT OBJECT ranges::rend (Implements D2091R0)
|
||||
// CUSTOMIZATION POINT OBJECT ranges::rend
|
||||
namespace _Rend {
|
||||
template <class _Ty>
|
||||
void rend(_Ty&) = delete;
|
||||
|
@ -2410,7 +2533,7 @@ namespace ranges {
|
|||
template <class>
|
||||
inline constexpr bool disable_sized_range = false;
|
||||
|
||||
// CUSTOMIZATION POINT OBJECT ranges::size (Implements D2091R0)
|
||||
// CUSTOMIZATION POINT OBJECT ranges::size
|
||||
namespace _Size {
|
||||
template <class _Ty>
|
||||
void size(_Ty&) = delete;
|
||||
|
@ -2479,7 +2602,7 @@ namespace ranges {
|
|||
return size(_Val);
|
||||
} else if constexpr (_Choice<_Ty&>._Strategy == _St::_Subtract) {
|
||||
const auto _Delta = _RANGES end(_Val) - _RANGES begin(_Val);
|
||||
return static_cast<make_unsigned_t<remove_cv_t<decltype(_Delta)>>>(_Delta);
|
||||
return static_cast<_Make_unsigned_like_t<remove_cv_t<decltype(_Delta)>>>(_Delta);
|
||||
} else {
|
||||
static_assert(_Always_false<_Ty>, "should be unreachable");
|
||||
}
|
||||
|
@ -2492,7 +2615,7 @@ namespace ranges {
|
|||
inline constexpr _Size::_Cpo size;
|
||||
}
|
||||
|
||||
// CUSTOMIZATION POINT OBJECT ranges::empty (Implements D2091R0)
|
||||
// CUSTOMIZATION POINT OBJECT ranges::empty
|
||||
namespace _Empty {
|
||||
// clang-format off
|
||||
template <class _Ty>
|
||||
|
@ -2514,13 +2637,13 @@ namespace ranges {
|
|||
|
||||
class _Cpo {
|
||||
private:
|
||||
enum class _St { _None, _Array, _Member, _Size, _Compare };
|
||||
enum class _St { _None, _Member, _Size, _Compare };
|
||||
|
||||
template <class _Ty>
|
||||
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
|
||||
_STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>);
|
||||
if constexpr (is_array_v<remove_reference_t<_Ty>>) {
|
||||
return {_St::_Array, true};
|
||||
if constexpr (is_unbounded_array_v<remove_reference_t<_Ty>>) {
|
||||
return {_St::_None};
|
||||
} else if constexpr (_Has_member<_Ty>) {
|
||||
return {_St::_Member, noexcept(static_cast<bool>(_STD declval<_Ty>().empty()))};
|
||||
} else if constexpr (_Has_size<_Ty>) {
|
||||
|
@ -2542,9 +2665,7 @@ namespace ranges {
|
|||
template <class _Ty>
|
||||
requires (_Choice<_Ty&>._Strategy != _St::_None)
|
||||
_NODISCARD constexpr bool operator()([[maybe_unused]] _Ty&& _Val) const noexcept(_Choice<_Ty&>._No_throw) {
|
||||
if constexpr (_Choice<_Ty&>._Strategy == _St::_Array) {
|
||||
return false;
|
||||
} else if constexpr (_Choice<_Ty&>._Strategy == _St::_Member) {
|
||||
if constexpr (_Choice<_Ty&>._Strategy == _St::_Member) {
|
||||
return static_cast<bool>(_Val.empty());
|
||||
} else if constexpr (_Choice<_Ty&>._Strategy == _St::_Size) {
|
||||
return _RANGES size(_Val) == 0;
|
||||
|
@ -2562,7 +2683,7 @@ namespace ranges {
|
|||
inline constexpr _Empty::_Cpo empty;
|
||||
}
|
||||
|
||||
// CUSTOMIZATION POINT OBJECT ranges::data (Implements D2091R0)
|
||||
// CUSTOMIZATION POINT OBJECT ranges::data
|
||||
namespace _Data {
|
||||
// clang-format off
|
||||
template <class _Ty>
|
||||
|
@ -2940,6 +3061,28 @@ namespace ranges {
|
|||
|
||||
using is_transparent = int;
|
||||
};
|
||||
|
||||
// CONCEPT _Not_same_as
|
||||
template <class _Ty1, class _Ty2>
|
||||
concept _Not_same_as = !same_as<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>>;
|
||||
|
||||
// CONCEPT ranges::common_range
|
||||
// clang-format off
|
||||
template <class _Rng>
|
||||
concept common_range = range<_Rng>
|
||||
&& same_as<iterator_t<_Rng>, sentinel_t<_Rng>>;
|
||||
// clang-format on
|
||||
|
||||
// STRUCT ranges::dangling
|
||||
struct dangling {
|
||||
constexpr dangling() noexcept = default;
|
||||
template <class... _Args>
|
||||
constexpr dangling(_Args&&...) noexcept {}
|
||||
};
|
||||
|
||||
// ALIAS TEMPLATE ranges::borrowed_iterator_t
|
||||
template <range _Rng>
|
||||
using borrowed_iterator_t = conditional_t<borrowed_range<_Rng>, iterator_t<_Rng>, dangling>;
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
|
|
|
@ -169,21 +169,32 @@
|
|||
// P1024R3 Enhancing span Usability
|
||||
// P1085R2 Removing span Comparisons
|
||||
// P1115R3 erase()/erase_if() Return size_type
|
||||
// P1207R4 Movability Of Single-Pass Iterators
|
||||
// (partially implemented)
|
||||
// P1209R0 erase_if(), erase()
|
||||
// P1227R2 Signed std::ssize(), Unsigned span::size()
|
||||
// P1243R4 Rangify New Algorithms
|
||||
// (partially implemented)
|
||||
// P1248R1 Fixing Relations
|
||||
// P1357R1 is_bounded_array, is_unbounded_array
|
||||
// P1394R4 Range Constructor For span
|
||||
// P1423R3 char8_t Backward Compatibility Remediation
|
||||
// P1456R1 Move-Only Views
|
||||
// P1474R1 Helpful Pointers For contiguous_iterator
|
||||
// P1612R1 Relocating endian To <bit>
|
||||
// P1645R1 constexpr For <numeric> Algorithms
|
||||
// P1651R0 bind_front() Should Not Unwrap reference_wrapper
|
||||
// P1690R1 Refining Heterogeneous Lookup For Unordered Containers
|
||||
// P1716R3 Range Comparison Algorithms Are Over-Constrained
|
||||
// P1754R1 Rename Concepts To standard_case
|
||||
// P1870R1 safe_range
|
||||
// P1870R1 Rename forwarding-range To borrowed_range (Was safe_range before LWG-3379)
|
||||
// P1872R0 span Should Have size_type, Not index_type
|
||||
// P1878R1 Constraining Readable Types
|
||||
// P1956R1 <bit> has_single_bit(), bit_ceil(), bit_floor(), bit_width()
|
||||
// P1959R0 Removing weak_equality And strong_equality
|
||||
// P1964R2 Replacing boolean With boolean-testable
|
||||
// P2091R0 Fixing Issues With Range Access CPOs
|
||||
// P2102R0 Making "Implicit Expression Variations" More Explicit
|
||||
// P????R? directory_entry::clear_cache()
|
||||
|
||||
// _HAS_CXX20 indirectly controls:
|
||||
|
@ -1082,11 +1093,6 @@
|
|||
|
||||
#if defined(__cpp_concepts) && __cpp_concepts > 201507L
|
||||
#define __cpp_lib_concepts 201907L
|
||||
|
||||
// P0898R3 (as modified by P1754R1) std::boolean
|
||||
#ifndef _HAS_STD_BOOLEAN
|
||||
#define _HAS_STD_BOOLEAN 1
|
||||
#endif // _HAS_STD_BOOLEAN
|
||||
#endif // defined(__cpp_concepts) && __cpp_concepts > 201507L
|
||||
|
||||
#define __cpp_lib_constexpr_algorithms 201806L
|
||||
|
|
|
@ -50,6 +50,12 @@ namespace std_testing {
|
|||
// expensive, and even for relatively cheap to copy function objects we care (somewhat) about debug
|
||||
// mode perf.
|
||||
|
||||
struct Immobile {
|
||||
Immobile() = default;
|
||||
Immobile(const Immobile&) = delete;
|
||||
Immobile& operator=(const Immobile&) = delete;
|
||||
};
|
||||
|
||||
struct MoveOnly {
|
||||
MoveOnly() = default;
|
||||
MoveOnly(const MoveOnly&) = delete;
|
||||
|
@ -98,14 +104,14 @@ namespace std_testing {
|
|||
void operator()(const T&) {}
|
||||
};
|
||||
|
||||
struct Rng : MoveOnly {
|
||||
struct Rng : Immobile {
|
||||
template <typename Integral>
|
||||
Integral operator()(Integral) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Urng : MoveOnly {
|
||||
struct Urng : Immobile {
|
||||
typedef unsigned int result_type;
|
||||
unsigned int operator()() {
|
||||
return 4; // chosen by fair dice roll; guaranteed to be random
|
||||
|
|
|
@ -0,0 +1,532 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
|
||||
|
||||
namespace ranges = std::ranges;
|
||||
|
||||
template <class>
|
||||
inline constexpr bool always_false = false;
|
||||
|
||||
namespace detail {
|
||||
static constexpr bool permissive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class>
|
||||
struct DependentBase {
|
||||
static constexpr bool permissive() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Derived : DependentBase<T> {
|
||||
static constexpr bool test() {
|
||||
return permissive();
|
||||
}
|
||||
};
|
||||
}
|
||||
constexpr bool is_permissive = detail::Derived<int>::test();
|
||||
|
||||
template <bool>
|
||||
struct borrowed { // borrowed<true> is a borrowed_range; borrowed<false> is not
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
template <>
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<borrowed<true>> = true;
|
||||
|
||||
inline constexpr auto get_first = [](auto&& x) -> auto&& {
|
||||
return static_cast<decltype(x)>(x).first;
|
||||
};
|
||||
|
||||
inline constexpr auto get_second = [](auto&& x) -> auto&& {
|
||||
return static_cast<decltype(x)>(x).second;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class move_only_range : public ranges::view_base {
|
||||
// Adapts a contiguous range into a move-only view with move-only iterators
|
||||
private:
|
||||
using U = std::span<T>;
|
||||
U elements;
|
||||
mutable bool begin_called = false;
|
||||
|
||||
class iterator;
|
||||
class sentinel;
|
||||
|
||||
public:
|
||||
constexpr explicit move_only_range(U x) : elements{x} {}
|
||||
|
||||
constexpr move_only_range(move_only_range&& that)
|
||||
: elements{std::exchange(that.elements, {})}, begin_called{that.begin_called} {}
|
||||
|
||||
constexpr move_only_range& operator=(move_only_range&& that) {
|
||||
elements = std::exchange(that.elements, {});
|
||||
begin_called = that.begin_called;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr iterator begin() const {
|
||||
assert(!std::exchange(begin_called, true));
|
||||
return iterator{elements.begin()};
|
||||
}
|
||||
|
||||
constexpr sentinel end() const {
|
||||
return sentinel{elements.end()};
|
||||
}
|
||||
};
|
||||
|
||||
template <ranges::contiguous_range R>
|
||||
move_only_range(R&)->move_only_range<std::remove_reference_t<ranges::range_reference_t<R>>>;
|
||||
|
||||
template <class T>
|
||||
class move_only_range<T>::iterator {
|
||||
private:
|
||||
friend sentinel;
|
||||
ranges::iterator_t<std::span<T>> pos;
|
||||
|
||||
public:
|
||||
using iterator_concept = std::input_iterator_tag;
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = std::remove_cv_t<T>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = T&;
|
||||
|
||||
iterator() = default;
|
||||
constexpr explicit iterator(ranges::iterator_t<U> p) : pos{p} {}
|
||||
constexpr iterator(iterator&& that) : pos{std::exchange(that.pos, {})} {}
|
||||
|
||||
constexpr iterator& operator=(iterator&& that) {
|
||||
pos = std::exchange(that.pos, {});
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr ranges::iterator_t<U> base() const {
|
||||
return pos;
|
||||
}
|
||||
|
||||
constexpr T& operator*() const {
|
||||
return *pos;
|
||||
}
|
||||
constexpr iterator& operator++() {
|
||||
++pos;
|
||||
return *this;
|
||||
}
|
||||
constexpr void operator++(int) {
|
||||
++pos;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class move_only_range<T>::sentinel {
|
||||
private:
|
||||
ranges::iterator_t<U> pos;
|
||||
|
||||
public:
|
||||
sentinel() = default;
|
||||
constexpr explicit sentinel(ranges::iterator_t<U> p) : pos{p} {}
|
||||
|
||||
constexpr ranges::iterator_t<U> base() const {
|
||||
return pos;
|
||||
}
|
||||
|
||||
constexpr bool operator==(iterator const& that) const {
|
||||
return pos == that.pos;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline constexpr bool ranges::enable_borrowed_range<::move_only_range<T>> = true;
|
||||
|
||||
struct boolish {
|
||||
operator bool() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
boolish operator!() const {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Category, class ValueType, bool Sized = false>
|
||||
struct test_iterator {
|
||||
template <class T>
|
||||
static constexpr bool exactly = std::is_same_v<T, Category>;
|
||||
template <class T>
|
||||
static constexpr bool at_least = std::derived_from<Category, T>;
|
||||
|
||||
struct reference {
|
||||
operator ValueType() const requires at_least<std::input_iterator_tag> {
|
||||
return {};
|
||||
}
|
||||
void operator=(ValueType const&) const {}
|
||||
};
|
||||
|
||||
// output iterator operations
|
||||
test_iterator() = default;
|
||||
test_iterator(test_iterator&&) = default;
|
||||
test_iterator& operator=(test_iterator&&) = default;
|
||||
|
||||
reference operator*() const {
|
||||
return {};
|
||||
}
|
||||
ValueType& operator*() const requires at_least<std::contiguous_iterator_tag> {
|
||||
static ValueType value{};
|
||||
return value;
|
||||
}
|
||||
|
||||
friend boolish operator==(test_iterator const&, std::default_sentinel_t const&) {
|
||||
return {};
|
||||
}
|
||||
friend boolish operator==(std::default_sentinel_t const&, test_iterator const&) {
|
||||
return {};
|
||||
}
|
||||
friend boolish operator!=(test_iterator const&, std::default_sentinel_t const&) {
|
||||
return {};
|
||||
}
|
||||
friend boolish operator!=(std::default_sentinel_t const&, test_iterator const&) {
|
||||
return {};
|
||||
}
|
||||
|
||||
test_iterator& operator++() & {
|
||||
return *this;
|
||||
}
|
||||
test_iterator operator++(int) & {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto operator--() & {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
auto operator--(int) & {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
|
||||
friend void iter_move(test_iterator const&) {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
friend void iter_swap(test_iterator const&, test_iterator const&) {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
void operator<(test_iterator const&) const {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
void operator>(test_iterator const&) const {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
void operator<=(test_iterator const&) const {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
void operator>=(test_iterator const&) const {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
|
||||
void operator&() const {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
template <class T>
|
||||
friend void operator,(test_iterator const&, T&&) {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
|
||||
// input iterator operations:
|
||||
void operator++(int) & requires exactly<std::input_iterator_tag> {}
|
||||
friend ValueType iter_move(test_iterator const&) requires at_least<std::input_iterator_tag> {
|
||||
return {};
|
||||
}
|
||||
friend void iter_swap(test_iterator const&, test_iterator const&) requires at_least<std::input_iterator_tag> {}
|
||||
|
||||
// forward iterator operations:
|
||||
test_iterator(test_iterator const&) requires at_least<std::forward_iterator_tag> = default;
|
||||
test_iterator& operator=(test_iterator const&) requires at_least<std::forward_iterator_tag> = default;
|
||||
test_iterator operator++(int) & requires at_least<std::forward_iterator_tag> {}
|
||||
boolish operator==(test_iterator const&) const requires at_least<std::forward_iterator_tag> {
|
||||
return {};
|
||||
}
|
||||
boolish operator!=(test_iterator const&) const requires at_least<std::forward_iterator_tag> {
|
||||
return {};
|
||||
}
|
||||
|
||||
// bidirectional iterator operations:
|
||||
test_iterator& operator--() & requires at_least<std::bidirectional_iterator_tag> {
|
||||
return *this;
|
||||
}
|
||||
test_iterator operator--(int) & requires at_least<std::bidirectional_iterator_tag> {}
|
||||
|
||||
// random-access iterator operations:
|
||||
boolish operator<(test_iterator const&) const requires at_least<std::random_access_iterator_tag> {
|
||||
return {};
|
||||
}
|
||||
boolish operator>(test_iterator const&) const requires at_least<std::random_access_iterator_tag> {
|
||||
return {};
|
||||
}
|
||||
boolish operator<=(test_iterator const&) const requires at_least<std::random_access_iterator_tag> {
|
||||
return {};
|
||||
}
|
||||
boolish operator>=(test_iterator const&) const requires at_least<std::random_access_iterator_tag> {
|
||||
return {};
|
||||
}
|
||||
decltype(auto) operator[](std::ptrdiff_t) const& requires at_least<std::random_access_iterator_tag> {
|
||||
return **this;
|
||||
}
|
||||
test_iterator& operator+=(std::ptrdiff_t) & requires at_least<std::random_access_iterator_tag> {
|
||||
return *this;
|
||||
}
|
||||
test_iterator& operator-=(std::ptrdiff_t) & requires at_least<std::random_access_iterator_tag> {
|
||||
return *this;
|
||||
}
|
||||
test_iterator operator+(std::ptrdiff_t) const requires at_least<std::random_access_iterator_tag> {
|
||||
return *this;
|
||||
}
|
||||
friend test_iterator operator+(
|
||||
std::ptrdiff_t, test_iterator const& i) requires at_least<std::random_access_iterator_tag> {
|
||||
return i;
|
||||
}
|
||||
test_iterator operator-(std::ptrdiff_t) const requires at_least<std::random_access_iterator_tag> {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// sized_sentinel_for operations:
|
||||
std::ptrdiff_t operator-(test_iterator const&) const requires Sized || at_least<std::random_access_iterator_tag> {
|
||||
return 42;
|
||||
}
|
||||
friend std::ptrdiff_t operator-(std::default_sentinel_t, test_iterator const&) requires Sized {
|
||||
return 42;
|
||||
}
|
||||
friend std::ptrdiff_t operator-(test_iterator const&, std::default_sentinel_t) requires Sized {
|
||||
return -42;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Category, class ValueType, bool Sized>
|
||||
struct std::iterator_traits<::test_iterator<Category, ValueType, Sized>> {
|
||||
using iterator_concept = Category;
|
||||
using iterator_category = Category; // TRANSITION, LWG-3289
|
||||
using value_type = ValueType;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = iter_reference_t<::test_iterator<Category, ValueType, Sized>>;
|
||||
};
|
||||
|
||||
template <class ValueType, bool Sized>
|
||||
struct std::pointer_traits<::test_iterator<std::contiguous_iterator_tag, ValueType, Sized>> {
|
||||
using pointer = ::test_iterator<contiguous_iterator_tag, ValueType, Sized>;
|
||||
using element_type = ValueType;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
[[nodiscard]] static constexpr element_type* to_address(pointer) noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
STATIC_ASSERT(std::output_iterator<test_iterator<std::output_iterator_tag, int, false>, int>);
|
||||
STATIC_ASSERT(std::input_iterator<test_iterator<std::input_iterator_tag, int, false>>);
|
||||
STATIC_ASSERT(std::forward_iterator<test_iterator<std::forward_iterator_tag, int, false>>);
|
||||
STATIC_ASSERT(std::bidirectional_iterator<test_iterator<std::bidirectional_iterator_tag, int, false>>);
|
||||
STATIC_ASSERT(std::random_access_iterator<test_iterator<std::random_access_iterator_tag, int, false>>);
|
||||
STATIC_ASSERT(std::contiguous_iterator<test_iterator<std::contiguous_iterator_tag, int, false>>);
|
||||
|
||||
STATIC_ASSERT(std::output_iterator<test_iterator<std::output_iterator_tag, int, true>, int>);
|
||||
STATIC_ASSERT(std::input_iterator<test_iterator<std::input_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::forward_iterator<test_iterator<std::forward_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::bidirectional_iterator<test_iterator<std::bidirectional_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::random_access_iterator<test_iterator<std::random_access_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::contiguous_iterator<test_iterator<std::contiguous_iterator_tag, int, true>>);
|
||||
|
||||
STATIC_ASSERT(std::sized_sentinel_for<std::default_sentinel_t, test_iterator<std::output_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::sized_sentinel_for<std::default_sentinel_t, test_iterator<std::input_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::sized_sentinel_for<std::default_sentinel_t, test_iterator<std::forward_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(
|
||||
std::sized_sentinel_for<std::default_sentinel_t, test_iterator<std::bidirectional_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(
|
||||
std::sized_sentinel_for<std::default_sentinel_t, test_iterator<std::random_access_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::sized_sentinel_for<std::default_sentinel_t, test_iterator<std::contiguous_iterator_tag, int, true>>);
|
||||
|
||||
STATIC_ASSERT(std::sized_sentinel_for<test_iterator<std::forward_iterator_tag, int, true>,
|
||||
test_iterator<std::forward_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::sized_sentinel_for<test_iterator<std::bidirectional_iterator_tag, int, true>,
|
||||
test_iterator<std::bidirectional_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::sized_sentinel_for<test_iterator<std::random_access_iterator_tag, int, true>,
|
||||
test_iterator<std::random_access_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(std::sized_sentinel_for<test_iterator<std::contiguous_iterator_tag, int, true>,
|
||||
test_iterator<std::contiguous_iterator_tag, int, true>>);
|
||||
|
||||
template <class Category, class ValueType, bool Sized = false, bool Common = false>
|
||||
struct test_range {
|
||||
using I = test_iterator<Category, ValueType, Sized>;
|
||||
using S = std::conditional_t<Common && std::derived_from<Category, std::forward_iterator_tag>, I,
|
||||
std::default_sentinel_t>;
|
||||
|
||||
I begin() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
S end() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ptrdiff_t size() const requires Sized {
|
||||
return 42;
|
||||
}
|
||||
|
||||
ValueType* data() const requires std::derived_from<Category, std::contiguous_iterator_tag> {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void operator&() const {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
template <class T>
|
||||
friend void operator,(test_range const&, T&&) {
|
||||
STATIC_ASSERT(always_false<Category>);
|
||||
}
|
||||
};
|
||||
|
||||
STATIC_ASSERT(ranges::output_range<test_range<std::output_iterator_tag, int, false>, int>);
|
||||
STATIC_ASSERT(ranges::input_range<test_range<std::input_iterator_tag, int, false>>);
|
||||
STATIC_ASSERT(ranges::forward_range<test_range<std::forward_iterator_tag, int, false>>);
|
||||
STATIC_ASSERT(ranges::bidirectional_range<test_range<std::bidirectional_iterator_tag, int, false>>);
|
||||
STATIC_ASSERT(ranges::random_access_range<test_range<std::random_access_iterator_tag, int, false>>);
|
||||
STATIC_ASSERT(ranges::contiguous_range<test_range<std::contiguous_iterator_tag, int, false>>);
|
||||
|
||||
STATIC_ASSERT(ranges::output_range<test_range<std::output_iterator_tag, int, true>, int>);
|
||||
STATIC_ASSERT(ranges::input_range<test_range<std::input_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::forward_range<test_range<std::forward_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::bidirectional_range<test_range<std::bidirectional_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::random_access_range<test_range<std::random_access_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::contiguous_range<test_range<std::contiguous_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::output_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::input_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::forward_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::bidirectional_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::random_access_iterator_tag, int, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::contiguous_iterator_tag, int, true>>);
|
||||
|
||||
STATIC_ASSERT(ranges::forward_range<test_range<std::forward_iterator_tag, int, true, true>>);
|
||||
STATIC_ASSERT(ranges::bidirectional_range<test_range<std::bidirectional_iterator_tag, int, true, true>>);
|
||||
STATIC_ASSERT(ranges::random_access_range<test_range<std::random_access_iterator_tag, int, true, true>>);
|
||||
STATIC_ASSERT(ranges::contiguous_range<test_range<std::contiguous_iterator_tag, int, true, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::forward_iterator_tag, int, true, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::bidirectional_iterator_tag, int, true, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::random_access_iterator_tag, int, true, true>>);
|
||||
STATIC_ASSERT(ranges::sized_range<test_range<std::contiguous_iterator_tag, int, true, true>>);
|
||||
|
||||
template <int>
|
||||
struct unique_tag {};
|
||||
|
||||
template <class I, int Tag = 0>
|
||||
using ProjectionFor = unique_tag<Tag> (*)(std::iter_common_reference_t<I>);
|
||||
|
||||
template <class I>
|
||||
using UnaryPredicateFor = boolish (*)(std::iter_common_reference_t<I>);
|
||||
|
||||
template <int Tag = 0>
|
||||
using ProjectedUnaryPredicate = boolish (*)(unique_tag<Tag>);
|
||||
template <class I2, int Tag1 = 0>
|
||||
using HalfProjectedBinaryPredicateFor = boolish (*)(unique_tag<Tag1>, std::iter_common_reference_t<I2>);
|
||||
template <int Tag1 = 0, int Tag2 = 0>
|
||||
using ProjectedBinaryPredicate = boolish (*)(unique_tag<Tag1>, unique_tag<Tag2>);
|
||||
|
||||
template <class I1, class I2>
|
||||
using BinaryPredicateFor = boolish (*)(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>);
|
||||
|
||||
template <class Continuation>
|
||||
struct with_output_iterators {
|
||||
template <class... Args>
|
||||
static void call() {
|
||||
Continuation::template call<Args..., test_iterator<std::output_iterator_tag, int>>();
|
||||
Continuation::template call<Args..., test_iterator<std::input_iterator_tag, int>>();
|
||||
Continuation::template call<Args..., test_iterator<std::forward_iterator_tag, int, false>>();
|
||||
Continuation::template call<Args..., test_iterator<std::forward_iterator_tag, int, true>>();
|
||||
Continuation::template call<Args..., test_iterator<std::bidirectional_iterator_tag, int, false>>();
|
||||
Continuation::template call<Args..., test_iterator<std::bidirectional_iterator_tag, int, true>>();
|
||||
Continuation::template call<Args..., test_iterator<std::random_access_iterator_tag, int>>();
|
||||
Continuation::template call<Args..., test_iterator<std::contiguous_iterator_tag, int>>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Continuation>
|
||||
struct with_input_ranges {
|
||||
template <class... Args>
|
||||
static void call() {
|
||||
Continuation::template call<Args..., test_range<std::input_iterator_tag, int, false>>();
|
||||
Continuation::template call<Args..., test_range<std::input_iterator_tag, int, true>>();
|
||||
|
||||
Continuation::template call<Args..., test_range<std::forward_iterator_tag, int, false, false>>();
|
||||
Continuation::template call<Args..., test_range<std::forward_iterator_tag, int, false, true>>();
|
||||
Continuation::template call<Args..., test_range<std::forward_iterator_tag, int, true, false>>();
|
||||
Continuation::template call<Args..., test_range<std::forward_iterator_tag, int, true, true>>();
|
||||
|
||||
Continuation::template call<Args..., test_range<std::bidirectional_iterator_tag, int, false, false>>();
|
||||
Continuation::template call<Args..., test_range<std::bidirectional_iterator_tag, int, false, true>>();
|
||||
Continuation::template call<Args..., test_range<std::bidirectional_iterator_tag, int, true, false>>();
|
||||
Continuation::template call<Args..., test_range<std::bidirectional_iterator_tag, int, true, true>>();
|
||||
|
||||
Continuation::template call<Args..., test_range<std::random_access_iterator_tag, int, true, false>>();
|
||||
Continuation::template call<Args..., test_range<std::random_access_iterator_tag, int, true, true>>();
|
||||
|
||||
Continuation::template call<Args..., test_range<std::contiguous_iterator_tag, int, true, false>>();
|
||||
Continuation::template call<Args..., test_range<std::contiguous_iterator_tag, int, true, true>>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Continuation>
|
||||
struct with_input_iterators {
|
||||
template <class... Args>
|
||||
static void call() {
|
||||
Continuation::template call<Args..., test_iterator<std::input_iterator_tag, int>>();
|
||||
Continuation::template call<Args..., test_iterator<std::forward_iterator_tag, int, false>>();
|
||||
Continuation::template call<Args..., test_iterator<std::forward_iterator_tag, int, true>>();
|
||||
Continuation::template call<Args..., test_iterator<std::bidirectional_iterator_tag, int, false>>();
|
||||
Continuation::template call<Args..., test_iterator<std::bidirectional_iterator_tag, int, true>>();
|
||||
Continuation::template call<Args..., test_iterator<std::random_access_iterator_tag, int>>();
|
||||
Continuation::template call<Args..., test_iterator<std::contiguous_iterator_tag, int>>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Continuation>
|
||||
struct with_difference {
|
||||
template <class Iterator>
|
||||
static void call() {
|
||||
Continuation::template call<Iterator, std::iter_difference_t<Iterator>>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Instantiator>
|
||||
void test_out() {
|
||||
with_output_iterators<Instantiator>::call();
|
||||
}
|
||||
|
||||
template <class Instantiator>
|
||||
void test_in() {
|
||||
with_input_ranges<Instantiator>::call();
|
||||
}
|
||||
|
||||
template <class Instantiator>
|
||||
void test_in_in() {
|
||||
with_input_ranges<with_input_ranges<Instantiator>>::call();
|
||||
}
|
||||
|
||||
template <class Instantiator>
|
||||
void test_in_out() {
|
||||
with_input_ranges<with_output_iterators<Instantiator>>::call();
|
||||
}
|
||||
|
||||
template <class Instantiator>
|
||||
void test_counted_out() {
|
||||
with_input_iterators<with_difference<with_output_iterators<Instantiator>>>::call();
|
||||
}
|
|
@ -225,6 +225,22 @@ tests\P0769R2_shift_left_shift_right
|
|||
tests\P0784R7_library_support_for_more_constexpr_containers
|
||||
tests\P0811R3_midpoint_lerp
|
||||
tests\P0896R4_P1614R2_comparisons
|
||||
tests\P0896R4_ranges_algorithm_machinery
|
||||
tests\P0896R4_ranges_alg_all_of
|
||||
tests\P0896R4_ranges_alg_any_of
|
||||
tests\P0896R4_ranges_alg_copy
|
||||
tests\P0896R4_ranges_alg_copy_if
|
||||
tests\P0896R4_ranges_alg_copy_n
|
||||
tests\P0896R4_ranges_alg_count
|
||||
tests\P0896R4_ranges_alg_count_if
|
||||
tests\P0896R4_ranges_alg_equal
|
||||
tests\P0896R4_ranges_alg_find
|
||||
tests\P0896R4_ranges_alg_find_if
|
||||
tests\P0896R4_ranges_alg_find_if_not
|
||||
tests\P0896R4_ranges_alg_for_each
|
||||
tests\P0896R4_ranges_alg_for_each_n
|
||||
tests\P0896R4_ranges_alg_mismatch
|
||||
tests\P0896R4_ranges_alg_none_of
|
||||
tests\P0896R4_ranges_iterator_machinery
|
||||
tests\P0896R4_ranges_range_machinery
|
||||
tests\P0896R4_ranges_to_address
|
||||
|
|
|
@ -75,8 +75,8 @@ static_assert(is_same_v<iterator_traits<span<const int, 3>::iterator>::pointer,
|
|||
static_assert(is_same_v<span<const int, 3>::reverse_iterator, reverse_iterator<span<const int, 3>::iterator>>);
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
static_assert(ranges::enable_safe_range<span<int>>);
|
||||
static_assert(ranges::enable_safe_range<span<int, 3>>);
|
||||
static_assert(ranges::enable_borrowed_range<span<int>>);
|
||||
static_assert(ranges::enable_borrowed_range<span<int, 3>>);
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
static_assert(is_base_of_v<integral_constant<size_t, 3>, tuple_size<span<int, 3>>>);
|
||||
|
@ -106,7 +106,7 @@ static_assert(!is_convertible_v<Derived (*)[], Base (*)[]>);
|
|||
|
||||
struct NonRange {};
|
||||
|
||||
template <typename T, bool Safe = false>
|
||||
template <typename T, bool Borrowed = false>
|
||||
struct BasicRange {
|
||||
T elements[3]{};
|
||||
|
||||
|
@ -141,15 +141,15 @@ struct BasicRange {
|
|||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace std::ranges {
|
||||
template <typename T, bool Safe>
|
||||
inline constexpr bool enable_safe_range<BasicRange<T, Safe>> = Safe;
|
||||
template <typename T, bool Borrowed>
|
||||
inline constexpr bool enable_borrowed_range<BasicRange<T, Borrowed>> = Borrowed;
|
||||
}
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
using ContiguousSizedRange = BasicRange<int>;
|
||||
|
||||
// Not truly a model of safe_range; this is a convenient fiction for testing purposes.
|
||||
using SafeContiguousSizedRange = BasicRange<int, true>;
|
||||
// Not truly a model of borrowed_range; this is a convenient fiction for testing purposes.
|
||||
using BorrowedContiguousSizedRange = BasicRange<int, true>;
|
||||
|
||||
template <typename T, size_t Extent = dynamic_extent>
|
||||
constexpr void FunctionTakingSpan(type_identity_t<span<T, Extent>>) {}
|
||||
|
@ -591,24 +591,24 @@ constexpr bool test() {
|
|||
|
||||
#ifdef __cpp_lib_concepts
|
||||
static_assert(!is_constructible_v<span<int>, ContiguousSizedRange>);
|
||||
static_assert(is_constructible_v<span<int>, SafeContiguousSizedRange>);
|
||||
static_assert(is_constructible_v<span<int>, BorrowedContiguousSizedRange>);
|
||||
static_assert(is_constructible_v<span<const int>, ContiguousSizedRange>);
|
||||
|
||||
static_assert(is_convertible_v<SafeContiguousSizedRange, span<int>>);
|
||||
static_assert(is_convertible_v<BorrowedContiguousSizedRange, span<int>>);
|
||||
static_assert(is_convertible_v<ContiguousSizedRange, span<const int>>);
|
||||
|
||||
SafeContiguousSizedRange safe_user_range;
|
||||
BorrowedContiguousSizedRange borrowed_user_range;
|
||||
|
||||
span<int> sp_4(move(safe_user_range));
|
||||
span<int> sp_4(move(borrowed_user_range));
|
||||
span<const int> sp_5(move(user_range));
|
||||
|
||||
assert(sp_4.data() == safe_user_range.data());
|
||||
assert(sp_4.data() == borrowed_user_range.data());
|
||||
assert(sp_5.data() == user_range.data());
|
||||
|
||||
assert(sp_4.size() == 3);
|
||||
assert(sp_5.size() == 3);
|
||||
|
||||
FunctionTakingSpan<int>(move(safe_user_range));
|
||||
FunctionTakingSpan<int>(move(borrowed_user_range));
|
||||
FunctionTakingSpan<const int>(move(user_range));
|
||||
|
||||
static_assert(is_same_v<decltype(span{user_range}), span<int>>);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
inline constexpr auto is_even = [](auto const& x) { return x % 2 == 0; };
|
||||
inline constexpr auto is_odd = [](auto const& x) { return x % 2 != 0; };
|
||||
|
||||
using R = std::array<std::pair<int, int>, 3>;
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::all_of;
|
||||
constexpr R pairs = {{{0, 13}, {2, 13}, {4, 13}}};
|
||||
|
||||
assert(all_of(move_only_range{pairs}, is_even, get_first));
|
||||
assert(!all_of(move_only_range{pairs}, is_even, get_second));
|
||||
assert(!all_of(move_only_range{pairs}, is_odd, get_first));
|
||||
assert(all_of(move_only_range{pairs}, is_odd, get_second));
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(all_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_even, get_first));
|
||||
}
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(!all_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_even, get_second));
|
||||
}
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(!all_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_odd, get_first));
|
||||
}
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(all_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_odd, get_second));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In>
|
||||
static void call(In&& in = {}) {
|
||||
(void) ranges::all_of(in, UnaryPredicateFor<ranges::iterator_t<In>>{});
|
||||
(void) ranges::all_of(in, ProjectedUnaryPredicate<>{}, ProjectionFor<ranges::iterator_t<In>>{});
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr auto is_even = [](auto const& x) { return x % 2 == 0; };
|
||||
constexpr auto is_odd = [](auto const& x) { return x % 2 != 0; };
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::any_of;
|
||||
constexpr std::array<std::pair<int, int>, 3> pairs = {{{0, 13}, {7, 13}, {4, 13}}};
|
||||
|
||||
assert(any_of(move_only_range{pairs}, is_even, get_first));
|
||||
assert(!any_of(move_only_range{pairs}, is_even, get_second));
|
||||
assert(any_of(move_only_range{pairs}, is_odd, get_first));
|
||||
assert(any_of(move_only_range{pairs}, is_odd, get_second));
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(any_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_even, get_first));
|
||||
}
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(!any_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_even, get_second));
|
||||
}
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(any_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_odd, get_first));
|
||||
}
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(any_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_odd, get_second));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In>
|
||||
static void call(In&& in = {}) {
|
||||
(void) ranges::any_of(in, UnaryPredicateFor<ranges::iterator_t<In>>{});
|
||||
(void) ranges::any_of(in, ProjectedUnaryPredicate<>{}, ProjectionFor<ranges::iterator_t<In>>{});
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,59 @@
|
|||
// 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>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::copy, ranges::copy_result, ranges::iterator_t;
|
||||
using std::same_as;
|
||||
|
||||
// Validate that copy_result aliases in_out_result
|
||||
STATIC_ASSERT(same_as<copy_result<int, double>, ranges::in_out_result<int, double>>);
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(
|
||||
same_as<decltype(copy(borrowed<false>{}, static_cast<int*>(nullptr))), copy_result<ranges::dangling, int*>>);
|
||||
STATIC_ASSERT(same_as<decltype(copy(borrowed<true>{}, static_cast<int*>(nullptr))), copy_result<int*, int*>>);
|
||||
|
||||
int const input[] = {13, 42, 1729};
|
||||
{ // Validate range overload
|
||||
int output[] = {-1, -1, -1};
|
||||
auto result = copy(move_only_range{input}, move_only_range{output}.begin());
|
||||
STATIC_ASSERT(same_as<decltype(result),
|
||||
copy_result<iterator_t<move_only_range<int const>>, iterator_t<move_only_range<int>>>>);
|
||||
assert(result.in == move_only_range{input}.end());
|
||||
assert(result.out == move_only_range{output}.end());
|
||||
assert(ranges::equal(output, input));
|
||||
}
|
||||
{ // Validate iterator + sentinel overload
|
||||
int output[] = {-1, -1, -1};
|
||||
move_only_range wrapped_input{input};
|
||||
auto result = copy(wrapped_input.begin(), wrapped_input.end(), move_only_range{output}.begin());
|
||||
STATIC_ASSERT(same_as<decltype(result),
|
||||
copy_result<iterator_t<move_only_range<int const>>, iterator_t<move_only_range<int>>>>);
|
||||
assert(result.in == wrapped_input.end());
|
||||
assert(result.out == move_only_range{output}.end());
|
||||
assert(ranges::equal(output, input));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In, class Out>
|
||||
static void call(In&& in = {}, Out out = {}) {
|
||||
(void) ranges::copy(in, std::move(out));
|
||||
(void) ranges::copy(ranges::begin(in), ranges::end(in), std::move(out));
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in_out<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <compare>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
template <class T, class U>
|
||||
struct not_pair {
|
||||
T first;
|
||||
U second;
|
||||
|
||||
auto operator<=>(const not_pair&) const = default;
|
||||
};
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::copy_if, ranges::copy_if_result, ranges::iterator_t;
|
||||
using std::same_as;
|
||||
using P = not_pair<int, int>;
|
||||
|
||||
constexpr auto is_odd = [](int x) { return x % 2 != 0; };
|
||||
|
||||
// Validate that copy_if_result aliases in_out_result
|
||||
STATIC_ASSERT(same_as<copy_if_result<int, double>, ranges::in_out_result<int, double>>);
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(same_as<decltype(copy_if(borrowed<false>{}, static_cast<int*>(nullptr), is_odd)),
|
||||
copy_if_result<ranges::dangling, int*>>);
|
||||
STATIC_ASSERT(
|
||||
same_as<decltype(copy_if(borrowed<true>{}, static_cast<int*>(nullptr), is_odd)), copy_if_result<int*, int*>>);
|
||||
|
||||
std::array<P, 3> const input = {{{1, 99}, {4, 98}, {5, 97}}};
|
||||
std::array<P, 2> const expected = {{{1, 99}, {5, 97}}};
|
||||
using I = iterator_t<move_only_range<P const>>;
|
||||
using O = iterator_t<move_only_range<P>>;
|
||||
{ // Validate range overload
|
||||
std::array<P, 2> output = {};
|
||||
auto result = copy_if(move_only_range{input}, move_only_range{output}.begin(), is_odd, get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), copy_if_result<I, O>>);
|
||||
assert(result.in == move_only_range{input}.end());
|
||||
assert(result.out == move_only_range{output}.end());
|
||||
assert(ranges::equal(output, expected));
|
||||
}
|
||||
{ // Validate iterator + sentinel overload
|
||||
std::array<P, 2> output = {};
|
||||
move_only_range wrapped_input{input};
|
||||
auto result =
|
||||
copy_if(wrapped_input.begin(), wrapped_input.end(), move_only_range{output}.begin(), is_odd, get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), copy_if_result<I, O>>);
|
||||
assert(result.in == wrapped_input.end());
|
||||
assert(result.out == move_only_range{output}.end());
|
||||
assert(ranges::equal(output, expected));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In, class Out>
|
||||
static void call(In&& in = {}, Out out = {}) {
|
||||
using ranges::begin, ranges::copy_if, ranges::end, ranges::iterator_t;
|
||||
|
||||
constexpr UnaryPredicateFor<iterator_t<In>> pred{};
|
||||
constexpr ProjectionFor<iterator_t<In>> proj{};
|
||||
|
||||
copy_if(in, std::move(out), pred);
|
||||
copy_if(begin(in), end(in), std::move(out), pred);
|
||||
copy_if(in, std::move(out), ProjectedUnaryPredicate<>{}, proj);
|
||||
copy_if(begin(in), end(in), std::move(out), ProjectedUnaryPredicate<>{}, proj);
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in_out<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,42 @@
|
|||
// 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>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::copy_n, ranges::copy_n_result, ranges::iterator_t;
|
||||
using std::same_as;
|
||||
|
||||
// Validate that copy_n_result aliases in_out_result
|
||||
STATIC_ASSERT(same_as<copy_n_result<int, double>, ranges::in_out_result<int, double>>);
|
||||
|
||||
int const input[] = {13, 42, 1729};
|
||||
int output[] = {-1, -1, -1};
|
||||
move_only_range wrapped_input{input};
|
||||
auto result = copy_n(wrapped_input.begin(), ranges::distance(input), move_only_range{output}.begin());
|
||||
STATIC_ASSERT(same_as<decltype(result),
|
||||
copy_n_result<iterator_t<move_only_range<int const>>, iterator_t<move_only_range<int>>>>);
|
||||
assert(result.in == wrapped_input.end());
|
||||
assert(result.out == move_only_range{output}.end());
|
||||
assert(ranges::equal(output, input));
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In, class, class Out>
|
||||
static void call(In in = {}, std::iter_difference_t<In> const count = 42, Out out = {}) {
|
||||
(void) ranges::copy_n(std::move(in), count, std::move(out));
|
||||
}
|
||||
};
|
||||
|
||||
template void test_counted_out<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::count;
|
||||
using P = std::pair<int, int>;
|
||||
std::array<P, 5> const x = {{{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}};
|
||||
using D = ranges::range_difference_t<move_only_range<P const>>;
|
||||
|
||||
{
|
||||
// Validate range overload
|
||||
auto result = count(move_only_range{x}, 99, get_second);
|
||||
STATIC_ASSERT(std::same_as<decltype(result), D>);
|
||||
assert(result == 3);
|
||||
}
|
||||
{
|
||||
// Validate iterator + sentinel overload
|
||||
move_only_range wrapped_x{x};
|
||||
auto result = count(wrapped_x.begin(), wrapped_x.end(), 47, get_second);
|
||||
STATIC_ASSERT(std::same_as<decltype(result), D>);
|
||||
assert(result == 2);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In>
|
||||
static void call(In&& in = {}) {
|
||||
ranges::range_value_t<In> const value{};
|
||||
(void) ranges::count(in, value);
|
||||
|
||||
struct type {
|
||||
bool operator==(type const&) const = default;
|
||||
};
|
||||
using Projection = type (*)(std::iter_common_reference_t<ranges::iterator_t<In>>);
|
||||
(void) ranges::count(in, type{}, Projection{});
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr auto is_even = [](auto const& x) { return x % 2 == 0; };
|
||||
constexpr auto is_odd = [](auto const& x) { return x % 2 != 0; };
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::count_if;
|
||||
using P = std::pair<int, int>;
|
||||
std::array<P, 5> const x = {{{0, 47}, {1, 99}, {2, 99}, {3, 47}, {4, 99}}};
|
||||
using D = ranges::range_difference_t<move_only_range<P const>>;
|
||||
|
||||
{
|
||||
// Validate range overload
|
||||
auto result = count_if(move_only_range{x}, is_even, get_first);
|
||||
STATIC_ASSERT(std::same_as<decltype(result), D>);
|
||||
assert(result == 3);
|
||||
}
|
||||
{
|
||||
// Validate iterator + sentinel overload
|
||||
move_only_range wrapped_x{x};
|
||||
auto result = count_if(wrapped_x.begin(), wrapped_x.end(), is_odd, get_first);
|
||||
STATIC_ASSERT(std::same_as<decltype(result), D>);
|
||||
assert(result == 2);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In>
|
||||
static void call(In&& in = {}) {
|
||||
using ranges::iterator_t;
|
||||
using I = iterator_t<In>;
|
||||
|
||||
(void) ranges::count_if(in, UnaryPredicateFor<I>{});
|
||||
(void) ranges::count_if(in, ProjectedUnaryPredicate<>{}, ProjectionFor<I>{});
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <cstdlib>
|
||||
#include <ranges>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::equal, ranges::equal_to;
|
||||
using std::abort, std::array, std::pair, std::same_as;
|
||||
|
||||
array<pair<int, int>, 3> const x = {{{0, 42}, {2, 42}, {4, 42}}};
|
||||
array<pair<long, long>, 3> const y = {{{13, -1}, {13, 1}, {13, 3}}};
|
||||
|
||||
constexpr auto cmp = [](auto&& x, auto&& y) { return x == y + 1; };
|
||||
|
||||
{
|
||||
// Validate sized ranges
|
||||
auto result = equal(x, y, cmp, get_first, get_second);
|
||||
STATIC_ASSERT(same_as<decltype(result), bool>);
|
||||
assert(result);
|
||||
assert(!equal(x, y, cmp, get_first, get_first));
|
||||
}
|
||||
{
|
||||
// Validate non-sized ranges
|
||||
auto result = equal(move_only_range{x}, move_only_range{y}, cmp, get_first, get_second);
|
||||
STATIC_ASSERT(same_as<decltype(result), bool>);
|
||||
assert(result);
|
||||
assert(!equal(move_only_range{x}, move_only_range{y}, cmp, get_first, get_first));
|
||||
}
|
||||
{
|
||||
// Validate sized iterator + sentinel pairs
|
||||
auto result = equal(x.begin(), x.end(), y.begin(), y.end(), cmp, get_first, get_second);
|
||||
STATIC_ASSERT(same_as<decltype(result), bool>);
|
||||
assert(result);
|
||||
assert(!equal(x.begin(), x.end(), y.begin(), y.end(), cmp, get_first, get_first));
|
||||
}
|
||||
{
|
||||
// Validate non-sized iterator + sentinel pairs
|
||||
move_only_range wrapped_x{x};
|
||||
move_only_range wrapped_y{y};
|
||||
auto result =
|
||||
equal(wrapped_x.begin(), wrapped_x.end(), wrapped_y.begin(), wrapped_y.end(), cmp, get_first, get_second);
|
||||
STATIC_ASSERT(same_as<decltype(result), bool>);
|
||||
assert(result);
|
||||
wrapped_x = move_only_range{x};
|
||||
wrapped_y = move_only_range{y};
|
||||
assert(
|
||||
!equal(wrapped_x.begin(), wrapped_x.end(), wrapped_y.begin(), wrapped_y.end(), cmp, get_first, get_first));
|
||||
}
|
||||
{
|
||||
// calls with sized ranges of differing size perform no comparisons nor projections
|
||||
constexpr auto proj = [](auto &&) -> int { abort(); };
|
||||
constexpr auto comp = [](auto&&, auto &&) -> bool { abort(); };
|
||||
int const one_int[] = {0};
|
||||
int const two_ints[] = {0, 1};
|
||||
assert(!equal(one_int, two_ints, comp, proj, proj));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In1, class In2>
|
||||
static void call(In1&& in1 = {}, In2&& in2 = {}) {
|
||||
using ranges::begin, ranges::end, ranges::equal, ranges::iterator_t;
|
||||
|
||||
if constexpr (!is_permissive) {
|
||||
(void) equal(in1, in2);
|
||||
(void) equal(begin(in1), end(in1), begin(in2), end(in2));
|
||||
}
|
||||
|
||||
BinaryPredicateFor<iterator_t<In1>, iterator_t<In2>> pred{};
|
||||
(void) equal(in1, in2, pred);
|
||||
(void) equal(begin(in1), end(in1), begin(in2), end(in2), pred);
|
||||
|
||||
HalfProjectedBinaryPredicateFor<iterator_t<In2>> halfpred{};
|
||||
ProjectionFor<iterator_t<In1>> halfproj{};
|
||||
(void) equal(in1, in2, halfpred, halfproj);
|
||||
(void) equal(begin(in1), end(in1), begin(in2), end(in2), halfpred, halfproj);
|
||||
|
||||
ProjectedBinaryPredicate<0, 1> projpred{};
|
||||
ProjectionFor<iterator_t<In1>, 0> proj1{};
|
||||
ProjectionFor<iterator_t<In2>, 1> proj2{};
|
||||
(void) equal(in1, in2, projpred, proj1, proj2);
|
||||
(void) equal(begin(in1), end(in1), begin(in2), end(in2), projpred, proj1, proj2);
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::find, ranges::iterator_t, std::same_as;
|
||||
using P = std::pair<int, int>;
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(same_as<decltype(find(borrowed<false>{}, 42)), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(find(borrowed<true>{}, 42)), int*>);
|
||||
|
||||
std::array<P, 3> const pairs = {{{0, 42}, {2, 42}, {4, 42}}};
|
||||
|
||||
for (auto [value, _] : pairs) {
|
||||
{
|
||||
// Validate range overload [found case]
|
||||
auto result = find(move_only_range{pairs}, value, get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P const>>>);
|
||||
assert((*result).first == value);
|
||||
}
|
||||
{
|
||||
// Validate iterator + sentinel overload [found case]
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
auto result = find(wrapped_pairs.begin(), wrapped_pairs.end(), value, get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P const>>>);
|
||||
assert((*result).first == value);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Validate range overload [not found case]
|
||||
auto result = find(move_only_range{pairs}, 42, get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P const>>>);
|
||||
assert(result == move_only_range{pairs}.end());
|
||||
}
|
||||
{
|
||||
// Validate iterator + sentinel overload [not found case]
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
auto result = find(wrapped_pairs.begin(), wrapped_pairs.end(), 42, get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P const>>>);
|
||||
assert(result == wrapped_pairs.end());
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In>
|
||||
static void call(In&& in = {}) {
|
||||
ranges::range_value_t<In> const value{};
|
||||
(void) ranges::find(in, value);
|
||||
|
||||
struct type {
|
||||
bool operator==(type const&) const = default;
|
||||
};
|
||||
using Projection = type (*)(std::iter_common_reference_t<ranges::iterator_t<In>>);
|
||||
(void) ranges::find(in, type{}, Projection{});
|
||||
};
|
||||
};
|
||||
|
||||
template void test_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::find_if, ranges::iterator_t, std::same_as;
|
||||
using P = std::pair<int, int>;
|
||||
|
||||
std::array<P, 3> const pairs = {{{0, 42}, {2, 42}, {4, 42}}};
|
||||
constexpr auto equals = [](auto x) { return [x](auto&& y) { return y == x; }; };
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(same_as<decltype(find_if(borrowed<false>{}, equals(42))), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(find_if(borrowed<true>{}, equals(42))), int*>);
|
||||
|
||||
for (auto [value, _] : pairs) {
|
||||
{
|
||||
// Validate range overload [found case]
|
||||
auto result = find_if(move_only_range{pairs}, equals(value), get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P const>>>);
|
||||
assert((*result).first == value);
|
||||
}
|
||||
{
|
||||
// Validate iterator + sentinel overload [found case]
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
auto result = find_if(wrapped_pairs.begin(), wrapped_pairs.end(), equals(value), get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P const>>>);
|
||||
assert((*result).first == value);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Validate range overload [not found case]
|
||||
auto result = find_if(move_only_range{pairs}, equals(42), get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P const>>>);
|
||||
assert(result == move_only_range{pairs}.end());
|
||||
}
|
||||
{
|
||||
// Validate iterator + sentinel overload [not found case]
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
auto result = find_if(wrapped_pairs.begin(), wrapped_pairs.end(), equals(42), get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P const>>>);
|
||||
assert(result == wrapped_pairs.end());
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In>
|
||||
static void call(In&& in = {}) {
|
||||
using ranges::iterator_t;
|
||||
using I = iterator_t<In>;
|
||||
|
||||
(void) ranges::find_if(in, UnaryPredicateFor<I>{});
|
||||
(void) ranges::find_if(in, ProjectedUnaryPredicate<>{}, ProjectionFor<I>{});
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::find_if_not, ranges::iterator_t, std::same_as;
|
||||
using P = std::pair<int, int>;
|
||||
|
||||
std::array<P, 3> pairs = {{{0, 13}, {0, 13}, {0, 13}}};
|
||||
constexpr auto equals = [](auto x) { return [x](auto&& y) { return y == x; }; };
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(same_as<decltype(find_if_not(borrowed<false>{}, equals(42))), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(find_if_not(borrowed<true>{}, equals(42))), int*>);
|
||||
|
||||
for (auto& [value, _] : pairs) {
|
||||
value = 42;
|
||||
{
|
||||
// Validate range overload [found case]
|
||||
auto result = find_if_not(move_only_range{pairs}, equals(0), get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P>>>);
|
||||
assert((*result).first == 42);
|
||||
}
|
||||
{
|
||||
// Validate iterator + sentinel overload [found case]
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
auto result = find_if_not(wrapped_pairs.begin(), wrapped_pairs.end(), equals(0), get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P>>>);
|
||||
assert((*result).first == 42);
|
||||
}
|
||||
value = 0;
|
||||
}
|
||||
{
|
||||
// Validate range overload [not found case]
|
||||
auto result = find_if_not(move_only_range{pairs}, equals(0), get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P>>>);
|
||||
assert(result == move_only_range{pairs}.end());
|
||||
}
|
||||
{
|
||||
// Validate iterator + sentinel overload [not found case]
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
auto result = find_if_not(wrapped_pairs.begin(), wrapped_pairs.end(), equals(0), get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), iterator_t<move_only_range<P>>>);
|
||||
assert(result == wrapped_pairs.end());
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In>
|
||||
static void call(In&& in = {}) {
|
||||
using ranges::iterator_t;
|
||||
using I = iterator_t<In>;
|
||||
|
||||
(void) ranges::find_if_not(in, UnaryPredicateFor<I>{});
|
||||
(void) ranges::find_if_not(in, ProjectedUnaryPredicate<>{}, ProjectionFor<I>{});
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::for_each, ranges::for_each_result, ranges::in_fun_result, ranges::iterator_t;
|
||||
using std::identity, std::same_as;
|
||||
using P = std::pair<int, int>;
|
||||
using R = std::array<P, 3>;
|
||||
|
||||
// Validate that for_each_result aliases in_fun_result
|
||||
STATIC_ASSERT(same_as<for_each_result<int, double>, in_fun_result<int, double>>);
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(
|
||||
same_as<decltype(for_each(borrowed<false>{}, identity{})), for_each_result<ranges::dangling, identity>>);
|
||||
STATIC_ASSERT(same_as<decltype(for_each(borrowed<true>{}, identity{})), for_each_result<int*, identity>>);
|
||||
|
||||
R const values = {{{0, 42}, {2, 42}, {4, 42}}};
|
||||
auto incr = [](auto& y) { ++y; };
|
||||
|
||||
{
|
||||
auto pairs = values;
|
||||
auto result = for_each(move_only_range{pairs}, incr, get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), for_each_result<iterator_t<move_only_range<P>>, decltype(incr)>>);
|
||||
assert(result.in == move_only_range{pairs}.end());
|
||||
int some_value = 1729;
|
||||
result.fun(some_value);
|
||||
assert(some_value == 1730);
|
||||
R const expected = {{{1, 42}, {3, 42}, {5, 42}}};
|
||||
assert(ranges::equal(pairs, expected));
|
||||
}
|
||||
{
|
||||
auto pairs = values;
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
auto result = for_each(wrapped_pairs.begin(), wrapped_pairs.end(), incr, get_second);
|
||||
STATIC_ASSERT(same_as<decltype(result), for_each_result<iterator_t<move_only_range<P>>, decltype(incr)>>);
|
||||
assert(result.in == wrapped_pairs.end());
|
||||
int some_value = 1729;
|
||||
result.fun(some_value);
|
||||
assert(some_value == 1730);
|
||||
R const expected = {{{0, 43}, {2, 43}, {4, 43}}};
|
||||
assert(ranges::equal(pairs, expected));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In>
|
||||
static void call(In&& in = {}) {
|
||||
using I = ranges::iterator_t<In>;
|
||||
using Fun = void (*)(std::iter_common_reference_t<I>);
|
||||
ranges::for_each(in, Fun{});
|
||||
ranges::for_each(ranges::begin(in), ranges::end(in), Fun{});
|
||||
|
||||
using ProjFun = void (*)(unique_tag<0>);
|
||||
ranges::for_each(in, ProjFun{}, ProjectionFor<I>{});
|
||||
ranges::for_each(ranges::begin(in), ranges::end(in), ProjFun{}, ProjectionFor<I>{});
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::for_each_n, ranges::for_each_n_result, ranges::in_fun_result, ranges::iterator_t;
|
||||
using std::same_as;
|
||||
using P = std::pair<int, int>;
|
||||
using R = std::array<P, 3>;
|
||||
|
||||
// Validate that for_each_n_result aliases in_fun_result
|
||||
STATIC_ASSERT(same_as<for_each_n_result<int, double>, in_fun_result<int, double>>);
|
||||
|
||||
R pairs = {{{0, 42}, {2, 42}, {4, 42}}};
|
||||
auto incr = [](auto& y) { ++y; };
|
||||
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
auto result = for_each_n(wrapped_pairs.begin(), ranges::distance(pairs), incr, get_first);
|
||||
STATIC_ASSERT(same_as<decltype(result), for_each_n_result<iterator_t<move_only_range<P>>, decltype(incr)>>);
|
||||
assert(result.in == wrapped_pairs.end());
|
||||
int some_value = 1729;
|
||||
result.fun(some_value);
|
||||
assert(some_value == 1730);
|
||||
R const expected = {{{1, 42}, {3, 42}, {5, 42}}};
|
||||
assert(ranges::equal(pairs, expected));
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In, class, class>
|
||||
static void call(In in = {}) {
|
||||
using std::iter_difference_t;
|
||||
|
||||
using Fun = void (*)(std::iter_common_reference_t<In>);
|
||||
ranges::for_each_n(std::move(in), iter_difference_t<In>{}, Fun{});
|
||||
|
||||
using ProjFun = void (*)(unique_tag<0>);
|
||||
ranges::for_each_n(std::move(in), iter_difference_t<In>{}, ProjFun{}, ProjectionFor<In>{});
|
||||
}
|
||||
};
|
||||
|
||||
template void test_counted_out<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::dangling, ranges::equal_to, ranges::iterator_t, ranges::mismatch, ranges::mismatch_result;
|
||||
using std::same_as;
|
||||
using P = std::pair<int, int>;
|
||||
using R = std::array<P, 3>;
|
||||
|
||||
R const x = {{{0, 42}, {2, 42}, {4, 42}}};
|
||||
std::array<std::pair<long, long>, 3> const y = {{{13, 0}, {13, 2}, {13, 5}}};
|
||||
|
||||
// Validate that mismatch_result aliases in_in_result
|
||||
STATIC_ASSERT(same_as<mismatch_result<int, double>, ranges::in_in_result<int, double>>);
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(
|
||||
same_as<decltype(mismatch(borrowed<false>{}, borrowed<false>{})), mismatch_result<dangling, dangling>>);
|
||||
STATIC_ASSERT(same_as<decltype(mismatch(borrowed<false>{}, borrowed<true>{})), mismatch_result<dangling, int*>>);
|
||||
STATIC_ASSERT(same_as<decltype(mismatch(borrowed<true>{}, borrowed<false>{})), mismatch_result<int*, dangling>>);
|
||||
STATIC_ASSERT(same_as<decltype(mismatch(borrowed<true>{}, borrowed<true>{})), mismatch_result<int*, int*>>);
|
||||
|
||||
{
|
||||
// Validate sized ranges
|
||||
auto result = mismatch(x, y, equal_to{}, get_first, get_second);
|
||||
using I1 = iterator_t<R const>;
|
||||
using I2 = std::array<std::pair<long, long>, 3>::const_iterator;
|
||||
STATIC_ASSERT(same_as<decltype(result), mismatch_result<I1, I2>>);
|
||||
assert((*result.in1 == P{4, 42}));
|
||||
assert((*result.in2 == std::pair<long, long>{13, 5}));
|
||||
}
|
||||
{
|
||||
// Validate non-sized ranges
|
||||
auto result = mismatch(move_only_range{x}, move_only_range{y}, equal_to{}, get_first, get_second);
|
||||
using I1 = iterator_t<move_only_range<P const>>;
|
||||
using I2 = iterator_t<move_only_range<std::pair<long, long> const>>;
|
||||
STATIC_ASSERT(same_as<decltype(result), mismatch_result<I1, I2>>);
|
||||
assert((*result.in1 == P{4, 42}));
|
||||
assert((*result.in2 == std::pair<long, long>{13, 5}));
|
||||
}
|
||||
{
|
||||
// Validate sized iterator + sentinel pairs
|
||||
auto result = mismatch(x.begin(), x.end(), y.begin(), y.end(), equal_to{}, get_first, get_second);
|
||||
using I1 = iterator_t<R const>;
|
||||
using I2 = std::array<std::pair<long, long>, 3>::const_iterator;
|
||||
STATIC_ASSERT(same_as<decltype(result), mismatch_result<I1, I2>>);
|
||||
assert((*result.in1 == P{4, 42}));
|
||||
assert((*result.in2 == std::pair<long, long>{13, 5}));
|
||||
}
|
||||
{
|
||||
// Validate non-sized iterator + sentinel pairs
|
||||
move_only_range wrapped_x{x};
|
||||
move_only_range wrapped_y{y};
|
||||
auto result = mismatch(
|
||||
wrapped_x.begin(), wrapped_x.end(), wrapped_y.begin(), wrapped_y.end(), equal_to{}, get_first, get_second);
|
||||
using I1 = iterator_t<decltype(wrapped_x)>;
|
||||
using I2 = iterator_t<decltype(wrapped_y)>;
|
||||
STATIC_ASSERT(same_as<decltype(result), mismatch_result<I1, I2>>);
|
||||
assert((*result.in1 == P{4, 42}));
|
||||
assert((*result.in2 == std::pair<long, long>{13, 5}));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In1, class In2>
|
||||
static void call(In1&& in1 = {}, In2&& in2 = {}) {
|
||||
using ranges::begin, ranges::end, ranges::mismatch, ranges::iterator_t;
|
||||
|
||||
if constexpr (!is_permissive) {
|
||||
(void) mismatch(in1, in2);
|
||||
(void) mismatch(begin(in1), end(in1), begin(in2), end(in2));
|
||||
}
|
||||
|
||||
BinaryPredicateFor<iterator_t<In1>, iterator_t<In2>> pred{};
|
||||
(void) mismatch(in1, in2, pred);
|
||||
(void) mismatch(begin(in1), end(in1), begin(in2), end(in2), pred);
|
||||
|
||||
HalfProjectedBinaryPredicateFor<iterator_t<In2>> halfpred{};
|
||||
ProjectionFor<iterator_t<In1>> halfproj{};
|
||||
(void) mismatch(in1, in2, halfpred, halfproj);
|
||||
(void) mismatch(begin(in1), end(in1), begin(in2), end(in2), halfpred, halfproj);
|
||||
|
||||
ProjectedBinaryPredicate<0, 1> projpred{};
|
||||
ProjectionFor<iterator_t<In1>, 0> proj1{};
|
||||
ProjectionFor<iterator_t<In2>, 1> proj2{};
|
||||
(void) mismatch(in1, in2, projpred, proj1, proj2);
|
||||
(void) mismatch(begin(in1), end(in1), begin(in2), end(in2), projpred, proj1, proj2);
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
//
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
constexpr auto is_even = [](auto const& x) { return x % 2 == 0; };
|
||||
constexpr auto is_odd = [](auto const& x) { return x % 2 != 0; };
|
||||
|
||||
constexpr void smoke_test() {
|
||||
using ranges::none_of;
|
||||
constexpr std::array<std::pair<int, int>, 3> pairs = {{{0, 13}, {7, 13}, {4, 13}}};
|
||||
|
||||
assert(!none_of(move_only_range{pairs}, is_even, get_first));
|
||||
assert(none_of(move_only_range{pairs}, is_even, get_second));
|
||||
assert(!none_of(move_only_range{pairs}, is_odd, get_first));
|
||||
assert(!none_of(move_only_range{pairs}, is_odd, get_second));
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(!none_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_even, get_first));
|
||||
}
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(none_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_even, get_second));
|
||||
}
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(!none_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_odd, get_first));
|
||||
}
|
||||
{
|
||||
move_only_range wrapped_pairs{pairs};
|
||||
assert(!none_of(wrapped_pairs.begin(), wrapped_pairs.end(), is_odd, get_second));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((smoke_test(), true));
|
||||
smoke_test();
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <class In>
|
||||
static void call(In&& in = {}) {
|
||||
(void) ranges::none_of(in, UnaryPredicateFor<ranges::iterator_t<In>>{});
|
||||
(void) ranges::none_of(in, ProjectedUnaryPredicate<>{}, ProjectionFor<ranges::iterator_t<In>>{});
|
||||
}
|
||||
};
|
||||
|
||||
template void test_in<instantiator>();
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,524 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
|
||||
|
||||
namespace ranges = std::ranges;
|
||||
|
||||
int main() {} // COMPILE-ONLY
|
||||
|
||||
namespace detail {
|
||||
static constexpr bool permissive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class>
|
||||
struct DependentBase {
|
||||
static constexpr bool permissive() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Derived : DependentBase<T> {
|
||||
static constexpr bool test() {
|
||||
return permissive();
|
||||
}
|
||||
};
|
||||
}
|
||||
constexpr bool is_permissive = detail::Derived<int>::test();
|
||||
|
||||
template <bool>
|
||||
struct borrowed { // borrowed<true> is a borrowed_range; borrowed<false> is not
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
template <>
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<borrowed<true>> = true;
|
||||
|
||||
struct simple_reference {
|
||||
operator int() const;
|
||||
};
|
||||
|
||||
struct simple_common_reference {
|
||||
simple_common_reference(simple_reference);
|
||||
simple_common_reference(int);
|
||||
};
|
||||
|
||||
template <int I>
|
||||
struct simple_iter_archetype {
|
||||
using value_type = int;
|
||||
|
||||
// 0: not indirectly_readable
|
||||
simple_reference operator*() const requires(I != 0);
|
||||
|
||||
friend void iter_swap(simple_iter_archetype const&, simple_iter_archetype const&) {}
|
||||
};
|
||||
STATIC_ASSERT(!std::indirectly_readable<simple_iter_archetype<0>>);
|
||||
STATIC_ASSERT(std::indirectly_readable<simple_iter_archetype<1>>);
|
||||
|
||||
template <template <class> class TQuals, template <class> class UQuals>
|
||||
struct std::basic_common_reference<int, ::simple_reference, TQuals, UQuals> {
|
||||
using type = ::simple_common_reference;
|
||||
};
|
||||
template <template <class> class TQuals, template <class> class UQuals>
|
||||
struct std::basic_common_reference<::simple_reference, int, TQuals, UQuals> {
|
||||
using type = ::simple_common_reference;
|
||||
};
|
||||
|
||||
namespace indirectly_unary_invocable_test {
|
||||
// Also validate indirect_result_t, and indirectly_regular_unary_invocable which is syntactically equivalent to
|
||||
// indirectly_unary_invocable since regular_invocable and invocable are syntactically equivalent.
|
||||
|
||||
template <int I>
|
||||
struct base {};
|
||||
template <>
|
||||
struct base<0> {
|
||||
// 0: not copy_constructible
|
||||
base() = default;
|
||||
base(base const&) = delete;
|
||||
};
|
||||
|
||||
template <int I>
|
||||
struct Fn : base<I> {
|
||||
// 1: not invocable<Fn&, iter_value_t<simple_iter_archetype>&>
|
||||
void operator()(int&) const requires(I == 1) = delete;
|
||||
// 2: not invocable<Fn&, iter_reference_t<simple_iter_archetype>>
|
||||
void operator()(simple_reference) const requires(I == 2) = delete;
|
||||
// 3: not invocable<Fn&, iter_common_reference_t<simple_iter_archetype>>
|
||||
void operator()(simple_common_reference) const requires(I == 3) = delete;
|
||||
|
||||
// 4 : not common_reference_with<invoke_result_t<Fn&, iter_value_t<simple_iter_archetype>&>,
|
||||
// invoke_result_t<Fn&, iter_reference_t<simple_iter_archetype>>>;
|
||||
void operator()(int&) const requires(I == 4);
|
||||
int operator()(simple_reference) const requires(I == 4);
|
||||
|
||||
int operator()(int&) const requires(I != 1 && I != 4);
|
||||
int operator()(simple_reference) const requires(I != 2 && I != 4);
|
||||
int operator()(simple_common_reference) const requires(I != 3 && I != 4);
|
||||
};
|
||||
|
||||
template <class F, class I>
|
||||
constexpr bool test() {
|
||||
constexpr bool result = std::indirectly_unary_invocable<F, I>;
|
||||
STATIC_ASSERT(result == std::indirectly_regular_unary_invocable<F, I>);
|
||||
return result;
|
||||
}
|
||||
STATIC_ASSERT(!test<Fn<0>, simple_iter_archetype<1>>());
|
||||
STATIC_ASSERT(!test<Fn<1>, simple_iter_archetype<1>>());
|
||||
STATIC_ASSERT(!test<Fn<2>, simple_iter_archetype<1>>());
|
||||
STATIC_ASSERT(!test<Fn<3>, simple_iter_archetype<1>>());
|
||||
STATIC_ASSERT(!test<Fn<4>, simple_iter_archetype<1>>());
|
||||
STATIC_ASSERT(!test<Fn<5>, simple_iter_archetype<0>>());
|
||||
STATIC_ASSERT(test<Fn<5>, simple_iter_archetype<1>>());
|
||||
|
||||
STATIC_ASSERT(std::same_as<std::indirect_result_t<Fn<5>, simple_iter_archetype<1>>, int>);
|
||||
} // namespace indirectly_unary_invocable_test
|
||||
|
||||
namespace indirect_unary_predicate_test {
|
||||
// Also validate indirect_result_t
|
||||
using std::indirect_unary_predicate;
|
||||
|
||||
template <int I>
|
||||
struct base {};
|
||||
template <>
|
||||
struct base<0> {
|
||||
// 0: not copy_constructible
|
||||
base() = default;
|
||||
base(base const&) = delete;
|
||||
};
|
||||
|
||||
template <int I>
|
||||
struct Fn : base<I> {
|
||||
// 1: not predicate<Fn&, iter_value_t<simple_iter_archetype>&>
|
||||
void operator()(int&) const requires(I == 1);
|
||||
// 2: not predicate<Fn&, iter_reference_t<simple_iter_archetype>>
|
||||
void operator()(simple_reference) const requires(I == 2) = delete;
|
||||
// 3: not predicate<Fn&, iter_common_reference_t<simple_iter_archetype>>
|
||||
void operator()(simple_common_reference) const requires(I == 3) = delete;
|
||||
|
||||
int operator()(int&) const requires(I != 1 && I != 4);
|
||||
int operator()(simple_reference) const requires(I != 2 && I != 4);
|
||||
int operator()(simple_common_reference) const requires(I != 3 && I != 4);
|
||||
};
|
||||
|
||||
STATIC_ASSERT(!indirect_unary_predicate<Fn<0>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_unary_predicate<Fn<1>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_unary_predicate<Fn<2>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_unary_predicate<Fn<3>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_unary_predicate<Fn<4>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_unary_predicate<Fn<5>, simple_iter_archetype<0>>);
|
||||
STATIC_ASSERT(indirect_unary_predicate<Fn<5>, simple_iter_archetype<1>>);
|
||||
|
||||
STATIC_ASSERT(std::same_as<std::indirect_result_t<Fn<5>, simple_iter_archetype<1>>, int>);
|
||||
} // namespace indirect_unary_predicate_test
|
||||
|
||||
namespace indirect_binary_predicate_test {
|
||||
// Also validate indirect_result_t
|
||||
using std::indirect_binary_predicate;
|
||||
|
||||
template <int>
|
||||
struct base {};
|
||||
template <>
|
||||
struct base<0> {
|
||||
// 0: not copy_constructible
|
||||
base() = default;
|
||||
base(base const&) = delete;
|
||||
};
|
||||
|
||||
template <int I>
|
||||
struct Fn : base<I> {
|
||||
// 1: not predicate<Fn&, iter_value_t<simple_iter_archetype>&, iter_value_t<simple_iter_archetype>&>
|
||||
void operator()(int&, int&) const requires(I == 1);
|
||||
// 2: not predicate<Fn&, iter_value_t<simple_iter_archetype>&, iter_reference_t<simple_iter_archetype>>
|
||||
void operator()(int&, simple_reference) const requires(I == 2);
|
||||
// 3: not predicate<Fn&, iter_reference_t<simple_iter_archetype>, iter_value_t<simple_iter_archetype>&>
|
||||
void operator()(simple_reference, int&) const requires(I == 3);
|
||||
// 4: not predicate<Fn&, iter_reference_t<simple_iter_archetype>, iter_reference_t<simple_iter_archetype>>
|
||||
void operator()(simple_reference, simple_reference) const requires(I == 4);
|
||||
// 5: not predicate<Fn&, iter_common_reference_t</**/>, iter_common_reference_t</**/>>
|
||||
void operator()(simple_common_reference, simple_common_reference) const requires(I == 5);
|
||||
|
||||
bool operator()(int&, int&) const requires(I != 1);
|
||||
int operator()(int&, simple_reference) const requires(I != 2);
|
||||
int* operator()(simple_reference, int&) const requires(I != 3);
|
||||
std::true_type operator()(simple_reference, simple_reference) const requires(I != 4);
|
||||
std::false_type operator()(simple_common_reference, simple_common_reference) const requires(I != 5);
|
||||
};
|
||||
|
||||
STATIC_ASSERT(!indirect_binary_predicate<Fn<0>, simple_iter_archetype<1>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_binary_predicate<Fn<1>, simple_iter_archetype<1>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_binary_predicate<Fn<2>, simple_iter_archetype<1>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_binary_predicate<Fn<3>, simple_iter_archetype<1>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_binary_predicate<Fn<4>, simple_iter_archetype<1>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_binary_predicate<Fn<5>, simple_iter_archetype<1>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_binary_predicate<Fn<6>, simple_iter_archetype<0>, simple_iter_archetype<1>>);
|
||||
STATIC_ASSERT(!indirect_binary_predicate<Fn<6>, simple_iter_archetype<1>, simple_iter_archetype<0>>);
|
||||
STATIC_ASSERT(indirect_binary_predicate<Fn<6>, simple_iter_archetype<1>, simple_iter_archetype<1>>);
|
||||
|
||||
STATIC_ASSERT(std::same_as<std::indirect_result_t<Fn<6>, simple_iter_archetype<1>, simple_iter_archetype<1>>,
|
||||
std::true_type>);
|
||||
} // namespace indirect_binary_predicate_test
|
||||
|
||||
namespace projected_test {
|
||||
template <class Iter, class Proj, class Value, class Reference>
|
||||
constexpr bool test() {
|
||||
STATIC_ASSERT(std::indirectly_readable<Iter>);
|
||||
|
||||
using P = std::projected<Iter, Proj>;
|
||||
STATIC_ASSERT(std::indirectly_readable<P>);
|
||||
STATIC_ASSERT(std::same_as<std::iter_value_t<P>, Value>);
|
||||
STATIC_ASSERT(std::same_as<std::iter_reference_t<P>, Reference>);
|
||||
return true;
|
||||
}
|
||||
STATIC_ASSERT(test<int*, std::identity, int, int&>());
|
||||
STATIC_ASSERT(test<int const*, std::identity, int, int const&>());
|
||||
|
||||
struct S {};
|
||||
STATIC_ASSERT(test<S*, int(S::*), int, int&>());
|
||||
STATIC_ASSERT(test<S const*, int(S::*), int, int const&>());
|
||||
|
||||
struct iter {
|
||||
using value_type = int;
|
||||
struct reference {
|
||||
operator value_type() const;
|
||||
};
|
||||
reference operator*() const;
|
||||
};
|
||||
STATIC_ASSERT(test<iter, std::identity, iter::reference, iter::reference&&>());
|
||||
STATIC_ASSERT(test<iter, double (*)(int), double, double>());
|
||||
} // namespace projected_test
|
||||
|
||||
namespace indirectly_copyable_test {
|
||||
using std::indirectly_copyable;
|
||||
|
||||
template <int I>
|
||||
struct out_archetype {
|
||||
out_archetype& operator*() const;
|
||||
// 0: not indirectly_writable<simple_reference>
|
||||
void operator=(int) const requires(I != 0);
|
||||
};
|
||||
|
||||
STATIC_ASSERT(!indirectly_copyable<simple_iter_archetype<0>, out_archetype<1>>);
|
||||
STATIC_ASSERT(!indirectly_copyable<simple_iter_archetype<1>, out_archetype<0>>);
|
||||
STATIC_ASSERT(indirectly_copyable<simple_iter_archetype<1>, out_archetype<1>>);
|
||||
} // namespace indirectly_copyable_test
|
||||
|
||||
namespace indirectly_swappable_test {
|
||||
using std::indirectly_readable, std::indirectly_swappable;
|
||||
|
||||
template <int I>
|
||||
struct archetype {
|
||||
using value_type = int;
|
||||
|
||||
struct reference {
|
||||
operator int() const;
|
||||
};
|
||||
|
||||
reference operator*() const noexcept requires(I != 0);
|
||||
|
||||
friend constexpr void iter_swap(archetype const&, archetype const&) requires(I != 1) {}
|
||||
|
||||
// clang-format off
|
||||
template <int J>
|
||||
requires(I != J && I != 2 && J != 2)
|
||||
friend constexpr void iter_swap(archetype const&, archetype<J> const&) {}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// We have to be careful to avoid checking some !indirectly_swappable cases that fail when the Evil Extension is
|
||||
// active (i.e., in permissive mode).
|
||||
template <bool IsPermissive>
|
||||
constexpr bool compile_only() {
|
||||
STATIC_ASSERT(!indirectly_readable<archetype<0>>); // <0> is not indirectly_readable
|
||||
STATIC_ASSERT(indirectly_readable<archetype<1>>); // <1+> is indirectly_readable
|
||||
STATIC_ASSERT(indirectly_readable<archetype<2>>);
|
||||
STATIC_ASSERT(indirectly_readable<archetype<3>>);
|
||||
STATIC_ASSERT(indirectly_readable<archetype<4>>);
|
||||
|
||||
STATIC_ASSERT(!indirectly_swappable<archetype<0>, archetype<0>>); // <0> is (still) not indirectly_readable
|
||||
if constexpr (!IsPermissive) {
|
||||
STATIC_ASSERT(!indirectly_swappable<archetype<1>, archetype<1>>); // <1> is not self-indirectly_swappable
|
||||
}
|
||||
STATIC_ASSERT(indirectly_swappable<archetype<2>, archetype<2>>); // <2+> is self-indirectly_swappable
|
||||
STATIC_ASSERT(indirectly_swappable<archetype<3>, archetype<3>>);
|
||||
STATIC_ASSERT(indirectly_swappable<archetype<4>, archetype<4>>);
|
||||
|
||||
STATIC_ASSERT(!indirectly_swappable<archetype<0>, archetype<4>>); // <0> is not indirectly_readable
|
||||
STATIC_ASSERT(!indirectly_swappable<archetype<4>, archetype<0>>); // <0> is not indirectly_readable
|
||||
if constexpr (!IsPermissive) {
|
||||
STATIC_ASSERT(!indirectly_swappable<archetype<1>, archetype<4>>); // <1> is not self-indirectly_swappable
|
||||
STATIC_ASSERT(!indirectly_swappable<archetype<4>, archetype<1>>); // <1> is not self-indirectly_swappable
|
||||
}
|
||||
STATIC_ASSERT(!indirectly_swappable<archetype<2>, archetype<4>>); // <2> & <4> aren't cross-indirectly_swappable
|
||||
STATIC_ASSERT(!indirectly_swappable<archetype<4>, archetype<2>>); // <2> & <4> aren't cross-indirectly_swappable
|
||||
|
||||
STATIC_ASSERT(indirectly_swappable<archetype<3>, archetype<4>>);
|
||||
STATIC_ASSERT(indirectly_swappable<archetype<4>, archetype<3>>);
|
||||
|
||||
return true;
|
||||
}
|
||||
STATIC_ASSERT(compile_only<is_permissive>());
|
||||
} // namespace indirectly_swappable_test
|
||||
|
||||
namespace indirectly_comparable_test {
|
||||
// Also validate indirect_result_t
|
||||
using std::indirectly_comparable;
|
||||
|
||||
using Proj = int (&)(simple_common_reference);
|
||||
using BadProj = char const* (&) (simple_common_reference);
|
||||
|
||||
template <int>
|
||||
struct base {};
|
||||
template <>
|
||||
struct base<0> {
|
||||
// 0: not copy_constructible
|
||||
base() = default;
|
||||
base(base const&) = delete;
|
||||
};
|
||||
|
||||
template <int I>
|
||||
struct Fn : base<I> {
|
||||
// 1: not predicate
|
||||
void operator()(int, int) const requires(I == 1);
|
||||
void* operator()(int, int) const requires(I != 1);
|
||||
};
|
||||
|
||||
STATIC_ASSERT(!indirectly_comparable<simple_iter_archetype<1>, simple_iter_archetype<1>, Fn<0>, Proj, Proj>);
|
||||
STATIC_ASSERT(!indirectly_comparable<simple_iter_archetype<1>, simple_iter_archetype<1>, Fn<1>, Proj, Proj>);
|
||||
STATIC_ASSERT(!indirectly_comparable<simple_iter_archetype<0>, simple_iter_archetype<1>, Fn<2>, Proj, Proj>);
|
||||
STATIC_ASSERT(!indirectly_comparable<simple_iter_archetype<1>, simple_iter_archetype<0>, Fn<2>, Proj, Proj>);
|
||||
STATIC_ASSERT(!indirectly_comparable<simple_iter_archetype<1>, simple_iter_archetype<1>, Fn<2>, BadProj, Proj>);
|
||||
STATIC_ASSERT(!indirectly_comparable<simple_iter_archetype<1>, simple_iter_archetype<1>, Fn<2>, Proj, BadProj>);
|
||||
STATIC_ASSERT(indirectly_comparable<simple_iter_archetype<1>, simple_iter_archetype<1>, Fn<2>, Proj, Proj>);
|
||||
|
||||
using Projected = std::projected<simple_iter_archetype<1>, Proj>;
|
||||
STATIC_ASSERT(std::same_as<std::indirect_result_t<Fn<2>, Projected, Projected>, void*>);
|
||||
} // namespace indirectly_comparable_test
|
||||
|
||||
namespace dangling_test {
|
||||
// Also test borrowed_iterator_t and borrowed_subrange_t
|
||||
using ranges::dangling, ranges::borrowed_iterator_t;
|
||||
using std::is_nothrow_constructible_v, std::same_as;
|
||||
|
||||
STATIC_ASSERT(std::is_class_v<dangling>);
|
||||
STATIC_ASSERT(std::semiregular<dangling>);
|
||||
STATIC_ASSERT(std::is_trivial_v<dangling>); // not guaranteed, but likely portable nonetheless
|
||||
|
||||
// dangling is constructible from any sequence of arguments without throwing
|
||||
STATIC_ASSERT(is_nothrow_constructible_v<dangling>);
|
||||
STATIC_ASSERT(is_nothrow_constructible_v<dangling, int>);
|
||||
STATIC_ASSERT(is_nothrow_constructible_v<dangling, int*>);
|
||||
STATIC_ASSERT(is_nothrow_constructible_v<dangling, int[42]>);
|
||||
STATIC_ASSERT(is_nothrow_constructible_v<dangling, int (*)()>);
|
||||
STATIC_ASSERT(is_nothrow_constructible_v<dangling, const int (*)[42]>);
|
||||
STATIC_ASSERT(is_nothrow_constructible_v<dangling, int, int*, int[42], int (*)(), const int (*)[42]>);
|
||||
|
||||
STATIC_ASSERT(same_as<borrowed_iterator_t<borrowed<false>>, dangling>);
|
||||
STATIC_ASSERT(same_as<borrowed_iterator_t<borrowed<true>>, int*>);
|
||||
|
||||
#if 0 // TRANSITION, subrange
|
||||
STATIC_ASSERT(same_as<borrowed_subrange_t<borrowed<false>>, dangling>);
|
||||
STATIC_ASSERT(same_as<borrowed_subrange_t<borrowed<true>>, ranges::subrange<int*>>);
|
||||
#endif // TRANSITION, subrange
|
||||
} // namespace dangling_test
|
||||
|
||||
namespace result_test {
|
||||
using ranges::in_found_result, ranges::in_fun_result, ranges::in_in_result, ranges::in_out_result,
|
||||
ranges::in_in_out_result, ranges::in_out_out_result, ranges::min_max_result;
|
||||
using std::is_aggregate_v, std::is_convertible_v, std::is_trivial_v;
|
||||
|
||||
// Validate the result types are:
|
||||
// * aggregates
|
||||
STATIC_ASSERT(is_aggregate_v<in_found_result<int>>);
|
||||
STATIC_ASSERT(is_aggregate_v<in_fun_result<int, int>>);
|
||||
STATIC_ASSERT(is_aggregate_v<in_in_result<int, int>>);
|
||||
STATIC_ASSERT(is_aggregate_v<in_out_result<int, int>>);
|
||||
STATIC_ASSERT(is_aggregate_v<in_in_out_result<int, int, int>>);
|
||||
STATIC_ASSERT(is_aggregate_v<in_out_out_result<int, int, int>>);
|
||||
STATIC_ASSERT(is_aggregate_v<min_max_result<int>>);
|
||||
|
||||
// * trivial when parameter types are trivial
|
||||
STATIC_ASSERT(is_trivial_v<in_found_result<int>>);
|
||||
STATIC_ASSERT(is_trivial_v<in_fun_result<int, int>>);
|
||||
STATIC_ASSERT(is_trivial_v<in_in_result<int, int>>);
|
||||
STATIC_ASSERT(is_trivial_v<in_out_result<int, int>>);
|
||||
STATIC_ASSERT(is_trivial_v<in_in_out_result<int, int, int>>);
|
||||
STATIC_ASSERT(is_trivial_v<in_out_out_result<int, int, int>>);
|
||||
STATIC_ASSERT(is_trivial_v<min_max_result<int>>);
|
||||
|
||||
// * usable with structured bindings
|
||||
constexpr bool test_bindings_in_found_result() {
|
||||
auto [x, y] = in_found_result<int>{42, true};
|
||||
assert(x == 42);
|
||||
assert(y == true);
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool test_bindings_2() {
|
||||
auto [x, y] = T{13, 42};
|
||||
assert(x == 13);
|
||||
assert(y == 42);
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool test_bindings_3() {
|
||||
auto [x, y, z] = T{2, 3, 5};
|
||||
assert(x == 2);
|
||||
assert(y == 3);
|
||||
assert(z == 5);
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC_ASSERT(test_bindings_in_found_result());
|
||||
STATIC_ASSERT(test_bindings_2<in_fun_result<int, int>>());
|
||||
STATIC_ASSERT(test_bindings_2<in_in_result<int, int>>());
|
||||
STATIC_ASSERT(test_bindings_2<in_out_result<int, int>>());
|
||||
STATIC_ASSERT(test_bindings_3<in_in_out_result<int, int, int>>());
|
||||
STATIC_ASSERT(test_bindings_3<in_out_out_result<int, int, int>>());
|
||||
STATIC_ASSERT(test_bindings_2<min_max_result<int>>());
|
||||
|
||||
// * appropriately lvalue and rvalue inter-specialization convertible
|
||||
template <class T>
|
||||
struct convertible_from {
|
||||
convertible_from(std::add_rvalue_reference_t<T>);
|
||||
};
|
||||
|
||||
using CFI = convertible_from<int>;
|
||||
|
||||
constexpr bool test_convertible_in_found_result() {
|
||||
STATIC_ASSERT(!is_convertible_v<in_found_result<int> const&, in_found_result<CFI>>);
|
||||
STATIC_ASSERT(is_convertible_v<in_found_result<int>, in_found_result<CFI>>);
|
||||
in_found_result<int> a{42, true};
|
||||
{
|
||||
in_found_result<long> b = std::as_const(a);
|
||||
auto [x, y] = b;
|
||||
assert(x == 42);
|
||||
assert(y);
|
||||
}
|
||||
{
|
||||
in_found_result<long> b = std::move(a);
|
||||
auto [x, y] = b;
|
||||
assert(x == 42);
|
||||
assert(y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
STATIC_ASSERT(test_convertible_in_found_result());
|
||||
constexpr bool test_convertible_min_max_result() {
|
||||
STATIC_ASSERT(!is_convertible_v<min_max_result<int> const&, min_max_result<CFI>>);
|
||||
STATIC_ASSERT(is_convertible_v<min_max_result<int>, min_max_result<CFI>>);
|
||||
min_max_result<int> a{13, 42};
|
||||
{
|
||||
min_max_result<long> b = std::as_const(a);
|
||||
auto [x, y] = b;
|
||||
assert(x == 13);
|
||||
assert(y == 42);
|
||||
}
|
||||
{
|
||||
min_max_result<long> b = std::move(a);
|
||||
auto [x, y] = b;
|
||||
assert(x == 13);
|
||||
assert(y == 42);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
STATIC_ASSERT(test_convertible_min_max_result());
|
||||
|
||||
template <template <class, class> class R>
|
||||
constexpr bool test_convertible_2() {
|
||||
STATIC_ASSERT(!is_convertible_v<R<int, int> const&, R<CFI, CFI>>);
|
||||
STATIC_ASSERT(is_convertible_v<R<int, int>, R<CFI, CFI>>);
|
||||
R<int, int> a{13, 42};
|
||||
{
|
||||
R<long, long> b = std::as_const(a);
|
||||
auto [x, y] = b;
|
||||
assert(x == 13);
|
||||
assert(y == 42);
|
||||
}
|
||||
{
|
||||
R<long, long> b = std::move(a);
|
||||
auto [x, y] = b;
|
||||
assert(x == 13);
|
||||
assert(y == 42);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
STATIC_ASSERT(test_convertible_2<in_fun_result>());
|
||||
STATIC_ASSERT(test_convertible_2<in_in_result>());
|
||||
STATIC_ASSERT(test_convertible_2<in_out_result>());
|
||||
|
||||
template <template <class, class, class> class R>
|
||||
constexpr bool test_convertible_3() {
|
||||
STATIC_ASSERT(!is_convertible_v<R<int, int, int> const&, R<CFI, CFI, CFI>>);
|
||||
STATIC_ASSERT(is_convertible_v<R<int, int, int>, R<CFI, CFI, CFI>>);
|
||||
R<int, int, int> a{13, 42, 1729};
|
||||
{
|
||||
R<long, long, long> b = std::as_const(a);
|
||||
auto [x, y, z] = b;
|
||||
assert(x == 13);
|
||||
assert(y == 42);
|
||||
assert(z == 1729);
|
||||
}
|
||||
{
|
||||
R<long, long, long> b = std::move(a);
|
||||
auto [x, y, z] = b;
|
||||
assert(x == 13);
|
||||
assert(y == 42);
|
||||
assert(z == 1729);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
STATIC_ASSERT(test_convertible_3<in_in_out_result>());
|
||||
STATIC_ASSERT(test_convertible_3<in_out_out_result>());
|
||||
} // namespace result_test
|
|
@ -240,7 +240,7 @@ struct output_iterator_archetype : iterator_archetype<I>,
|
|||
void operator*() requires(I == 12);
|
||||
output_iterator_archetype& operator*() requires(I != 12);
|
||||
|
||||
// writable requirements
|
||||
// indirectly_writable requirements
|
||||
void operator=(int) requires(I != 13);
|
||||
};
|
||||
|
||||
|
@ -275,8 +275,8 @@ struct input_iterator_archetype : iterator_archetype<I>,
|
|||
using increment_ops<I, input_iterator_archetype<I>, void>::operator++;
|
||||
|
||||
// dereference ops from iterator_archetype
|
||||
void operator*() requires(I == 12);
|
||||
int& operator*() requires(I != 12);
|
||||
void operator*() const requires(I == 12);
|
||||
int& operator*() const requires(I != 12);
|
||||
};
|
||||
|
||||
inline constexpr std::size_t input_iterator_archetype_max = 17;
|
||||
|
@ -500,22 +500,22 @@ namespace incrementable_traits_test {
|
|||
STATIC_ASSERT(!test_difference<non_integral_difference>());
|
||||
} // namespace incrementable_traits_test
|
||||
|
||||
namespace readable_traits_test {
|
||||
namespace indirectly_readable_traits_test {
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4180) // qualifier applied to function type has no meaning; ignored
|
||||
template <class T, class V = no_such_type>
|
||||
constexpr bool test_value() noexcept {
|
||||
using std::readable_traits, std::iter_value_t, std::same_as;
|
||||
using std::indirectly_readable_traits, std::iter_value_t, std::same_as;
|
||||
|
||||
if constexpr (same_as<V, no_such_type>) {
|
||||
STATIC_ASSERT(!has_member_value_type<readable_traits<T>>);
|
||||
STATIC_ASSERT(!has_member_value_type<readable_traits<T const>>);
|
||||
STATIC_ASSERT(!has_iter_value<readable_traits<T>>);
|
||||
STATIC_ASSERT(!has_iter_value<readable_traits<T const>>);
|
||||
STATIC_ASSERT(!has_member_value_type<indirectly_readable_traits<T>>);
|
||||
STATIC_ASSERT(!has_member_value_type<indirectly_readable_traits<T const>>);
|
||||
STATIC_ASSERT(!has_iter_value<indirectly_readable_traits<T>>);
|
||||
STATIC_ASSERT(!has_iter_value<indirectly_readable_traits<T const>>);
|
||||
return false;
|
||||
} else {
|
||||
STATIC_ASSERT(same_as<typename readable_traits<T>::value_type, V>);
|
||||
STATIC_ASSERT(same_as<typename readable_traits<T const>::value_type, V>);
|
||||
STATIC_ASSERT(same_as<typename indirectly_readable_traits<T>::value_type, V>);
|
||||
STATIC_ASSERT(same_as<typename indirectly_readable_traits<T const>::value_type, V>);
|
||||
STATIC_ASSERT(same_as<iter_value_t<T>, V>);
|
||||
STATIC_ASSERT(same_as<iter_value_t<T const>, V>);
|
||||
return true;
|
||||
|
@ -552,10 +552,10 @@ namespace readable_traits_test {
|
|||
STATIC_ASSERT(test_value<with_element_type<int const>, int>());
|
||||
|
||||
STATIC_ASSERT(test_value<my_iterator, char>());
|
||||
} // namespace readable_traits_test
|
||||
} // namespace indirectly_readable_traits_test
|
||||
|
||||
namespace iterator_traits_test {
|
||||
using std::incrementable_traits, std::readable_traits, std::iterator_traits, std::iter_value_t,
|
||||
using std::incrementable_traits, std::indirectly_readable_traits, std::iterator_traits, std::iter_value_t,
|
||||
std::iter_difference_t, std::same_as, std::output_iterator_tag, std::input_iterator_tag,
|
||||
std::forward_iterator_tag, std::bidirectional_iterator_tag, std::random_access_iterator_tag,
|
||||
std::contiguous_iterator_tag;
|
||||
|
@ -652,7 +652,7 @@ namespace iterator_traits_test {
|
|||
STATIC_ASSERT(same_as<typename iterator_traits<T>::value_type, Value>);
|
||||
if constexpr (!same_as<Value, void>) {
|
||||
STATIC_ASSERT(same_as<iter_value_t<T>, Value>);
|
||||
STATIC_ASSERT(same_as<typename readable_traits<T>::value_type, Value>);
|
||||
STATIC_ASSERT(same_as<typename indirectly_readable_traits<T>::value_type, Value>);
|
||||
}
|
||||
STATIC_ASSERT(same_as<typename iterator_traits<T>::difference_type, Difference>);
|
||||
if constexpr (!same_as<Difference, void>) {
|
||||
|
@ -804,7 +804,7 @@ namespace iterator_traits_test {
|
|||
} // namespace iterator_traits_test
|
||||
|
||||
template <class Base>
|
||||
struct std::readable_traits<iterator_traits_test::simple_contiguous_iter<Base>> {
|
||||
struct std::indirectly_readable_traits<iterator_traits_test::simple_contiguous_iter<Base>> {
|
||||
using value_type = double;
|
||||
};
|
||||
|
||||
|
@ -983,8 +983,8 @@ namespace iterator_cust_move_test {
|
|||
} // namespace iterator_cust_move_test
|
||||
|
||||
namespace iterator_cust_swap_test {
|
||||
using std::indirectly_movable_storable, std::iter_reference_t, std::readable, std::remove_reference_t, std::same_as,
|
||||
std::swappable_with;
|
||||
using std::indirectly_movable_storable, std::iter_reference_t, std::indirectly_readable, std::remove_reference_t,
|
||||
std::same_as, std::swappable_with;
|
||||
|
||||
template <class T, class U>
|
||||
concept can_iter_swap = requires(T&& t, U&& u) {
|
||||
|
@ -1027,12 +1027,12 @@ namespace iterator_cust_swap_test {
|
|||
STATIC_ASSERT(bullet1<E1>);
|
||||
STATIC_ASSERT((ranges::iter_swap(E1::x, E1::x), true));
|
||||
|
||||
// N4820 [iterator.cust.swap]/4.2: "Otherwise if the types of E1 and E2 each model readable, and if the reference
|
||||
// types of E1 and E2 model swappable_with, then ranges::swap(*E1, *E2)."
|
||||
// N4849 [iterator.cust.swap]/4.2: "Otherwise if the types of E1 and E2 each model indirectly_readable, and if the
|
||||
// reference types of E1 and E2 model swappable_with, then ranges::swap(*E1, *E2)."
|
||||
// clang-format off
|
||||
template <class T, class U = T>
|
||||
concept bullet2 = !bullet1<T, U> && readable<remove_reference_t<T>> && readable<remove_reference_t<U>>
|
||||
&& swappable_with<iter_reference_t<T>, iter_reference_t<U>>;
|
||||
concept bullet2 = !bullet1<T, U> && indirectly_readable<remove_reference_t<T>>
|
||||
&& indirectly_readable<remove_reference_t<U>> && swappable_with<iter_reference_t<T>, iter_reference_t<U>>;
|
||||
// clang-format on
|
||||
|
||||
constexpr bool test() {
|
||||
|
@ -1153,64 +1153,64 @@ namespace iterator_cust_swap_test {
|
|||
} // namespace iterator_cust_swap_test
|
||||
|
||||
namespace iterator_concept_readable_test {
|
||||
using std::readable;
|
||||
using std::indirectly_readable;
|
||||
|
||||
STATIC_ASSERT(!readable<void>);
|
||||
STATIC_ASSERT(!readable<void*>);
|
||||
STATIC_ASSERT(readable<int*>);
|
||||
STATIC_ASSERT(readable<int const*>);
|
||||
STATIC_ASSERT(!readable<int const empty_type::*>);
|
||||
STATIC_ASSERT(!indirectly_readable<void>);
|
||||
STATIC_ASSERT(!indirectly_readable<void*>);
|
||||
STATIC_ASSERT(indirectly_readable<int*>);
|
||||
STATIC_ASSERT(indirectly_readable<int const*>);
|
||||
STATIC_ASSERT(!indirectly_readable<int const empty_type::*>);
|
||||
|
||||
STATIC_ASSERT(!readable<dereferences_to<void>>);
|
||||
STATIC_ASSERT(readable<dereferences_to<int>>);
|
||||
STATIC_ASSERT(readable<dereferences_to<int&>>);
|
||||
STATIC_ASSERT(readable<dereferences_to<int const&>>);
|
||||
STATIC_ASSERT(readable<dereferences_to<move_only>>);
|
||||
STATIC_ASSERT(readable<dereferences_to<int (&)[42]>>);
|
||||
STATIC_ASSERT(!readable<dereferences_to<int (&)()>>);
|
||||
STATIC_ASSERT(!readable<int (empty_type::*)()>);
|
||||
STATIC_ASSERT(!indirectly_readable<dereferences_to<void>>);
|
||||
STATIC_ASSERT(indirectly_readable<dereferences_to<int>>);
|
||||
STATIC_ASSERT(indirectly_readable<dereferences_to<int&>>);
|
||||
STATIC_ASSERT(indirectly_readable<dereferences_to<int const&>>);
|
||||
STATIC_ASSERT(indirectly_readable<dereferences_to<move_only>>);
|
||||
STATIC_ASSERT(indirectly_readable<dereferences_to<int (&)[42]>>);
|
||||
STATIC_ASSERT(!indirectly_readable<dereferences_to<int (&)()>>);
|
||||
STATIC_ASSERT(!indirectly_readable<int (empty_type::*)()>);
|
||||
|
||||
struct no_value_type {
|
||||
int operator*() const;
|
||||
};
|
||||
STATIC_ASSERT(!readable<no_value_type>);
|
||||
STATIC_ASSERT(!indirectly_readable<no_value_type>);
|
||||
|
||||
struct not_dereferenceable {
|
||||
using value_type = int;
|
||||
};
|
||||
STATIC_ASSERT(!readable<no_value_type>);
|
||||
STATIC_ASSERT(!indirectly_readable<no_value_type>);
|
||||
|
||||
struct simple_abstract {
|
||||
virtual void f() = 0;
|
||||
};
|
||||
STATIC_ASSERT(readable<dereferences_to<simple_abstract&>>);
|
||||
STATIC_ASSERT(indirectly_readable<dereferences_to<simple_abstract&>>);
|
||||
} // namespace iterator_concept_readable_test
|
||||
|
||||
namespace iterator_concept_writable_test {
|
||||
using std::writable;
|
||||
using std::indirectly_writable;
|
||||
|
||||
template <class I, class T>
|
||||
constexpr bool test_writable() {
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4180) // qualifier applied to function type has no meaning; ignored
|
||||
constexpr bool result = writable<I, T>;
|
||||
STATIC_ASSERT(writable<I, T const> == result);
|
||||
STATIC_ASSERT(writable<I, T volatile> == result);
|
||||
STATIC_ASSERT(writable<I, T const volatile> == result);
|
||||
constexpr bool result = indirectly_writable<I, T>;
|
||||
STATIC_ASSERT(indirectly_writable<I, T const> == result);
|
||||
STATIC_ASSERT(indirectly_writable<I, T volatile> == result);
|
||||
STATIC_ASSERT(indirectly_writable<I, T const volatile> == result);
|
||||
|
||||
if constexpr (can_reference<T>) {
|
||||
STATIC_ASSERT(writable<I, T&> == result);
|
||||
STATIC_ASSERT(writable<I, T const&> == result);
|
||||
STATIC_ASSERT(writable<I, T volatile&> == result);
|
||||
STATIC_ASSERT(writable<I, T const volatile&> == result);
|
||||
STATIC_ASSERT(indirectly_writable<I, T&> == result);
|
||||
STATIC_ASSERT(indirectly_writable<I, T const&> == result);
|
||||
STATIC_ASSERT(indirectly_writable<I, T volatile&> == result);
|
||||
STATIC_ASSERT(indirectly_writable<I, T const volatile&> == result);
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
STATIC_ASSERT(!writable<void, int>);
|
||||
STATIC_ASSERT(!writable<void*, void>);
|
||||
STATIC_ASSERT(!indirectly_writable<void, int>);
|
||||
STATIC_ASSERT(!indirectly_writable<void*, void>);
|
||||
STATIC_ASSERT(!test_writable<int*, void>());
|
||||
|
||||
STATIC_ASSERT(test_writable<int*, int>());
|
||||
|
@ -1240,10 +1240,10 @@ namespace iterator_concept_writable_test {
|
|||
STATIC_ASSERT(!test_writable<int (*)(), int (*)()>());
|
||||
STATIC_ASSERT(test_writable<int (**)(), int (*)()>());
|
||||
|
||||
STATIC_ASSERT(writable<move_only*, move_only>);
|
||||
STATIC_ASSERT(indirectly_writable<move_only*, move_only>);
|
||||
STATIC_ASSERT(!test_writable<move_only*, move_only&>());
|
||||
|
||||
// Verify the "writable through a constified reference" requirements
|
||||
// Verify the "indirectly_writable through a constified reference" requirements
|
||||
struct std_string {}; // slightly simplified
|
||||
STATIC_ASSERT(!test_writable<dereferences_to<std_string>, std_string>());
|
||||
|
||||
|
|
|
@ -549,7 +549,7 @@ STATIC_ASSERT(test_rend<int[]>());
|
|||
STATIC_ASSERT(test_crbegin<int[]>());
|
||||
STATIC_ASSERT(test_crend<int[]>());
|
||||
STATIC_ASSERT(test_size<int[]>());
|
||||
STATIC_ASSERT(test_empty<int[], true>());
|
||||
STATIC_ASSERT(test_empty<int[], false>());
|
||||
STATIC_ASSERT(test_data<int[]>());
|
||||
STATIC_ASSERT(test_cdata<int[]>());
|
||||
STATIC_ASSERT(!ranges::range<int[]>);
|
||||
|
@ -564,7 +564,7 @@ STATIC_ASSERT(test_rend<int const[]>());
|
|||
STATIC_ASSERT(test_crbegin<int const[]>());
|
||||
STATIC_ASSERT(test_crend<int const[]>());
|
||||
STATIC_ASSERT(test_size<int const[]>());
|
||||
STATIC_ASSERT(test_empty<int const[], true>());
|
||||
STATIC_ASSERT(test_empty<int const[], false>());
|
||||
STATIC_ASSERT(test_data<int const[]>());
|
||||
STATIC_ASSERT(test_cdata<int const[]>());
|
||||
STATIC_ASSERT(!ranges::range<int const[]>);
|
||||
|
@ -579,7 +579,7 @@ STATIC_ASSERT(test_rend<int (&)[]>());
|
|||
STATIC_ASSERT(test_crbegin<int (&)[]>());
|
||||
STATIC_ASSERT(test_crend<int (&)[]>());
|
||||
STATIC_ASSERT(test_size<int (&)[]>());
|
||||
STATIC_ASSERT(test_empty<int (&)[], true>());
|
||||
STATIC_ASSERT(test_empty<int (&)[], false>());
|
||||
// Can't use test_data/_cdata here because they use range_value_t and this isn't a range
|
||||
STATIC_ASSERT(std::same_as<decltype(ranges::data(std::declval<int (&)[]>())), int*>);
|
||||
STATIC_ASSERT(std::same_as<decltype(ranges::cdata(std::declval<int (&)[]>())), int const*>);
|
||||
|
@ -595,7 +595,7 @@ STATIC_ASSERT(test_rend<int const (&)[]>());
|
|||
STATIC_ASSERT(test_crbegin<int const (&)[]>());
|
||||
STATIC_ASSERT(test_crend<int const (&)[]>());
|
||||
STATIC_ASSERT(test_size<int const (&)[]>());
|
||||
STATIC_ASSERT(test_empty<int const (&)[], true>());
|
||||
STATIC_ASSERT(test_empty<int const (&)[], false>());
|
||||
// Can't use test_data/_cdata here because they use range_value_t and this isn't a range
|
||||
STATIC_ASSERT(std::same_as<decltype(ranges::data(std::declval<int const (&)[]>())), int const*>);
|
||||
STATIC_ASSERT(std::same_as<decltype(ranges::cdata(std::declval<int const (&)[]>())), int const*>);
|
||||
|
@ -613,7 +613,7 @@ STATIC_ASSERT(!CanREnd<decltype((initially_unbounded))>);
|
|||
STATIC_ASSERT(!CanCRBegin<decltype((initially_unbounded))>);
|
||||
STATIC_ASSERT(!CanCREnd<decltype((initially_unbounded))>);
|
||||
STATIC_ASSERT(!CanSize<decltype((initially_unbounded))>);
|
||||
STATIC_ASSERT(!ranges::empty(initially_unbounded));
|
||||
STATIC_ASSERT(!CanEmpty<decltype((initially_unbounded))>);
|
||||
STATIC_ASSERT(ranges::data(initially_unbounded) == initially_unbounded);
|
||||
STATIC_ASSERT(ranges::cdata(initially_unbounded) == initially_unbounded);
|
||||
int initially_unbounded[42];
|
||||
|
@ -1414,8 +1414,8 @@ namespace nothrow_testing {
|
|||
} // namespace nothrow_testing
|
||||
|
||||
namespace subsumption_testing {
|
||||
// Validate that the "readable" range concepts properly subsume (doubly important given that we spell them
|
||||
// differently than does the working draft)
|
||||
// Validate that the "indirectly_readable" range concepts properly subsume (doubly important given that we spell
|
||||
// them differently than does the working draft)
|
||||
enum range_type {
|
||||
exactly_range,
|
||||
exactly_input_range,
|
||||
|
@ -1465,51 +1465,53 @@ namespace subsumption_testing {
|
|||
STATIC_ASSERT(f<int (&)[42]>() == exactly_contiguous_range);
|
||||
} // namespace subsumption_testing
|
||||
|
||||
namespace safe_range_testing {
|
||||
namespace borrowed_range_testing {
|
||||
template <class Rng, class Iterator, class Sentinel = Iterator, class RIterator = std::reverse_iterator<Iterator>,
|
||||
class RSentinel = RIterator>
|
||||
constexpr bool test_safe_range() {
|
||||
// Validate that rvalue/lvalue const/non-const Rng models safe_range
|
||||
constexpr bool test_borrowed_range() {
|
||||
// Validate that rvalue/lvalue const/non-const Rng models borrowed_range
|
||||
STATIC_ASSERT(Decayed<Rng>);
|
||||
|
||||
STATIC_ASSERT(test_begin<Rng, Iterator>());
|
||||
STATIC_ASSERT(test_end<Rng, Sentinel>());
|
||||
STATIC_ASSERT(test_rbegin<Rng, RIterator>());
|
||||
STATIC_ASSERT(test_rend<Rng, RSentinel>());
|
||||
STATIC_ASSERT(ranges::safe_range<Rng>);
|
||||
STATIC_ASSERT(ranges::borrowed_range<Rng>);
|
||||
|
||||
STATIC_ASSERT(test_begin<Rng&, Iterator>());
|
||||
STATIC_ASSERT(test_end<Rng&, Sentinel>());
|
||||
STATIC_ASSERT(test_rbegin<Rng&, RIterator>());
|
||||
STATIC_ASSERT(test_rend<Rng&, RSentinel>());
|
||||
STATIC_ASSERT(ranges::safe_range<Rng&>);
|
||||
STATIC_ASSERT(ranges::borrowed_range<Rng&>);
|
||||
|
||||
STATIC_ASSERT(test_begin<Rng const, Iterator>());
|
||||
STATIC_ASSERT(test_end<Rng const, Sentinel>());
|
||||
STATIC_ASSERT(test_rbegin<Rng const, RIterator>());
|
||||
STATIC_ASSERT(test_rend<Rng const, RSentinel>());
|
||||
STATIC_ASSERT(ranges::safe_range<Rng const>);
|
||||
STATIC_ASSERT(ranges::borrowed_range<Rng const>);
|
||||
|
||||
STATIC_ASSERT(test_begin<Rng const&, Iterator>());
|
||||
STATIC_ASSERT(test_end<Rng const&, Sentinel>());
|
||||
STATIC_ASSERT(test_rbegin<Rng const&, RIterator>());
|
||||
STATIC_ASSERT(test_rend<Rng const&, RSentinel>());
|
||||
STATIC_ASSERT(ranges::safe_range<Rng const&>);
|
||||
STATIC_ASSERT(ranges::borrowed_range<Rng const&>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC_ASSERT(test_safe_range<std::string_view, std::string_view::iterator>());
|
||||
STATIC_ASSERT(test_safe_range<std::wstring_view, std::wstring_view::iterator>());
|
||||
STATIC_ASSERT(test_safe_range<std::span<int>, std::span<int>::iterator>());
|
||||
STATIC_ASSERT(test_safe_range<std::span<int, 42>, std::span<int, 42>::iterator>());
|
||||
STATIC_ASSERT(test_borrowed_range<std::string_view, std::string_view::iterator>());
|
||||
STATIC_ASSERT(test_borrowed_range<std::wstring_view, std::wstring_view::iterator>());
|
||||
STATIC_ASSERT(test_borrowed_range<std::span<int>, std::span<int>::iterator>());
|
||||
STATIC_ASSERT(test_borrowed_range<std::span<int, 42>, std::span<int, 42>::iterator>());
|
||||
#if 0 // TRANSITION, subrange
|
||||
STATIC_ASSERT(test_borrowed_range<ranges::subrange<int*, int*>, int*>());
|
||||
#endif // TRANSITION, subrange
|
||||
#if 0 // TRANSITION, future
|
||||
STATIC_ASSERT(test_safe_range<ranges::subrange<int*, int*>, int*>());
|
||||
STATIC_ASSERT(test_safe_range<ranges::ref_view<int[42]>, int*>());
|
||||
STATIC_ASSERT(test_safe_range<ranges::iota_view<int, int>, ...>());
|
||||
STATIC_ASSERT(test_borrowed_range<ranges::ref_view<int[42]>, int*>());
|
||||
STATIC_ASSERT(test_borrowed_range<ranges::iota_view<int, int>, ...>());
|
||||
#endif // TRANSITION, future
|
||||
|
||||
struct simple_safe_range {
|
||||
struct simple_borrowed_range {
|
||||
int* begin() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1518,25 +1520,25 @@ namespace safe_range_testing {
|
|||
}
|
||||
};
|
||||
|
||||
struct less_simple_safe_range {
|
||||
friend int* begin(less_simple_safe_range) {
|
||||
struct less_simple_borrowed_range {
|
||||
friend int* begin(less_simple_borrowed_range) {
|
||||
return nullptr;
|
||||
}
|
||||
friend int* end(less_simple_safe_range) {
|
||||
friend int* end(less_simple_borrowed_range) {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
} // namespace safe_range_testing
|
||||
} // namespace borrowed_range_testing
|
||||
|
||||
template <>
|
||||
inline constexpr bool std::ranges::enable_safe_range<safe_range_testing::simple_safe_range> = true;
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<borrowed_range_testing::simple_borrowed_range> = true;
|
||||
template <>
|
||||
inline constexpr bool std::ranges::enable_safe_range<safe_range_testing::less_simple_safe_range> = true;
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<borrowed_range_testing::less_simple_borrowed_range> = true;
|
||||
|
||||
namespace safe_range_testing {
|
||||
STATIC_ASSERT(test_safe_range<simple_safe_range, int*>());
|
||||
STATIC_ASSERT(test_safe_range<less_simple_safe_range, int*>());
|
||||
} // namespace safe_range_testing
|
||||
namespace borrowed_range_testing {
|
||||
STATIC_ASSERT(test_borrowed_range<simple_borrowed_range, int*>());
|
||||
STATIC_ASSERT(test_borrowed_range<less_simple_borrowed_range, int*>());
|
||||
} // namespace borrowed_range_testing
|
||||
|
||||
template <bool AllowNonConst, bool AllowConst, bool AllowSize>
|
||||
struct arbitrary_range {
|
||||
|
|
|
@ -2357,117 +2357,51 @@ namespace test_object_concepts {
|
|||
STATIC_ASSERT(test_regular<RegularType>());
|
||||
} // namespace test_object_concepts
|
||||
|
||||
namespace test_boolean {
|
||||
using std::boolean;
|
||||
namespace test_boolean_testable {
|
||||
// Note: other than knowing the secret internal concept name, this is a portable test.
|
||||
using std::_Boolean_testable;
|
||||
|
||||
// Better have these three, since we use them as examples in the Standard.
|
||||
STATIC_ASSERT(boolean<bool>);
|
||||
STATIC_ASSERT(boolean<std::true_type>);
|
||||
STATIC_ASSERT(boolean<std::bitset<42>::reference>);
|
||||
// Better have these four, since we use them as examples in the Standard.
|
||||
STATIC_ASSERT(_Boolean_testable<bool>);
|
||||
STATIC_ASSERT(_Boolean_testable<std::true_type>);
|
||||
STATIC_ASSERT(_Boolean_testable<int*>);
|
||||
STATIC_ASSERT(_Boolean_testable<std::bitset<42>::reference>);
|
||||
|
||||
STATIC_ASSERT(boolean<std::false_type>);
|
||||
STATIC_ASSERT(_Boolean_testable<std::false_type>);
|
||||
|
||||
STATIC_ASSERT(boolean<int>); // Over the restricted domain {0, 1}
|
||||
STATIC_ASSERT(!boolean<void*>);
|
||||
STATIC_ASSERT(_Boolean_testable<int>);
|
||||
STATIC_ASSERT(_Boolean_testable<void*>);
|
||||
|
||||
enum unscoped_boolish : bool { No, Yes };
|
||||
STATIC_ASSERT(boolean<unscoped_boolish>);
|
||||
STATIC_ASSERT(_Boolean_testable<unscoped_boolish>);
|
||||
|
||||
enum class scoped_boolish : bool { No, Yes };
|
||||
STATIC_ASSERT(!boolean<scoped_boolish>);
|
||||
STATIC_ASSERT(!_Boolean_testable<scoped_boolish>);
|
||||
|
||||
STATIC_ASSERT(!boolean<EmptyClass>);
|
||||
STATIC_ASSERT(!_Boolean_testable<EmptyClass>);
|
||||
|
||||
STATIC_ASSERT(boolean<ImplicitTo<bool>>);
|
||||
STATIC_ASSERT(!boolean<ExplicitTo<bool>>);
|
||||
STATIC_ASSERT(_Boolean_testable<ImplicitTo<bool>>);
|
||||
STATIC_ASSERT(!_Boolean_testable<ExplicitTo<bool>>);
|
||||
|
||||
struct MutatingBoolConversion {
|
||||
operator bool();
|
||||
};
|
||||
STATIC_ASSERT(!boolean<MutatingBoolConversion>);
|
||||
STATIC_ASSERT(_Boolean_testable<MutatingBoolConversion>);
|
||||
|
||||
static constexpr unsigned Archetype_max = 28;
|
||||
template <unsigned Select> // values in [0, Archetype_max) select a requirement to violate
|
||||
struct Archetype {
|
||||
// clang-format off
|
||||
operator bool() const requires (Select != 0); // Archetype<0> is not implicitly convertible to bool
|
||||
explicit operator bool() const requires (Select < 2); // Archetype<1> is not explicitly convertible to bool (ambiguity)
|
||||
void operator!() const requires (Select == 2); // !Archetype<2> is not ConvertibleTo<bool>
|
||||
void operator!() const requires (Select == 2); // !Archetype<2> does not model _Boolean_testable_impl
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
void operator&&(Archetype<3>, Archetype<3>) {} // Archetype<3> && Archetype<3> is not same_as<bool>
|
||||
void operator&&(Archetype<4>, bool) {} // Archetype<3> && bool is not same_as<bool>
|
||||
void operator&&(bool, Archetype<5>) {} // bool && Archetype<5> is not same_as<bool>
|
||||
void operator||(Archetype<6>, Archetype<6>) {} // Archetype<6> || Archetype<6> is not same_as<bool>
|
||||
void operator||(Archetype<7>, bool) {} // Archetype<7> || bool is not same_as<bool>
|
||||
void operator||(bool, Archetype<8>) {} // bool || Archetype<8> is not same_as<bool>
|
||||
void operator==(Archetype<9>, Archetype<9>) {} // Archetype<9> == Archetype<9> is not ConvertibleTo<bool>
|
||||
void operator==(Archetype<10>, bool) {} // Archetype<10> == bool is not ConvertibleTo<bool>
|
||||
void operator==(bool, Archetype<11>) {} // bool == Archetype<11> is not ConvertibleTo<bool>
|
||||
void operator!=(Archetype<12>, Archetype<12>) {} // Archetype<12> != Archetype<12> is not ConvertibleTo<bool>
|
||||
void operator!=(Archetype<13>, bool) {} // Archetype<13> != bool is not ConvertibleTo<bool>
|
||||
void operator!=(bool, Archetype<14>) {} // bool != Archetype<14> is not ConvertibleTo<bool>
|
||||
ImplicitTo<bool> operator&&(Archetype<15>, Archetype<15>) { // Archetype<15> && Archetype<15> is not same_as<bool>
|
||||
return {};
|
||||
}
|
||||
ImplicitTo<bool> operator&&(Archetype<16>, bool) { // Archetype<16> && bool is not same_as<bool>
|
||||
return {};
|
||||
}
|
||||
ImplicitTo<bool> operator&&(bool, Archetype<17>) { // bool && Archetype<17> is not same_as<bool>
|
||||
return {};
|
||||
}
|
||||
ImplicitTo<bool> operator||(Archetype<18>, Archetype<18>) { // Archetype<18> || Archetype<18> is not same_as<bool>
|
||||
return {};
|
||||
}
|
||||
ImplicitTo<bool> operator||(Archetype<19>, bool) { // Archetype<19> || bool is not same_as<bool>
|
||||
return {};
|
||||
}
|
||||
ImplicitTo<bool> operator||(bool, Archetype<20>) { // bool || Archetype<20> is not same_as<bool>
|
||||
return {};
|
||||
}
|
||||
ExplicitTo<bool> operator==(
|
||||
Archetype<21>, Archetype<21>) { // Archetype<21> == Archetype<21> is only explicitly convertible to bool
|
||||
return {};
|
||||
}
|
||||
ExplicitTo<bool> operator==(Archetype<22>, bool) { // Archetype<22> == bool is only explicitly convertible to bool
|
||||
return {};
|
||||
}
|
||||
ExplicitTo<bool> operator==(bool, Archetype<23>) { // bool == Archetype<23> is only explicitly convertible to bool
|
||||
return {};
|
||||
}
|
||||
ExplicitTo<bool> operator!=(
|
||||
Archetype<24>, Archetype<24>) { // Archetype<24> != Archetype<24> is only explicitly convertible to bool
|
||||
return {};
|
||||
}
|
||||
ExplicitTo<bool> operator!=(Archetype<25>, bool) { // Archetype<25> != bool is only explicitly convertible to bool
|
||||
return {};
|
||||
}
|
||||
ExplicitTo<bool> operator!=(bool, Archetype<26>) { // bool != Archetype<26> is only explicitly convertible to bool
|
||||
return {};
|
||||
}
|
||||
|
||||
template <>
|
||||
struct Archetype<27> { // Archetype<27> is not movable
|
||||
Archetype() = default;
|
||||
Archetype(Archetype&&) = delete;
|
||||
operator bool() const;
|
||||
};
|
||||
|
||||
template <std::size_t I>
|
||||
constexpr void test_one() {
|
||||
STATIC_ASSERT(!boolean<Archetype<I>>);
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
constexpr bool test_Archetype(std::index_sequence<Is...>) {
|
||||
STATIC_ASSERT(std::is_same_v<std::index_sequence<Is...>, std::make_index_sequence<Archetype_max>>);
|
||||
(test_one<Is>(), ...);
|
||||
STATIC_ASSERT(boolean<Archetype<sizeof...(Is)>>);
|
||||
return true;
|
||||
}
|
||||
STATIC_ASSERT(test_Archetype(std::make_index_sequence<Archetype_max>{}));
|
||||
} // namespace test_boolean
|
||||
STATIC_ASSERT(!_Boolean_testable<Archetype<0>>);
|
||||
STATIC_ASSERT(!_Boolean_testable<Archetype<1>>);
|
||||
STATIC_ASSERT(!_Boolean_testable<Archetype<2>>);
|
||||
STATIC_ASSERT(_Boolean_testable<Archetype<3>>);
|
||||
} // namespace test_boolean_testable
|
||||
|
||||
namespace test_equality_comparable {
|
||||
using std::equality_comparable;
|
||||
|
@ -2503,11 +2437,11 @@ namespace test_equality_comparable {
|
|||
|
||||
template <unsigned Select>
|
||||
bool operator==(Archetype<Select> const&, Archetype<Select> const&);
|
||||
void operator==(Archetype<0> const&, Archetype<0> const&); // Archetype<0> == Archetype<0> doesn't model boolean
|
||||
void operator==(Archetype<0> const&, Archetype<0> const&); // Archetype<0> == Archetype<0> is not _Boolean_testable
|
||||
|
||||
template <unsigned Select>
|
||||
bool operator!=(Archetype<Select> const&, Archetype<Select> const&);
|
||||
void operator!=(Archetype<1> const&, Archetype<1> const&); // Archetype<1> != Archetype<1> doesn't model boolean
|
||||
void operator!=(Archetype<1> const&, Archetype<1> const&); // Archetype<1> != Archetype<1> is not _Boolean_testable
|
||||
|
||||
STATIC_ASSERT(!test<Archetype<0>>());
|
||||
STATIC_ASSERT(!test<Archetype<1>>());
|
||||
|
@ -3101,17 +3035,17 @@ namespace test_predicate {
|
|||
using RPF3 = bool const& (*&) (int, int, int);
|
||||
using RPF4 = bool (*&)(int, ...);
|
||||
STATIC_ASSERT(predicate<RF0>);
|
||||
STATIC_ASSERT(!predicate<RF1, int>);
|
||||
STATIC_ASSERT(predicate<RF1, int>);
|
||||
STATIC_ASSERT(predicate<RF2, int, long>);
|
||||
STATIC_ASSERT(predicate<RF3, int, long, int>);
|
||||
STATIC_ASSERT(predicate<RF4, int, float, void*>);
|
||||
STATIC_ASSERT(predicate<PF0>);
|
||||
STATIC_ASSERT(!predicate<PF1, int>);
|
||||
STATIC_ASSERT(predicate<PF1, int>);
|
||||
STATIC_ASSERT(predicate<PF2, int, long>);
|
||||
STATIC_ASSERT(predicate<PF3, int, long, int>);
|
||||
STATIC_ASSERT(predicate<PF4, int, float, void*>);
|
||||
STATIC_ASSERT(predicate<RPF0>);
|
||||
STATIC_ASSERT(!predicate<RPF1, int>);
|
||||
STATIC_ASSERT(predicate<RPF1, int>);
|
||||
STATIC_ASSERT(predicate<RPF2, int, long>);
|
||||
STATIC_ASSERT(predicate<RPF3, int, long, int>);
|
||||
STATIC_ASSERT(predicate<RPF4, int, float, void*>);
|
||||
|
@ -3351,14 +3285,16 @@ namespace test_predicate {
|
|||
} // namespace test_predicate
|
||||
|
||||
namespace test_relation {
|
||||
// Tests both relation and strict_weak_order (since they are syntactically identical)
|
||||
// Tests relation, equivalence_relation, and strict_weak_order (since they are syntactically identical)
|
||||
|
||||
using std::relation, std::strict_weak_order;
|
||||
using std::relation, std::equivalence_relation, std::strict_weak_order;
|
||||
|
||||
template <class F, class T, class U = T>
|
||||
constexpr bool test() {
|
||||
constexpr bool result = relation<F, T, U>;
|
||||
STATIC_ASSERT(relation<F, U, T> == result);
|
||||
STATIC_ASSERT(equivalence_relation<F, T, U> == result);
|
||||
STATIC_ASSERT(equivalence_relation<F, U, T> == result);
|
||||
STATIC_ASSERT(strict_weak_order<F, T, U> == result);
|
||||
STATIC_ASSERT(strict_weak_order<F, U, T> == result);
|
||||
return result;
|
||||
|
@ -3394,7 +3330,7 @@ namespace test_relation {
|
|||
|
||||
template <unsigned>
|
||||
struct B {};
|
||||
void operator==(B<1>, B<1>); // B<1> == B<1> does not model boolean
|
||||
void operator==(B<1>, B<1>); // B<1> == B<1> does not model _Boolean_testable
|
||||
template <unsigned U>
|
||||
bool operator==(B<U>, B<U>);
|
||||
STATIC_ASSERT(test<Equivalent, B<0>>());
|
||||
|
|
Загрузка…
Ссылка в новой задаче