* 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:
Casey Carter 2020-03-04 22:19:53 -08:00 коммит произвёл GitHub
Родитель 369008308c
Коммит 930b843f31
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
47 изменённых файлов: 3330 добавлений и 324 удалений

Просмотреть файл

@ -72,6 +72,160 @@ struct _Optimistic_temporary_buffer { // temporary storage with _alloca-like att
aligned_union_t<0, _Ty> _Stack_space[_Optimistic_count]; 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 // FUNCTION TEMPLATE for_each
template <class _InIt, class _Fn> template <class _InIt, class _Fn>
_CONSTEXPR20 _Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) { // perform function for each element [_First, _Last) _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 // _ITERATOR_DEBUG_ARRAY_OVERLOADS
#endif // _HAS_CXX17 #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 #if _HAS_CXX17
// PARALLEL FUNCTION TEMPLATE find_if // PARALLEL FUNCTION TEMPLATE find_if
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0> 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 _NODISCARD _FwdIt find_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
#endif // _HAS_CXX17 #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 // FUNCTION TEMPLATE find_if_not
template <class _InIt, class _Pr> template <class _InIt, class _Pr>
_NODISCARD _CONSTEXPR20 _InIt find_if_not(_InIt _First, const _InIt _Last, _Pr _Pred) { _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 _NODISCARD _FwdIt find_if_not(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept; // terminates
#endif // _HAS_CXX17 #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 // FUNCTION TEMPLATE adjacent_find
template <class _FwdIt, class _Pr> template <class _FwdIt, class _Pr>
_NODISCARD _CONSTEXPR20 _FwdIt adjacent_find(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) { _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 #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 // FUNCTION TEMPLATE count_if
template <class _InIt, class _Pr> template <class _InIt, class _Pr>
_NODISCARD _CONSTEXPR20 _Iter_diff_t<_InIt> count_if(_InIt _First, _InIt _Last, _Pr _Pred) { _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 _ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
#endif // _HAS_CXX17 #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 // FUNCTION TEMPLATE mismatch
template <class _InIt1, class _InIt2, class _Pr> template <class _InIt1, class _InIt2, class _Pr>
_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _Pr _Pred) { _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 #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 // FUNCTION TEMPLATE all_of
template <class _InIt, class _Pr> template <class _InIt, class _Pr>
_NODISCARD _CONSTEXPR20 bool all_of(_InIt _First, _InIt _Last, _Pr _Pred) { // test if all elements satisfy _Pred _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 _NODISCARD bool all_of(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept; // terminates
#endif // _HAS_CXX17 #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 // FUNCTION TEMPLATE any_of
template <class _InIt, class _Pr> template <class _InIt, class _Pr>
_NODISCARD _CONSTEXPR20 bool any_of(const _InIt _First, const _InIt _Last, _Pr _Pred) { _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 _NODISCARD bool any_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
#endif // _HAS_CXX17 #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 // FUNCTION TEMPLATE none_of
template <class _InIt, class _Pr> template <class _InIt, class _Pr>
_NODISCARD _CONSTEXPR20 bool none_of(const _InIt _First, const _InIt _Last, _Pr _Pred) { _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 _NODISCARD bool none_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
#endif // _HAS_CXX17 #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 // FUNCTION TEMPLATE copy_if
template <class _InIt, class _OutIt, class _Pr> template <class _InIt, class _OutIt, class _Pr>
_CONSTEXPR20 _OutIt copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy each satisfying _Pred _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 // _ITERATOR_DEBUG_ARRAY_OVERLOADS
#endif // _HAS_CXX17 #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 // FUNCTION TEMPLATE partition_copy
template <class _InIt, class _OutIt1, class _OutIt2, class _Pr> template <class _InIt, class _OutIt1, class _OutIt2, class _Pr>
_CONSTEXPR20 pair<_OutIt1, _OutIt2> partition_copy( _CONSTEXPR20 pair<_OutIt1, _OutIt2> partition_copy(

Просмотреть файл

@ -48,11 +48,9 @@ concept derived_from = __is_base_of(_Base, _Derived)
// CONCEPT convertible_to // CONCEPT convertible_to
template <class _From, class _To> template <class _From, class _To>
concept convertible_to = __is_convertible_to(_From, _To) concept convertible_to = __is_convertible_to(_From, _To)
#if 1 // Implement the PR of LWG-3151 && requires(add_rvalue_reference_t<_From> (&_Fn)()) {
&& requires { static_cast<_To>(_STD declval<_From>()); }; static_cast<_To>(_Fn());
#else // ^^^ LWG-3151 / N4810 vvv };
&& requires(_From (&_Fn)()) { static_cast<_To>(_Fn()); };
#endif // select LWG-3151 vs. N4810
// CONCEPT common_reference_with // CONCEPT common_reference_with
template <class _Ty1, class _Ty2> template <class _Ty1, class _Ty2>
@ -181,12 +179,7 @@ concept swappable = requires(_Ty& __x, _Ty& __y) {
// CONCEPT swappable_with // CONCEPT swappable_with
template <class _Ty1, class _Ty2> template <class _Ty1, class _Ty2>
concept swappable_with = concept swappable_with = common_reference_with<_Ty1, _Ty2>
#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
&& requires(_Ty1&& __t, _Ty2&& __u) { && requires(_Ty1&& __t, _Ty2&& __u) {
_RANGES swap(static_cast<_Ty1&&>(__t), static_cast<_Ty1&&>(__t)); _RANGES swap(static_cast<_Ty1&&>(__t), static_cast<_Ty1&&>(__t));
_RANGES swap(static_cast<_Ty2&&>(__u), static_cast<_Ty2&&>(__u)); _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>
&& 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> 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> template <class _Ty>
concept _STL_BOOLEAN_CONCEPT = movable<remove_cvref_t<_Ty>> concept _Boolean_testable = _Boolean_testable_impl<_Ty>
&& requires(const remove_reference_t<_Ty>& __x, const remove_reference_t<_Ty>& __y, const bool __b) { && requires (_Ty&& __t) {
{ __x } -> convertible_to<bool>; { !static_cast<_Ty&&>(__t) } -> _Boolean_testable_impl;
{ !__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 _Weakly_equality_comparable_with // CONCEPT _Weakly_equality_comparable_with
template <class _Ty1, class _Ty2> template <class _Ty1, class _Ty2>
concept _Half_equality_comparable = concept _Half_equality_comparable =
requires(const remove_reference_t<_Ty1>& __x, const remove_reference_t<_Ty2>& __y) { requires(const remove_reference_t<_Ty1>& __x, const remove_reference_t<_Ty2>& __y) {
{ __x == __y } -> _STL_BOOLEAN_CONCEPT; { __x == __y } -> _Boolean_testable;
{ __x != __y } -> _STL_BOOLEAN_CONCEPT; { __x != __y } -> _Boolean_testable;
}; };
template <class _Ty1, class _Ty2> template <class _Ty1, class _Ty2>
@ -257,10 +231,10 @@ concept equality_comparable_with = equality_comparable<_Ty1> && equality_compara
// CONCEPT _Partially_ordered_with // CONCEPT _Partially_ordered_with
template <class _Ty1, class _Ty2> template <class _Ty1, class _Ty2>
concept _Half_ordered = requires(const remove_reference_t<_Ty1>& __t, const remove_reference_t<_Ty2>& __u) { concept _Half_ordered = requires(const remove_reference_t<_Ty1>& __t, const remove_reference_t<_Ty2>& __u) {
{ __t < __u } -> _STL_BOOLEAN_CONCEPT; { __t < __u } -> _Boolean_testable;
{ __t > __u } -> _STL_BOOLEAN_CONCEPT; { __t > __u } -> _Boolean_testable;
{ __t <= __u } -> _STL_BOOLEAN_CONCEPT; { __t <= __u } -> _Boolean_testable;
{ __t >= __u } -> _STL_BOOLEAN_CONCEPT; { __t >= __u } -> _Boolean_testable;
}; };
template <class _Ty1, class _Ty2> 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>&>> && totally_ordered<common_reference_t<const remove_reference_t<_Ty1>&, const remove_reference_t<_Ty2>&>>
&& _Partially_ordered_with<_Ty1, _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 // CONCEPT copyable
template <class _Ty> 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 // CONCEPT semiregular
template <class _Ty> template <class _Ty>
@ -301,13 +286,21 @@ concept regular_invocable = invocable<_FTy, _ArgTys...>;
// CONCEPT predicate // CONCEPT predicate
template <class _FTy, class... _ArgTys> 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 // CONCEPT relation
template <class _FTy, class _Ty1, class _Ty2> 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>; && 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 // CONCEPT strict_weak_order
template <class _FTy, class _Ty1, class _Ty2> template <class _FTy, class _Ty1, class _Ty2>
concept strict_weak_order = relation<_FTy, _Ty1, _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); 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 #if _HAS_CXX17
// FUNCTION TEMPLATE not_fn // FUNCTION TEMPLATE not_fn
struct _Not_fn_tag { struct _Not_fn_tag {

Просмотреть файл

@ -25,15 +25,12 @@ namespace ranges {
// Much machinery defined in <xutility> // Much machinery defined in <xutility>
// clang-format off // 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 // CONCEPT ranges::viewable_range
template <class _Rng> template <class _Rng>
concept viewable_range = range<_Rng> && (safe_range<_Rng> || view<remove_cvref_t<_Rng>>); concept viewable_range = range<_Rng>
// clang-format on && (borrowed_range<_Rng> || view<remove_cvref_t<_Rng>>);
} // namespace ranges } // namespace ranges
_STD_END _STD_END
#pragma pop_macro("new") #pragma pop_macro("new")

Просмотреть файл

@ -260,7 +260,7 @@ class span;
#ifdef __cpp_lib_concepts #ifdef __cpp_lib_concepts
namespace ranges { namespace ranges {
template <class _Ty, size_t _Extent> 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 } // namespace ranges
// VARIABLE TEMPLATE _Is_span_v // VARIABLE TEMPLATE _Is_span_v
@ -293,7 +293,7 @@ concept _Is_span_compatible_range =
&& !_Is_std_array_v<remove_cvref_t<_Rng>> && !_Is_std_array_v<remove_cvref_t<_Rng>>
&& _RANGES contiguous_range<_Rng> && _RANGES contiguous_range<_Rng>
&& _RANGES sized_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(*)[]>; && is_convertible_v<remove_reference_t<_RANGES range_reference_t<_Rng>>(*)[], _Ty(*)[]>;
// clang-format on // clang-format on
#else // ^^^ __cpp_lib_concepts / !__cpp_lib_concepts vvv #else // ^^^ __cpp_lib_concepts / !__cpp_lib_concepts vvv

Просмотреть файл

@ -1576,7 +1576,7 @@ private:
#ifdef __cpp_lib_concepts #ifdef __cpp_lib_concepts
namespace ranges { namespace ranges {
template <class _Elem, class _Traits> 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 } // namespace ranges
#endif // __cpp_lib_concepts #endif // __cpp_lib_concepts

Просмотреть файл

@ -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 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 #endif // _HAS_CXX20
// FUNCTION TEMPLATE _Pass_fn // FUNCTION TEMPLATE _Pass_fn
@ -312,10 +322,10 @@ template <class>
struct iterator_traits; struct iterator_traits;
template <class _Ty> template <class _Ty>
using iter_difference_t = typename conditional_t<_Is_from_primary<iterator_traits<_Ty>>, incrementable_traits<_Ty>, using iter_difference_t = typename conditional_t<_Is_from_primary<iterator_traits<remove_cvref_t<_Ty>>>,
iterator_traits<_Ty>>::difference_type; 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> template <class>
struct _Cond_value_type {}; struct _Cond_value_type {};
@ -328,32 +338,32 @@ struct _Cond_value_type<_Ty> {
// clang-format on // clang-format on
template <class> template <class>
struct readable_traits {}; struct indirectly_readable_traits {};
template <class _Ty> template <class _Ty>
struct readable_traits<_Ty*> : _Cond_value_type<_Ty> {}; struct indirectly_readable_traits<_Ty*> : _Cond_value_type<_Ty> {};
// clang-format off // clang-format off
template <class _Ty> template <class _Ty>
requires is_array_v<_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>>; using value_type = remove_cv_t<remove_extent_t<_Ty>>;
}; };
// clang-format on // clang-format on
template <class _Ty> 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> 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> 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 // ALIAS TEMPLATE iter_value_t
template <class _Ty> template <class _Ty>
using iter_value_t = typename conditional_t<_Is_from_primary<iterator_traits<_Ty>>, readable_traits<_Ty>, using iter_value_t = typename conditional_t<_Is_from_primary<iterator_traits<remove_cvref_t<_Ty>>>,
iterator_traits<_Ty>>::value_type; indirectly_readable_traits<remove_cvref_t<_Ty>>, iterator_traits<remove_cvref_t<_Ty>>>::value_type;
// ALIAS TEMPLATE iter_reference_t // ALIAS TEMPLATE iter_reference_t
template <_Dereferenceable _Ty> template <_Dereferenceable _Ty>
@ -411,11 +421,13 @@ concept _Cpp17_iterator = copyable<_It> && requires(_It __i) {
}; };
template <class _It> template <class _It>
concept _Cpp17_input_iterator = _Cpp17_iterator<_It> && equality_comparable<_It> concept _Cpp17_input_iterator = _Cpp17_iterator<_It>
&& _Has_member_difference_type<incrementable_traits<_It>> && _Has_member_value_type<readable_traits<_It>> && equality_comparable<_It>
&& _Has_member_difference_type<incrementable_traits<_It>>
&& _Has_member_value_type<indirectly_readable_traits<_It>>
&& requires(_It __i) { && requires(_It __i) {
typename common_reference_t<iter_reference_t<_It>&&, 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 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>; requires signed_integral<typename incrementable_traits<_It>::difference_type>;
}; };
@ -544,7 +556,7 @@ struct _Iter_traits_category2<false> {
// clang-format off // clang-format off
template <class _It> template <class _It>
concept _Cpp17_forward_delta = constructible_from<_It> && is_lvalue_reference_v<iter_reference_t<_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) { && requires(_It __i) {
{ __i++ } -> convertible_to<const _It&>; { __i++ } -> convertible_to<const _It&>;
requires same_as<decltype(*__i++), iter_reference_t<_It>>; requires same_as<decltype(*__i++), iter_reference_t<_It>>;
@ -569,7 +581,7 @@ template <class _It>
struct _Iterator_traits_base<_It> { struct _Iterator_traits_base<_It> {
using iterator_category = typename _Iter_traits_category<_Has_member_iterator_category<_It>>::template _Apply<_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 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<( using pointer = typename _Iter_traits_pointer<(
_Has_member_pointer<_It> ? _Itraits_pointer_strategy::_Use_member _Has_member_pointer<_It> ? _Itraits_pointer_strategy::_Use_member
: _Has_op_arrow<_It&> ? _Itraits_pointer_strategy::_Use_decltype : _Has_op_arrow<_It&> ? _Itraits_pointer_strategy::_Use_decltype
@ -607,12 +619,13 @@ namespace ranges {
}; };
namespace _Iter_move { namespace _Iter_move {
void iter_move(); // Block unqualified lookup per LWG-3247 void iter_move(); // Block unqualified name lookup
// clang-format off // clang-format off
template <class _Ty> template <class _Ty>
concept _Has_ADL = _Has_class_or_enum_type<_Ty> // Per LWG-3299 concept _Has_ADL = _Has_class_or_enum_type<_Ty> && requires(_Ty&& __t) {
&& requires(_Ty&& __t) { iter_move(static_cast<_Ty&&>(__t)); }; iter_move(static_cast<_Ty&&>(__t));
};
template <class _Ty> template <class _Ty>
concept _Can_deref = requires(_Ty&& __t) { 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&>())); using iter_rvalue_reference_t = decltype(_RANGES iter_move(_STD declval<_Ty&>()));
// CONCEPT readable // CONCEPT indirectly_readable
template <class _It> template <class _It>
concept readable = requires { concept _Indirectly_readable_impl = requires(const _It __i) {
typename iter_value_t<_It>; typename iter_value_t<_It>;
typename iter_reference_t<_It>; typename iter_reference_t<_It>;
typename iter_rvalue_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_value_t<_It>&>
&& common_reference_with<iter_reference_t<_It>&&, iter_rvalue_reference_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>&>; && 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 // clang-format on
// ALIAS TEMPLATE iter_common_reference_t // 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>&>; 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> 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); *__i = static_cast<_Ty&&>(__t);
*static_cast<_It&&>(__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); 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++; __i++;
}; };
// ALIAS TEMPLATE _Make_unsigned_like_t
template <class _Ty>
using _Make_unsigned_like_t = make_unsigned_t<_Ty>;
// CONCEPT incrementable // CONCEPT incrementable
template <class _Ty> template <class _Ty>
concept incrementable = regular<_Ty> && weakly_incrementable<_Ty> && requires(_Ty __t) { 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 // clang-format off
// CONCEPT input_iterator // CONCEPT input_iterator
template <class _It> 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>; && derived_from<_Iter_concept<_It>, input_iterator_tag>;
// CONCEPT output_iterator // CONCEPT output_iterator
template <class _It, class _Ty> template <class _It, class _Ty>
concept output_iterator = input_or_output_iterator<_It> && writable<_It, _Ty> && requires(_It __i, _Ty&& __t) { concept output_iterator = input_or_output_iterator<_It> && indirectly_writable<_It, _Ty>
*__i++ = static_cast<_Ty&&>(__t); && requires(_It __i, _Ty&& __t) {
}; *__i++ = static_cast<_Ty&&>(__t);
};
// CONCEPT forward_iterator // CONCEPT forward_iterator
template <class _It> 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>>>; { _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 // CONCEPT indirectly_movable
template <class _In, class _Out> 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 // CONCEPT indirectly_movable_storable
template <class _In, class _Out> template <class _In, class _Out>
concept indirectly_movable_storable = indirectly_movable<_In, _Out> && writable<_Out, iter_value_t<_In>> concept indirectly_movable_storable = indirectly_movable<_In, _Out>
&& movable<iter_value_t<_In>> && constructible_from<iter_value_t<_In>, iter_rvalue_reference_t<_In>> && 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>>; && 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 // clang-format on
// CUSTOMIZATION POINT OBJECT iter_swap // CUSTOMIZATION POINT OBJECT iter_swap
@ -846,13 +949,14 @@ namespace ranges {
// clang-format off // clang-format off
template <class _Ty1, class _Ty2> 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) { && requires(_Ty1&& __t1, _Ty2&& __t2) {
iter_swap(static_cast<_Ty1&&>(__t1), static_cast<_Ty2&&>(__t2)); iter_swap(static_cast<_Ty1&&>(__t1), static_cast<_Ty2&&>(__t2));
}; };
template <class _Ty1, class _Ty2> 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>>; && swappable_with<iter_reference_t<_Ty1>, iter_reference_t<_Ty2>>;
// clang-format on // clang-format on
@ -912,6 +1016,25 @@ namespace ranges {
} }
} // 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 // ALIAS TEMPLATE _Iter_ref_t
template <class _Iter> template <class _Iter>
using _Iter_ref_t = iter_reference_t<_Iter>; using _Iter_ref_t = iter_reference_t<_Iter>;
@ -2018,14 +2141,14 @@ namespace ranges {
inline constexpr bool _Has_complete_elements<_Ty> = true; inline constexpr bool _Has_complete_elements<_Ty> = true;
// clang-format on // clang-format on
// VARIABLE TEMPLATE ranges::enable_safe_range // VARIABLE TEMPLATE ranges::enable_borrowed_range
template <class> template <class>
inline constexpr bool enable_safe_range = false; inline constexpr bool enable_borrowed_range = false;
template <class _Rng> 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 { namespace _Begin {
template <class _Ty> template <class _Ty>
void begin(_Ty&) = delete; void begin(_Ty&) = delete;
@ -2054,8 +2177,8 @@ namespace ranges {
if constexpr (is_array_v<remove_reference_t<_Ty>>) { if constexpr (is_array_v<remove_reference_t<_Ty>>) {
static_assert(_Has_complete_elements<_Ty>, static_assert(_Has_complete_elements<_Ty>,
"The range access customization point objects " "The range access customization point objects "
"std::ranges::begin, std::ranges::end, std::ranges::rbegin, and std::ranges::rend " "std::ranges::begin, std::ranges::end, std::ranges::rbegin, std::ranges::rend, "
"do not accept arrays with incomplete element types."); "and std::ranges::data do not accept arrays with incomplete element types.");
return {_St::_Array, true}; return {_St::_Array, true};
} else if constexpr (_Has_member<_Ty>) { } else if constexpr (_Has_member<_Ty>) {
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty>().begin()))}; return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty>().begin()))};
@ -2092,11 +2215,11 @@ namespace ranges {
inline constexpr _Begin::_Cpo begin; inline constexpr _Begin::_Cpo begin;
} }
// ALIAS TEMPLATE ranges::iterator_t (Implements D2091R0) // ALIAS TEMPLATE ranges::iterator_t
template <class _Ty> template <class _Ty>
using iterator_t = decltype(_RANGES begin(_STD declval<_Ty&>())); using iterator_t = decltype(_RANGES begin(_STD declval<_Ty&>()));
// CUSTOMIZATION POINT OBJECT ranges::end (Implements D2091R0) // CUSTOMIZATION POINT OBJECT ranges::end
namespace _End { namespace _End {
template <class _Ty> template <class _Ty>
void end(_Ty&) = delete; void end(_Ty&) = delete;
@ -2127,8 +2250,8 @@ namespace ranges {
if constexpr (is_array_v<_UnRef>) { if constexpr (is_array_v<_UnRef>) {
static_assert(_Has_complete_elements<_UnRef>, static_assert(_Has_complete_elements<_UnRef>,
"The range access customization point objects " "The range access customization point objects "
"std::ranges::begin, std::ranges::end, std::ranges::rbegin, and std::ranges::rend " "std::ranges::begin, std::ranges::end, std::ranges::rbegin, std::ranges::rend, "
"do not accept arrays with incomplete element types."); "and std::ranges::data do not accept arrays with incomplete element types.");
if constexpr (extent_v<_UnRef> != 0) { if constexpr (extent_v<_UnRef> != 0) {
return {_St::_Array, true}; return {_St::_Array, true};
} else { } else {
@ -2177,10 +2300,10 @@ namespace ranges {
_RANGES end(__r); _RANGES end(__r);
}; };
// CONCEPT ranges::safe_range // CONCEPT ranges::borrowed_range
// clang-format off // clang-format off
template <class _Rng> template <class _Rng>
concept safe_range = range<_Rng> && _Should_range_access<_Rng>; concept borrowed_range = range<_Rng> && _Should_range_access<_Rng>;
// clang-format on // clang-format on
// ALIAS TEMPLATE ranges::sentinel_t // ALIAS TEMPLATE ranges::sentinel_t
@ -2235,7 +2358,7 @@ namespace ranges {
inline constexpr _Cend_fn cend; inline constexpr _Cend_fn cend;
} }
// CUSTOMIZATION POINT OBJECT ranges::rbegin (Implements D2091R0) // CUSTOMIZATION POINT OBJECT ranges::rbegin
namespace _Rbegin { namespace _Rbegin {
template <class _Ty> template <class _Ty>
void rbegin(_Ty&) = delete; void rbegin(_Ty&) = delete;
@ -2304,7 +2427,7 @@ namespace ranges {
inline constexpr _Rbegin::_Cpo rbegin; inline constexpr _Rbegin::_Cpo rbegin;
} }
// CUSTOMIZATION POINT OBJECT ranges::rend (Implements D2091R0) // CUSTOMIZATION POINT OBJECT ranges::rend
namespace _Rend { namespace _Rend {
template <class _Ty> template <class _Ty>
void rend(_Ty&) = delete; void rend(_Ty&) = delete;
@ -2410,7 +2533,7 @@ namespace ranges {
template <class> template <class>
inline constexpr bool disable_sized_range = false; inline constexpr bool disable_sized_range = false;
// CUSTOMIZATION POINT OBJECT ranges::size (Implements D2091R0) // CUSTOMIZATION POINT OBJECT ranges::size
namespace _Size { namespace _Size {
template <class _Ty> template <class _Ty>
void size(_Ty&) = delete; void size(_Ty&) = delete;
@ -2479,7 +2602,7 @@ namespace ranges {
return size(_Val); return size(_Val);
} else if constexpr (_Choice<_Ty&>._Strategy == _St::_Subtract) { } else if constexpr (_Choice<_Ty&>._Strategy == _St::_Subtract) {
const auto _Delta = _RANGES end(_Val) - _RANGES begin(_Val); 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 { } else {
static_assert(_Always_false<_Ty>, "should be unreachable"); static_assert(_Always_false<_Ty>, "should be unreachable");
} }
@ -2492,7 +2615,7 @@ namespace ranges {
inline constexpr _Size::_Cpo size; inline constexpr _Size::_Cpo size;
} }
// CUSTOMIZATION POINT OBJECT ranges::empty (Implements D2091R0) // CUSTOMIZATION POINT OBJECT ranges::empty
namespace _Empty { namespace _Empty {
// clang-format off // clang-format off
template <class _Ty> template <class _Ty>
@ -2514,13 +2637,13 @@ namespace ranges {
class _Cpo { class _Cpo {
private: private:
enum class _St { _None, _Array, _Member, _Size, _Compare }; enum class _St { _None, _Member, _Size, _Compare };
template <class _Ty> template <class _Ty>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
_STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>);
if constexpr (is_array_v<remove_reference_t<_Ty>>) { if constexpr (is_unbounded_array_v<remove_reference_t<_Ty>>) {
return {_St::_Array, true}; return {_St::_None};
} else if constexpr (_Has_member<_Ty>) { } else if constexpr (_Has_member<_Ty>) {
return {_St::_Member, noexcept(static_cast<bool>(_STD declval<_Ty>().empty()))}; return {_St::_Member, noexcept(static_cast<bool>(_STD declval<_Ty>().empty()))};
} else if constexpr (_Has_size<_Ty>) { } else if constexpr (_Has_size<_Ty>) {
@ -2542,9 +2665,7 @@ namespace ranges {
template <class _Ty> template <class _Ty>
requires (_Choice<_Ty&>._Strategy != _St::_None) requires (_Choice<_Ty&>._Strategy != _St::_None)
_NODISCARD constexpr bool operator()([[maybe_unused]] _Ty&& _Val) const noexcept(_Choice<_Ty&>._No_throw) { _NODISCARD constexpr bool operator()([[maybe_unused]] _Ty&& _Val) const noexcept(_Choice<_Ty&>._No_throw) {
if constexpr (_Choice<_Ty&>._Strategy == _St::_Array) { if constexpr (_Choice<_Ty&>._Strategy == _St::_Member) {
return false;
} else if constexpr (_Choice<_Ty&>._Strategy == _St::_Member) {
return static_cast<bool>(_Val.empty()); return static_cast<bool>(_Val.empty());
} else if constexpr (_Choice<_Ty&>._Strategy == _St::_Size) { } else if constexpr (_Choice<_Ty&>._Strategy == _St::_Size) {
return _RANGES size(_Val) == 0; return _RANGES size(_Val) == 0;
@ -2562,7 +2683,7 @@ namespace ranges {
inline constexpr _Empty::_Cpo empty; inline constexpr _Empty::_Cpo empty;
} }
// CUSTOMIZATION POINT OBJECT ranges::data (Implements D2091R0) // CUSTOMIZATION POINT OBJECT ranges::data
namespace _Data { namespace _Data {
// clang-format off // clang-format off
template <class _Ty> template <class _Ty>
@ -2940,6 +3061,28 @@ namespace ranges {
using is_transparent = int; 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 } // namespace ranges
#endif // __cpp_lib_concepts #endif // __cpp_lib_concepts

Просмотреть файл

@ -169,21 +169,32 @@
// P1024R3 Enhancing span Usability // P1024R3 Enhancing span Usability
// P1085R2 Removing span Comparisons // P1085R2 Removing span Comparisons
// P1115R3 erase()/erase_if() Return size_type // P1115R3 erase()/erase_if() Return size_type
// P1207R4 Movability Of Single-Pass Iterators
// (partially implemented)
// P1209R0 erase_if(), erase() // P1209R0 erase_if(), erase()
// P1227R2 Signed std::ssize(), Unsigned span::size() // P1227R2 Signed std::ssize(), Unsigned span::size()
// P1243R4 Rangify New Algorithms
// (partially implemented)
// P1248R1 Fixing Relations
// P1357R1 is_bounded_array, is_unbounded_array // P1357R1 is_bounded_array, is_unbounded_array
// P1394R4 Range Constructor For span // P1394R4 Range Constructor For span
// P1423R3 char8_t Backward Compatibility Remediation // P1423R3 char8_t Backward Compatibility Remediation
// P1456R1 Move-Only Views // P1456R1 Move-Only Views
// P1474R1 Helpful Pointers For contiguous_iterator
// P1612R1 Relocating endian To <bit> // P1612R1 Relocating endian To <bit>
// P1645R1 constexpr For <numeric> Algorithms // P1645R1 constexpr For <numeric> Algorithms
// P1651R0 bind_front() Should Not Unwrap reference_wrapper // P1651R0 bind_front() Should Not Unwrap reference_wrapper
// P1690R1 Refining Heterogeneous Lookup For Unordered Containers // P1690R1 Refining Heterogeneous Lookup For Unordered Containers
// P1716R3 Range Comparison Algorithms Are Over-Constrained
// P1754R1 Rename Concepts To standard_case // 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 // P1872R0 span Should Have size_type, Not index_type
// P1878R1 Constraining Readable Types
// P1956R1 <bit> has_single_bit(), bit_ceil(), bit_floor(), bit_width() // P1956R1 <bit> has_single_bit(), bit_ceil(), bit_floor(), bit_width()
// P1959R0 Removing weak_equality And strong_equality // 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() // P????R? directory_entry::clear_cache()
// _HAS_CXX20 indirectly controls: // _HAS_CXX20 indirectly controls:
@ -1082,11 +1093,6 @@
#if defined(__cpp_concepts) && __cpp_concepts > 201507L #if defined(__cpp_concepts) && __cpp_concepts > 201507L
#define __cpp_lib_concepts 201907L #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 #endif // defined(__cpp_concepts) && __cpp_concepts > 201507L
#define __cpp_lib_constexpr_algorithms 201806L #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 // expensive, and even for relatively cheap to copy function objects we care (somewhat) about debug
// mode perf. // mode perf.
struct Immobile {
Immobile() = default;
Immobile(const Immobile&) = delete;
Immobile& operator=(const Immobile&) = delete;
};
struct MoveOnly { struct MoveOnly {
MoveOnly() = default; MoveOnly() = default;
MoveOnly(const MoveOnly&) = delete; MoveOnly(const MoveOnly&) = delete;
@ -98,14 +104,14 @@ namespace std_testing {
void operator()(const T&) {} void operator()(const T&) {}
}; };
struct Rng : MoveOnly { struct Rng : Immobile {
template <typename Integral> template <typename Integral>
Integral operator()(Integral) { Integral operator()(Integral) {
return 0; return 0;
} }
}; };
struct Urng : MoveOnly { struct Urng : Immobile {
typedef unsigned int result_type; typedef unsigned int result_type;
unsigned int operator()() { unsigned int operator()() {
return 4; // chosen by fair dice roll; guaranteed to be random 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\P0784R7_library_support_for_more_constexpr_containers
tests\P0811R3_midpoint_lerp tests\P0811R3_midpoint_lerp
tests\P0896R4_P1614R2_comparisons 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_iterator_machinery
tests\P0896R4_ranges_range_machinery tests\P0896R4_ranges_range_machinery
tests\P0896R4_ranges_to_address 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>>); static_assert(is_same_v<span<const int, 3>::reverse_iterator, reverse_iterator<span<const int, 3>::iterator>>);
#ifdef __cpp_lib_concepts #ifdef __cpp_lib_concepts
static_assert(ranges::enable_safe_range<span<int>>); static_assert(ranges::enable_borrowed_range<span<int>>);
static_assert(ranges::enable_safe_range<span<int, 3>>); static_assert(ranges::enable_borrowed_range<span<int, 3>>);
#endif // __cpp_lib_concepts #endif // __cpp_lib_concepts
static_assert(is_base_of_v<integral_constant<size_t, 3>, tuple_size<span<int, 3>>>); 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 {}; struct NonRange {};
template <typename T, bool Safe = false> template <typename T, bool Borrowed = false>
struct BasicRange { struct BasicRange {
T elements[3]{}; T elements[3]{};
@ -141,15 +141,15 @@ struct BasicRange {
#ifdef __cpp_lib_concepts #ifdef __cpp_lib_concepts
namespace std::ranges { namespace std::ranges {
template <typename T, bool Safe> template <typename T, bool Borrowed>
inline constexpr bool enable_safe_range<BasicRange<T, Safe>> = Safe; inline constexpr bool enable_borrowed_range<BasicRange<T, Borrowed>> = Borrowed;
} }
#endif // __cpp_lib_concepts #endif // __cpp_lib_concepts
using ContiguousSizedRange = BasicRange<int>; using ContiguousSizedRange = BasicRange<int>;
// Not truly a model of safe_range; this is a convenient fiction for testing purposes. // Not truly a model of borrowed_range; this is a convenient fiction for testing purposes.
using SafeContiguousSizedRange = BasicRange<int, true>; using BorrowedContiguousSizedRange = BasicRange<int, true>;
template <typename T, size_t Extent = dynamic_extent> template <typename T, size_t Extent = dynamic_extent>
constexpr void FunctionTakingSpan(type_identity_t<span<T, Extent>>) {} constexpr void FunctionTakingSpan(type_identity_t<span<T, Extent>>) {}
@ -591,24 +591,24 @@ constexpr bool test() {
#ifdef __cpp_lib_concepts #ifdef __cpp_lib_concepts
static_assert(!is_constructible_v<span<int>, ContiguousSizedRange>); 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_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>>); 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)); 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_5.data() == user_range.data());
assert(sp_4.size() == 3); assert(sp_4.size() == 3);
assert(sp_5.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)); FunctionTakingSpan<const int>(move(user_range));
static_assert(is_same_v<decltype(span{user_range}), span<int>>); 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); void operator*() requires(I == 12);
output_iterator_archetype& operator*() requires(I != 12); output_iterator_archetype& operator*() requires(I != 12);
// writable requirements // indirectly_writable requirements
void operator=(int) requires(I != 13); 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++; using increment_ops<I, input_iterator_archetype<I>, void>::operator++;
// dereference ops from iterator_archetype // dereference ops from iterator_archetype
void operator*() requires(I == 12); void operator*() const requires(I == 12);
int& operator*() requires(I != 12); int& operator*() const requires(I != 12);
}; };
inline constexpr std::size_t input_iterator_archetype_max = 17; 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>()); STATIC_ASSERT(!test_difference<non_integral_difference>());
} // namespace incrementable_traits_test } // namespace incrementable_traits_test
namespace readable_traits_test { namespace indirectly_readable_traits_test {
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4180) // qualifier applied to function type has no meaning; ignored #pragma warning(disable : 4180) // qualifier applied to function type has no meaning; ignored
template <class T, class V = no_such_type> template <class T, class V = no_such_type>
constexpr bool test_value() noexcept { 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>) { if constexpr (same_as<V, no_such_type>) {
STATIC_ASSERT(!has_member_value_type<readable_traits<T>>); STATIC_ASSERT(!has_member_value_type<indirectly_readable_traits<T>>);
STATIC_ASSERT(!has_member_value_type<readable_traits<T const>>); STATIC_ASSERT(!has_member_value_type<indirectly_readable_traits<T const>>);
STATIC_ASSERT(!has_iter_value<readable_traits<T>>); STATIC_ASSERT(!has_iter_value<indirectly_readable_traits<T>>);
STATIC_ASSERT(!has_iter_value<readable_traits<T const>>); STATIC_ASSERT(!has_iter_value<indirectly_readable_traits<T const>>);
return false; return false;
} else { } else {
STATIC_ASSERT(same_as<typename readable_traits<T>::value_type, V>); STATIC_ASSERT(same_as<typename indirectly_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 const>::value_type, V>);
STATIC_ASSERT(same_as<iter_value_t<T>, V>); STATIC_ASSERT(same_as<iter_value_t<T>, V>);
STATIC_ASSERT(same_as<iter_value_t<T const>, V>); STATIC_ASSERT(same_as<iter_value_t<T const>, V>);
return true; return true;
@ -552,10 +552,10 @@ namespace readable_traits_test {
STATIC_ASSERT(test_value<with_element_type<int const>, int>()); STATIC_ASSERT(test_value<with_element_type<int const>, int>());
STATIC_ASSERT(test_value<my_iterator, char>()); STATIC_ASSERT(test_value<my_iterator, char>());
} // namespace readable_traits_test } // namespace indirectly_readable_traits_test
namespace iterator_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::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::forward_iterator_tag, std::bidirectional_iterator_tag, std::random_access_iterator_tag,
std::contiguous_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>); STATIC_ASSERT(same_as<typename iterator_traits<T>::value_type, Value>);
if constexpr (!same_as<Value, void>) { if constexpr (!same_as<Value, void>) {
STATIC_ASSERT(same_as<iter_value_t<T>, Value>); 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>); STATIC_ASSERT(same_as<typename iterator_traits<T>::difference_type, Difference>);
if constexpr (!same_as<Difference, void>) { if constexpr (!same_as<Difference, void>) {
@ -804,7 +804,7 @@ namespace iterator_traits_test {
} // namespace iterator_traits_test } // namespace iterator_traits_test
template <class Base> 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; using value_type = double;
}; };
@ -983,8 +983,8 @@ namespace iterator_cust_move_test {
} // namespace iterator_cust_move_test } // namespace iterator_cust_move_test
namespace iterator_cust_swap_test { namespace iterator_cust_swap_test {
using std::indirectly_movable_storable, std::iter_reference_t, std::readable, std::remove_reference_t, std::same_as, using std::indirectly_movable_storable, std::iter_reference_t, std::indirectly_readable, std::remove_reference_t,
std::swappable_with; std::same_as, std::swappable_with;
template <class T, class U> template <class T, class U>
concept can_iter_swap = requires(T&& t, U&& 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(bullet1<E1>);
STATIC_ASSERT((ranges::iter_swap(E1::x, E1::x), true)); 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 // N4849 [iterator.cust.swap]/4.2: "Otherwise if the types of E1 and E2 each model indirectly_readable, and if the
// types of E1 and E2 model swappable_with, then ranges::swap(*E1, *E2)." // reference types of E1 and E2 model swappable_with, then ranges::swap(*E1, *E2)."
// clang-format off // clang-format off
template <class T, class U = T> template <class T, class U = T>
concept bullet2 = !bullet1<T, U> && readable<remove_reference_t<T>> && readable<remove_reference_t<U>> concept bullet2 = !bullet1<T, U> && indirectly_readable<remove_reference_t<T>>
&& swappable_with<iter_reference_t<T>, iter_reference_t<U>>; && indirectly_readable<remove_reference_t<U>> && swappable_with<iter_reference_t<T>, iter_reference_t<U>>;
// clang-format on // clang-format on
constexpr bool test() { constexpr bool test() {
@ -1153,64 +1153,64 @@ namespace iterator_cust_swap_test {
} // namespace iterator_cust_swap_test } // namespace iterator_cust_swap_test
namespace iterator_concept_readable_test { namespace iterator_concept_readable_test {
using std::readable; using std::indirectly_readable;
STATIC_ASSERT(!readable<void>); STATIC_ASSERT(!indirectly_readable<void>);
STATIC_ASSERT(!readable<void*>); STATIC_ASSERT(!indirectly_readable<void*>);
STATIC_ASSERT(readable<int*>); STATIC_ASSERT(indirectly_readable<int*>);
STATIC_ASSERT(readable<int const*>); STATIC_ASSERT(indirectly_readable<int const*>);
STATIC_ASSERT(!readable<int const empty_type::*>); STATIC_ASSERT(!indirectly_readable<int const empty_type::*>);
STATIC_ASSERT(!readable<dereferences_to<void>>); STATIC_ASSERT(!indirectly_readable<dereferences_to<void>>);
STATIC_ASSERT(readable<dereferences_to<int>>); STATIC_ASSERT(indirectly_readable<dereferences_to<int>>);
STATIC_ASSERT(readable<dereferences_to<int&>>); STATIC_ASSERT(indirectly_readable<dereferences_to<int&>>);
STATIC_ASSERT(readable<dereferences_to<int const&>>); STATIC_ASSERT(indirectly_readable<dereferences_to<int const&>>);
STATIC_ASSERT(readable<dereferences_to<move_only>>); STATIC_ASSERT(indirectly_readable<dereferences_to<move_only>>);
STATIC_ASSERT(readable<dereferences_to<int (&)[42]>>); STATIC_ASSERT(indirectly_readable<dereferences_to<int (&)[42]>>);
STATIC_ASSERT(!readable<dereferences_to<int (&)()>>); STATIC_ASSERT(!indirectly_readable<dereferences_to<int (&)()>>);
STATIC_ASSERT(!readable<int (empty_type::*)()>); STATIC_ASSERT(!indirectly_readable<int (empty_type::*)()>);
struct no_value_type { struct no_value_type {
int operator*() const; int operator*() const;
}; };
STATIC_ASSERT(!readable<no_value_type>); STATIC_ASSERT(!indirectly_readable<no_value_type>);
struct not_dereferenceable { struct not_dereferenceable {
using value_type = int; using value_type = int;
}; };
STATIC_ASSERT(!readable<no_value_type>); STATIC_ASSERT(!indirectly_readable<no_value_type>);
struct simple_abstract { struct simple_abstract {
virtual void f() = 0; 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_readable_test
namespace iterator_concept_writable_test { namespace iterator_concept_writable_test {
using std::writable; using std::indirectly_writable;
template <class I, class T> template <class I, class T>
constexpr bool test_writable() { constexpr bool test_writable() {
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4180) // qualifier applied to function type has no meaning; ignored #pragma warning(disable : 4180) // qualifier applied to function type has no meaning; ignored
constexpr bool result = writable<I, T>; constexpr bool result = indirectly_writable<I, T>;
STATIC_ASSERT(writable<I, T const> == result); STATIC_ASSERT(indirectly_writable<I, T const> == result);
STATIC_ASSERT(writable<I, T volatile> == result); STATIC_ASSERT(indirectly_writable<I, T volatile> == result);
STATIC_ASSERT(writable<I, T const volatile> == result); STATIC_ASSERT(indirectly_writable<I, T const volatile> == result);
if constexpr (can_reference<T>) { if constexpr (can_reference<T>) {
STATIC_ASSERT(writable<I, T&> == result); STATIC_ASSERT(indirectly_writable<I, T&> == result);
STATIC_ASSERT(writable<I, T const&> == result); STATIC_ASSERT(indirectly_writable<I, T const&> == result);
STATIC_ASSERT(writable<I, T volatile&> == result); STATIC_ASSERT(indirectly_writable<I, T volatile&> == result);
STATIC_ASSERT(writable<I, T const volatile&> == result); STATIC_ASSERT(indirectly_writable<I, T const volatile&> == result);
} }
#pragma warning(pop) #pragma warning(pop)
return result; return result;
} }
STATIC_ASSERT(!writable<void, int>); STATIC_ASSERT(!indirectly_writable<void, int>);
STATIC_ASSERT(!writable<void*, void>); STATIC_ASSERT(!indirectly_writable<void*, void>);
STATIC_ASSERT(!test_writable<int*, void>()); STATIC_ASSERT(!test_writable<int*, void>());
STATIC_ASSERT(test_writable<int*, int>()); 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(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&>()); 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 struct std_string {}; // slightly simplified
STATIC_ASSERT(!test_writable<dereferences_to<std_string>, std_string>()); 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_crbegin<int[]>());
STATIC_ASSERT(test_crend<int[]>()); STATIC_ASSERT(test_crend<int[]>());
STATIC_ASSERT(test_size<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_data<int[]>());
STATIC_ASSERT(test_cdata<int[]>()); STATIC_ASSERT(test_cdata<int[]>());
STATIC_ASSERT(!ranges::range<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_crbegin<int const[]>());
STATIC_ASSERT(test_crend<int const[]>()); STATIC_ASSERT(test_crend<int const[]>());
STATIC_ASSERT(test_size<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_data<int const[]>());
STATIC_ASSERT(test_cdata<int const[]>()); STATIC_ASSERT(test_cdata<int const[]>());
STATIC_ASSERT(!ranges::range<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_crbegin<int (&)[]>());
STATIC_ASSERT(test_crend<int (&)[]>()); STATIC_ASSERT(test_crend<int (&)[]>());
STATIC_ASSERT(test_size<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 // 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::data(std::declval<int (&)[]>())), int*>);
STATIC_ASSERT(std::same_as<decltype(ranges::cdata(std::declval<int (&)[]>())), int const*>); 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_crbegin<int const (&)[]>());
STATIC_ASSERT(test_crend<int const (&)[]>()); STATIC_ASSERT(test_crend<int const (&)[]>());
STATIC_ASSERT(test_size<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 // 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::data(std::declval<int const (&)[]>())), int const*>);
STATIC_ASSERT(std::same_as<decltype(ranges::cdata(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(!CanCRBegin<decltype((initially_unbounded))>);
STATIC_ASSERT(!CanCREnd<decltype((initially_unbounded))>); STATIC_ASSERT(!CanCREnd<decltype((initially_unbounded))>);
STATIC_ASSERT(!CanSize<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::data(initially_unbounded) == initially_unbounded);
STATIC_ASSERT(ranges::cdata(initially_unbounded) == initially_unbounded); STATIC_ASSERT(ranges::cdata(initially_unbounded) == initially_unbounded);
int initially_unbounded[42]; int initially_unbounded[42];
@ -1414,8 +1414,8 @@ namespace nothrow_testing {
} // namespace nothrow_testing } // namespace nothrow_testing
namespace subsumption_testing { namespace subsumption_testing {
// Validate that the "readable" range concepts properly subsume (doubly important given that we spell them // Validate that the "indirectly_readable" range concepts properly subsume (doubly important given that we spell
// differently than does the working draft) // them differently than does the working draft)
enum range_type { enum range_type {
exactly_range, exactly_range,
exactly_input_range, exactly_input_range,
@ -1465,51 +1465,53 @@ namespace subsumption_testing {
STATIC_ASSERT(f<int (&)[42]>() == exactly_contiguous_range); STATIC_ASSERT(f<int (&)[42]>() == exactly_contiguous_range);
} // namespace subsumption_testing } // 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>, template <class Rng, class Iterator, class Sentinel = Iterator, class RIterator = std::reverse_iterator<Iterator>,
class RSentinel = RIterator> class RSentinel = RIterator>
constexpr bool test_safe_range() { constexpr bool test_borrowed_range() {
// Validate that rvalue/lvalue const/non-const Rng models safe_range // Validate that rvalue/lvalue const/non-const Rng models borrowed_range
STATIC_ASSERT(Decayed<Rng>); STATIC_ASSERT(Decayed<Rng>);
STATIC_ASSERT(test_begin<Rng, Iterator>()); STATIC_ASSERT(test_begin<Rng, Iterator>());
STATIC_ASSERT(test_end<Rng, Sentinel>()); STATIC_ASSERT(test_end<Rng, Sentinel>());
STATIC_ASSERT(test_rbegin<Rng, RIterator>()); STATIC_ASSERT(test_rbegin<Rng, RIterator>());
STATIC_ASSERT(test_rend<Rng, RSentinel>()); 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_begin<Rng&, Iterator>());
STATIC_ASSERT(test_end<Rng&, Sentinel>()); STATIC_ASSERT(test_end<Rng&, Sentinel>());
STATIC_ASSERT(test_rbegin<Rng&, RIterator>()); STATIC_ASSERT(test_rbegin<Rng&, RIterator>());
STATIC_ASSERT(test_rend<Rng&, RSentinel>()); 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_begin<Rng const, Iterator>());
STATIC_ASSERT(test_end<Rng const, Sentinel>()); STATIC_ASSERT(test_end<Rng const, Sentinel>());
STATIC_ASSERT(test_rbegin<Rng const, RIterator>()); STATIC_ASSERT(test_rbegin<Rng const, RIterator>());
STATIC_ASSERT(test_rend<Rng const, RSentinel>()); 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_begin<Rng const&, Iterator>());
STATIC_ASSERT(test_end<Rng const&, Sentinel>()); STATIC_ASSERT(test_end<Rng const&, Sentinel>());
STATIC_ASSERT(test_rbegin<Rng const&, RIterator>()); STATIC_ASSERT(test_rbegin<Rng const&, RIterator>());
STATIC_ASSERT(test_rend<Rng const&, RSentinel>()); STATIC_ASSERT(test_rend<Rng const&, RSentinel>());
STATIC_ASSERT(ranges::safe_range<Rng const&>); STATIC_ASSERT(ranges::borrowed_range<Rng const&>);
return true; return true;
} }
STATIC_ASSERT(test_safe_range<std::string_view, std::string_view::iterator>()); STATIC_ASSERT(test_borrowed_range<std::string_view, std::string_view::iterator>());
STATIC_ASSERT(test_safe_range<std::wstring_view, std::wstring_view::iterator>()); STATIC_ASSERT(test_borrowed_range<std::wstring_view, std::wstring_view::iterator>());
STATIC_ASSERT(test_safe_range<std::span<int>, std::span<int>::iterator>()); STATIC_ASSERT(test_borrowed_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::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 #if 0 // TRANSITION, future
STATIC_ASSERT(test_safe_range<ranges::subrange<int*, int*>, int*>()); STATIC_ASSERT(test_borrowed_range<ranges::ref_view<int[42]>, int*>());
STATIC_ASSERT(test_safe_range<ranges::ref_view<int[42]>, int*>()); STATIC_ASSERT(test_borrowed_range<ranges::iota_view<int, int>, ...>());
STATIC_ASSERT(test_safe_range<ranges::iota_view<int, int>, ...>());
#endif // TRANSITION, future #endif // TRANSITION, future
struct simple_safe_range { struct simple_borrowed_range {
int* begin() const { int* begin() const {
return nullptr; return nullptr;
} }
@ -1518,25 +1520,25 @@ namespace safe_range_testing {
} }
}; };
struct less_simple_safe_range { struct less_simple_borrowed_range {
friend int* begin(less_simple_safe_range) { friend int* begin(less_simple_borrowed_range) {
return nullptr; return nullptr;
} }
friend int* end(less_simple_safe_range) { friend int* end(less_simple_borrowed_range) {
return nullptr; return nullptr;
} }
}; };
} // namespace safe_range_testing } // namespace borrowed_range_testing
template <> 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 <> 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 { namespace borrowed_range_testing {
STATIC_ASSERT(test_safe_range<simple_safe_range, int*>()); STATIC_ASSERT(test_borrowed_range<simple_borrowed_range, int*>());
STATIC_ASSERT(test_safe_range<less_simple_safe_range, int*>()); STATIC_ASSERT(test_borrowed_range<less_simple_borrowed_range, int*>());
} // namespace safe_range_testing } // namespace borrowed_range_testing
template <bool AllowNonConst, bool AllowConst, bool AllowSize> template <bool AllowNonConst, bool AllowConst, bool AllowSize>
struct arbitrary_range { struct arbitrary_range {

Просмотреть файл

@ -2357,117 +2357,51 @@ namespace test_object_concepts {
STATIC_ASSERT(test_regular<RegularType>()); STATIC_ASSERT(test_regular<RegularType>());
} // namespace test_object_concepts } // namespace test_object_concepts
namespace test_boolean { namespace test_boolean_testable {
using std::boolean; // 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. // Better have these four, since we use them as examples in the Standard.
STATIC_ASSERT(boolean<bool>); STATIC_ASSERT(_Boolean_testable<bool>);
STATIC_ASSERT(boolean<std::true_type>); STATIC_ASSERT(_Boolean_testable<std::true_type>);
STATIC_ASSERT(boolean<std::bitset<42>::reference>); 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_testable<int>);
STATIC_ASSERT(!boolean<void*>); STATIC_ASSERT(_Boolean_testable<void*>);
enum unscoped_boolish : bool { No, Yes }; enum unscoped_boolish : bool { No, Yes };
STATIC_ASSERT(boolean<unscoped_boolish>); STATIC_ASSERT(_Boolean_testable<unscoped_boolish>);
enum class scoped_boolish : bool { No, Yes }; 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_testable<ImplicitTo<bool>>);
STATIC_ASSERT(!boolean<ExplicitTo<bool>>); STATIC_ASSERT(!_Boolean_testable<ExplicitTo<bool>>);
struct MutatingBoolConversion { struct MutatingBoolConversion {
operator bool(); 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 template <unsigned Select> // values in [0, Archetype_max) select a requirement to violate
struct Archetype { struct Archetype {
// clang-format off // clang-format off
operator bool() const requires (Select != 0); // Archetype<0> is not implicitly convertible to bool 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) 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 // clang-format on
}; };
void operator&&(Archetype<3>, Archetype<3>) {} // Archetype<3> && Archetype<3> is not same_as<bool> STATIC_ASSERT(!_Boolean_testable<Archetype<0>>);
void operator&&(Archetype<4>, bool) {} // Archetype<3> && bool is not same_as<bool> STATIC_ASSERT(!_Boolean_testable<Archetype<1>>);
void operator&&(bool, Archetype<5>) {} // bool && Archetype<5> is not same_as<bool> STATIC_ASSERT(!_Boolean_testable<Archetype<2>>);
void operator||(Archetype<6>, Archetype<6>) {} // Archetype<6> || Archetype<6> is not same_as<bool> STATIC_ASSERT(_Boolean_testable<Archetype<3>>);
void operator||(Archetype<7>, bool) {} // Archetype<7> || bool is not same_as<bool> } // namespace test_boolean_testable
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
namespace test_equality_comparable { namespace test_equality_comparable {
using std::equality_comparable; using std::equality_comparable;
@ -2503,11 +2437,11 @@ namespace test_equality_comparable {
template <unsigned Select> template <unsigned Select>
bool operator==(Archetype<Select> const&, Archetype<Select> const&); 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> template <unsigned Select>
bool operator!=(Archetype<Select> const&, Archetype<Select> const&); 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<0>>());
STATIC_ASSERT(!test<Archetype<1>>()); STATIC_ASSERT(!test<Archetype<1>>());
@ -3101,17 +3035,17 @@ namespace test_predicate {
using RPF3 = bool const& (*&) (int, int, int); using RPF3 = bool const& (*&) (int, int, int);
using RPF4 = bool (*&)(int, ...); using RPF4 = bool (*&)(int, ...);
STATIC_ASSERT(predicate<RF0>); STATIC_ASSERT(predicate<RF0>);
STATIC_ASSERT(!predicate<RF1, int>); STATIC_ASSERT(predicate<RF1, int>);
STATIC_ASSERT(predicate<RF2, int, long>); STATIC_ASSERT(predicate<RF2, int, long>);
STATIC_ASSERT(predicate<RF3, int, long, int>); STATIC_ASSERT(predicate<RF3, int, long, int>);
STATIC_ASSERT(predicate<RF4, int, float, void*>); STATIC_ASSERT(predicate<RF4, int, float, void*>);
STATIC_ASSERT(predicate<PF0>); STATIC_ASSERT(predicate<PF0>);
STATIC_ASSERT(!predicate<PF1, int>); STATIC_ASSERT(predicate<PF1, int>);
STATIC_ASSERT(predicate<PF2, int, long>); STATIC_ASSERT(predicate<PF2, int, long>);
STATIC_ASSERT(predicate<PF3, int, long, int>); STATIC_ASSERT(predicate<PF3, int, long, int>);
STATIC_ASSERT(predicate<PF4, int, float, void*>); STATIC_ASSERT(predicate<PF4, int, float, void*>);
STATIC_ASSERT(predicate<RPF0>); STATIC_ASSERT(predicate<RPF0>);
STATIC_ASSERT(!predicate<RPF1, int>); STATIC_ASSERT(predicate<RPF1, int>);
STATIC_ASSERT(predicate<RPF2, int, long>); STATIC_ASSERT(predicate<RPF2, int, long>);
STATIC_ASSERT(predicate<RPF3, int, long, int>); STATIC_ASSERT(predicate<RPF3, int, long, int>);
STATIC_ASSERT(predicate<RPF4, int, float, void*>); STATIC_ASSERT(predicate<RPF4, int, float, void*>);
@ -3351,14 +3285,16 @@ namespace test_predicate {
} // namespace test_predicate } // namespace test_predicate
namespace test_relation { 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> template <class F, class T, class U = T>
constexpr bool test() { constexpr bool test() {
constexpr bool result = relation<F, T, U>; constexpr bool result = relation<F, T, U>;
STATIC_ASSERT(relation<F, U, T> == result); 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, T, U> == result);
STATIC_ASSERT(strict_weak_order<F, U, T> == result); STATIC_ASSERT(strict_weak_order<F, U, T> == result);
return result; return result;
@ -3394,7 +3330,7 @@ namespace test_relation {
template <unsigned> template <unsigned>
struct B {}; 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> template <unsigned U>
bool operator==(B<U>, B<U>); bool operator==(B<U>, B<U>);
STATIC_ASSERT(test<Equivalent, B<0>>()); STATIC_ASSERT(test<Equivalent, B<0>>());