forked from OSchip/llvm-project
[libc++][ranges] implement `std::ranges::unique{_copy}`
implement `std::ranges::unique` and `std::ranges::unique_copy` Differential Revision: https://reviews.llvm.org/D130404
This commit is contained in:
parent
bf3714884a
commit
72f57e3a30
|
@ -57,7 +57,7 @@ Write,swap_ranges,Nikolas Klauser,`D116303 <https://llvm.org/D116303>`_,✅
|
|||
Write,reverse_copy,Nikolas Klauser,`D127211 <https://llvm.org/D127211>`_,✅
|
||||
Write,rotate_copy,Nikolas Klauser,`D127211 <https://llvm.org/D127211>`_,✅
|
||||
Write,sample,Not assigned,n/a,Not started
|
||||
Write,unique_copy,Not assigned,n/a,Not started
|
||||
Write,unique_copy,Hui Xie,`D130404 <https://llvm.org/D130404>`,✅
|
||||
Write,partition_copy,Konstantin Varlamov,`D130070 <https://llvm.org/D130070>`_,✅
|
||||
Write,partial_sort_copy,Konstantin Varlamov,n/a,In progress
|
||||
Merge,merge,Hui Xie,`D128611 <https://llvm.org/D128611>`_,✅
|
||||
|
@ -70,7 +70,7 @@ Permutation,remove_if,Nikolas Klauser,`D128618 <https://llvm.org/D128618>`_,✅
|
|||
Permutation,reverse,Nikolas Klauser,`D125752 <https://llvm.org/D125752>`_,✅
|
||||
Permutation,rotate,Nikolas Klauser,`D124122 <https://llvm.org/D124122>`_,Under review
|
||||
Permutation,shuffle,Konstantin Varlamov,`D130321 <https://llvm.org/D130321>`_,✅
|
||||
Permutation,unique,Not assigned,n/a,Not started
|
||||
Permutation,unique,Hui Xie,`D130404 <https://llvm.org/D130404>`,✅
|
||||
Permutation,partition,Konstantin Varlamov,`D129624 <https://llvm.org/D129624>`_,✅
|
||||
Permutation,stable_partition,Konstantin Varlamov,`D129624 <https://llvm.org/D129624>`_,✅
|
||||
Permutation,sort,Konstantin Varlamov,`D127557 <https://llvm.org/D127557>`_,✅
|
||||
|
|
|
|
@ -11,8 +11,10 @@
|
|||
#define _LIBCPP___ALGORITHM_ADJACENT_FIND_H
|
||||
|
||||
#include <__algorithm/comp.h>
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__config>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__utility/move.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
|
@ -20,25 +22,31 @@
|
|||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _ForwardIterator, class _BinaryPredicate>
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
adjacent_find(_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred) {
|
||||
if (__first != __last) {
|
||||
_ForwardIterator __i = __first;
|
||||
while (++__i != __last) {
|
||||
if (__pred(*__first, *__i))
|
||||
return __first;
|
||||
__first = __i;
|
||||
}
|
||||
template <class _Iter, class _Sent, class _BinaryPredicate>
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _Iter
|
||||
__adjacent_find(_Iter __first, _Sent __last, _BinaryPredicate&& __pred) {
|
||||
if (__first == __last)
|
||||
return __first;
|
||||
_Iter __i = __first;
|
||||
while (++__i != __last) {
|
||||
if (__pred(*__first, *__i))
|
||||
return __first;
|
||||
__first = __i;
|
||||
}
|
||||
return __last;
|
||||
return __i;
|
||||
}
|
||||
|
||||
template <class _ForwardIterator, class _BinaryPredicate>
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
adjacent_find(_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred) {
|
||||
return std::__adjacent_find(std::move(__first), std::move(__last), __pred);
|
||||
}
|
||||
|
||||
template <class _ForwardIterator>
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
adjacent_find(_ForwardIterator __first, _ForwardIterator __last) {
|
||||
typedef typename iterator_traits<_ForwardIterator>::value_type __v;
|
||||
return _VSTD::adjacent_find(__first, __last, __equal_to<__v>());
|
||||
return std::adjacent_find(std::move(__first), std::move(__last), __equal_to<__v>());
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <__iterator/iter_swap.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/next.h>
|
||||
#include <__iterator/readable_traits.h>
|
||||
#include <__utility/declval.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
|
@ -35,6 +36,10 @@ struct _RangeAlgPolicy {};
|
|||
|
||||
template <>
|
||||
struct _IterOps<_RangeAlgPolicy> {
|
||||
|
||||
template <class _Iter>
|
||||
using __value_type = iter_value_t<_Iter>;
|
||||
|
||||
static constexpr auto advance = ranges::advance;
|
||||
static constexpr auto distance = ranges::distance;
|
||||
static constexpr auto __iter_move = ranges::iter_move;
|
||||
|
@ -50,6 +55,9 @@ struct _ClassicAlgPolicy {};
|
|||
template <>
|
||||
struct _IterOps<_ClassicAlgPolicy> {
|
||||
|
||||
template <class _Iter>
|
||||
using __value_type = typename iterator_traits<_Iter>::value_type;
|
||||
|
||||
// advance
|
||||
template <class _Iter, class _Distance>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef _LIBCPP___ALGORITHM_RANGES_UNIQUE_H
|
||||
#define _LIBCPP___ALGORITHM_RANGES_UNIQUE_H
|
||||
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__algorithm/make_projected.h>
|
||||
#include <__algorithm/unique.h>
|
||||
#include <__config>
|
||||
|
@ -37,28 +38,31 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
|||
namespace ranges {
|
||||
namespace __unique {
|
||||
|
||||
struct __fn {
|
||||
struct __fn {
|
||||
template <
|
||||
permutable _Iter,
|
||||
sentinel_for<_Iter> _Sent,
|
||||
class _Proj = identity,
|
||||
indirect_equivalence_relation<projected<_Iter, _Proj>> _Comp = ranges::equal_to>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter>
|
||||
operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||
auto __ret = std::__unique<_RangeAlgPolicy>(
|
||||
std::move(__first), std::move(__last), ranges::__make_projected_comp(__comp, __proj));
|
||||
return {std::move(__ret.first), std::move(__ret.second)};
|
||||
}
|
||||
|
||||
template <permutable _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
|
||||
indirect_equivalence_relation<projected<_Iter, _Proj>> _Comp = ranges::equal_to>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
subrange<_Iter> operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__first; (void)__last; (void)__comp; (void)__proj;
|
||||
return {};
|
||||
}
|
||||
|
||||
template <forward_range _Range, class _Proj = identity,
|
||||
indirect_equivalence_relation<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::equal_to>
|
||||
requires permutable<iterator_t<_Range>>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
borrowed_subrange_t<_Range> operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__range; (void)__comp; (void)__proj;
|
||||
return {};
|
||||
}
|
||||
|
||||
};
|
||||
template <
|
||||
forward_range _Range,
|
||||
class _Proj = identity,
|
||||
indirect_equivalence_relation<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::equal_to>
|
||||
requires permutable<iterator_t<_Range>>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range>
|
||||
operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||
auto __ret = std::__unique<_RangeAlgPolicy>(
|
||||
ranges::begin(__range), ranges::end(__range), ranges::__make_projected_comp(__comp, __proj));
|
||||
return {std::move(__ret.first), std::move(__ret.second)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace __unique
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define _LIBCPP___ALGORITHM_RANGES_UNIQUE_COPY_H
|
||||
|
||||
#include <__algorithm/in_out_result.h>
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__algorithm/make_projected.h>
|
||||
#include <__algorithm/unique_copy.h>
|
||||
#include <__concepts/same_as.h>
|
||||
|
@ -19,8 +20,8 @@
|
|||
#include <__functional/ranges_operations.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/readable_traits.h>
|
||||
#include <__iterator/projected.h>
|
||||
#include <__iterator/readable_traits.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/dangling.h>
|
||||
|
@ -42,42 +43,68 @@ using unique_copy_result = in_out_result<_InIter, _OutIter>;
|
|||
|
||||
namespace __unique_copy {
|
||||
|
||||
template <class _InIter, class _OutIter>
|
||||
concept __can_reread_from_output = (input_iterator<_OutIter> && same_as<iter_value_t<_InIter>, iter_value_t<_OutIter>>);
|
||||
|
||||
struct __fn {
|
||||
template <class _InIter, class _OutIter>
|
||||
static consteval auto __get_algo_tag() {
|
||||
if constexpr (forward_iterator<_InIter>) {
|
||||
return __unique_copy_tags::__reread_from_input_tag{};
|
||||
} else if constexpr (__can_reread_from_output<_InIter, _OutIter>) {
|
||||
return __unique_copy_tags::__reread_from_output_tag{};
|
||||
} else if constexpr (indirectly_copyable_storable<_InIter, _OutIter>) {
|
||||
return __unique_copy_tags::__read_from_tmp_value_tag{};
|
||||
}
|
||||
}
|
||||
|
||||
template <input_iterator _InIter, sentinel_for<_InIter> _Sent, weakly_incrementable _OutIter, class _Proj = identity,
|
||||
template <class _InIter, class _OutIter>
|
||||
using __algo_tag_t = decltype(__get_algo_tag<_InIter, _OutIter>());
|
||||
|
||||
template <input_iterator _InIter,
|
||||
sentinel_for<_InIter> _Sent,
|
||||
weakly_incrementable _OutIter,
|
||||
class _Proj = identity,
|
||||
indirect_equivalence_relation<projected<_InIter, _Proj>> _Comp = ranges::equal_to>
|
||||
requires indirectly_copyable<_InIter, _OutIter> &&
|
||||
(forward_iterator<_InIter> ||
|
||||
(input_iterator<_OutIter> && same_as<iter_value_t<_InIter>, iter_value_t<_OutIter>>) ||
|
||||
indirectly_copyable_storable<_InIter, _OutIter>)
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
unique_copy_result<_InIter, _OutIter>
|
||||
requires indirectly_copyable<_InIter, _OutIter> &&
|
||||
(forward_iterator<_InIter> ||
|
||||
(input_iterator<_OutIter> && same_as<iter_value_t<_InIter>, iter_value_t<_OutIter>>) ||
|
||||
indirectly_copyable_storable<_InIter, _OutIter>)
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr unique_copy_result<_InIter, _OutIter>
|
||||
operator()(_InIter __first, _Sent __last, _OutIter __result, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__first; (void)__last; (void)__result; (void)__comp; (void)__proj;
|
||||
return {};
|
||||
auto __ret = std::__unique_copy<_RangeAlgPolicy>(
|
||||
std::move(__first),
|
||||
std::move(__last),
|
||||
std::move(__result),
|
||||
__make_projected_comp(__comp, __proj),
|
||||
__algo_tag_t<_InIter, _OutIter>());
|
||||
return {std::move(__ret.first), std::move(__ret.second)};
|
||||
}
|
||||
|
||||
template <input_range _Range, weakly_incrementable _OutIter, class _Proj = identity,
|
||||
template <input_range _Range,
|
||||
weakly_incrementable _OutIter,
|
||||
class _Proj = identity,
|
||||
indirect_equivalence_relation<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::equal_to>
|
||||
requires indirectly_copyable<iterator_t<_Range>, _OutIter> &&
|
||||
(forward_iterator<iterator_t<_Range>> ||
|
||||
(input_iterator<_OutIter> && same_as<range_value_t<_Range>, iter_value_t<_OutIter>>) ||
|
||||
indirectly_copyable_storable<iterator_t<_Range>, _OutIter>)
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
unique_copy_result<borrowed_iterator_t<_Range>, _OutIter>
|
||||
requires indirectly_copyable<iterator_t<_Range>, _OutIter> &&
|
||||
(forward_iterator<iterator_t<_Range>> ||
|
||||
(input_iterator<_OutIter> && same_as<range_value_t<_Range>, iter_value_t<_OutIter>>) ||
|
||||
indirectly_copyable_storable<iterator_t<_Range>, _OutIter>)
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr unique_copy_result<borrowed_iterator_t<_Range>, _OutIter>
|
||||
operator()(_Range&& __range, _OutIter __result, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__range; (void)__result; (void)__comp; (void)__proj;
|
||||
return {};
|
||||
auto __ret = std::__unique_copy<_RangeAlgPolicy>(
|
||||
ranges::begin(__range),
|
||||
ranges::end(__range),
|
||||
std::move(__result),
|
||||
__make_projected_comp(__comp, __proj),
|
||||
__algo_tag_t<iterator_t<_Range>, _OutIter>());
|
||||
return {std::move(__ret.first), std::move(__ret.second)};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace __unique_copy
|
||||
|
||||
inline namespace __cpo {
|
||||
inline constexpr auto unique_copy = __unique_copy::__fn{};
|
||||
inline constexpr auto unique_copy = __unique_copy::__fn{};
|
||||
} // namespace __cpo
|
||||
} // namespace ranges
|
||||
|
||||
|
|
|
@ -11,9 +11,11 @@
|
|||
|
||||
#include <__algorithm/adjacent_find.h>
|
||||
#include <__algorithm/comp.h>
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__config>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__utility/pair.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
|
@ -23,32 +25,34 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
|||
|
||||
// unique
|
||||
|
||||
template <class _AlgPolicy, class _Iter, class _Sent, class _BinaryPredicate>
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 std::pair<_Iter, _Iter>
|
||||
__unique(_Iter __first, _Sent __last, _BinaryPredicate&& __pred) {
|
||||
__first = std::__adjacent_find(__first, __last, __pred);
|
||||
if (__first != __last) {
|
||||
// ... a a ? ...
|
||||
// f i
|
||||
_Iter __i = __first;
|
||||
for (++__i; ++__i != __last;)
|
||||
if (!__pred(*__first, *__i))
|
||||
*++__first = _IterOps<_AlgPolicy>::__iter_move(__i);
|
||||
++__first;
|
||||
return std::pair<_Iter, _Iter>(std::move(__first), std::move(__i));
|
||||
}
|
||||
return std::pair<_Iter, _Iter>(__first, __first);
|
||||
}
|
||||
|
||||
template <class _ForwardIterator, class _BinaryPredicate>
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
unique(_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred)
|
||||
{
|
||||
__first = _VSTD::adjacent_find<_ForwardIterator, _BinaryPredicate&>(__first, __last, __pred);
|
||||
if (__first != __last)
|
||||
{
|
||||
// ... a a ? ...
|
||||
// f i
|
||||
_ForwardIterator __i = __first;
|
||||
for (++__i; ++__i != __last;)
|
||||
if (!__pred(*__first, *__i))
|
||||
*++__first = _VSTD::move(*__i);
|
||||
++__first;
|
||||
}
|
||||
return __first;
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
unique(_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred) {
|
||||
return std::__unique<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __pred).first;
|
||||
}
|
||||
|
||||
template <class _ForwardIterator>
|
||||
_LIBCPP_NODISCARD_EXT inline
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
_ForwardIterator
|
||||
unique(_ForwardIterator __first, _ForwardIterator __last)
|
||||
{
|
||||
typedef typename iterator_traits<_ForwardIterator>::value_type __v;
|
||||
return _VSTD::unique(__first, __last, __equal_to<__v>());
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
unique(_ForwardIterator __first, _ForwardIterator __last) {
|
||||
typedef typename iterator_traits<_ForwardIterator>::value_type __v;
|
||||
return std::unique(__first, __last, __equal_to<__v>());
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
|
|
@ -10,8 +10,14 @@
|
|||
#define _LIBCPP___ALGORITHM_UNIQUE_COPY_H
|
||||
|
||||
#include <__algorithm/comp.h>
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__config>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__type_traits/conditional.h>
|
||||
#include <__type_traits/is_base_of.h>
|
||||
#include <__type_traits/is_same.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__utility/pair.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
|
@ -19,88 +25,99 @@
|
|||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _BinaryPredicate, class _InputIterator, class _OutputIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator
|
||||
__unique_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryPredicate __pred,
|
||||
input_iterator_tag, output_iterator_tag)
|
||||
{
|
||||
if (__first != __last)
|
||||
{
|
||||
typename iterator_traits<_InputIterator>::value_type __t(*__first);
|
||||
namespace __unique_copy_tags {
|
||||
|
||||
struct __reread_from_input_tag {};
|
||||
struct __reread_from_output_tag {};
|
||||
struct __read_from_tmp_value_tag {};
|
||||
|
||||
} // namespace __unique_copy_tags
|
||||
|
||||
template <class _AlgPolicy, class _BinaryPredicate, class _InputIterator, class _Sent, class _OutputIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _OutputIterator>
|
||||
__unique_copy(_InputIterator __first,
|
||||
_Sent __last,
|
||||
_OutputIterator __result,
|
||||
_BinaryPredicate&& __pred,
|
||||
__unique_copy_tags::__read_from_tmp_value_tag) {
|
||||
if (__first != __last) {
|
||||
typename _IterOps<_AlgPolicy>::template __value_type<_InputIterator> __t(*__first);
|
||||
*__result = __t;
|
||||
++__result;
|
||||
while (++__first != __last) {
|
||||
if (!__pred(__t, *__first)) {
|
||||
__t = *__first;
|
||||
*__result = __t;
|
||||
++__result;
|
||||
while (++__first != __last)
|
||||
{
|
||||
if (!__pred(__t, *__first))
|
||||
{
|
||||
__t = *__first;
|
||||
*__result = __t;
|
||||
++__result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return __result;
|
||||
}
|
||||
return pair<_InputIterator, _OutputIterator>(std::move(__first), std::move(__result));
|
||||
}
|
||||
|
||||
template <class _BinaryPredicate, class _ForwardIterator, class _OutputIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator
|
||||
__unique_copy(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result, _BinaryPredicate __pred,
|
||||
forward_iterator_tag, output_iterator_tag)
|
||||
{
|
||||
if (__first != __last)
|
||||
{
|
||||
_ForwardIterator __i = __first;
|
||||
*__result = *__i;
|
||||
++__result;
|
||||
while (++__first != __last)
|
||||
{
|
||||
if (!__pred(*__i, *__first))
|
||||
{
|
||||
*__result = *__first;
|
||||
++__result;
|
||||
__i = __first;
|
||||
}
|
||||
}
|
||||
}
|
||||
return __result;
|
||||
}
|
||||
|
||||
template <class _BinaryPredicate, class _InputIterator, class _ForwardIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
__unique_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result, _BinaryPredicate __pred,
|
||||
input_iterator_tag, forward_iterator_tag)
|
||||
{
|
||||
if (__first != __last)
|
||||
{
|
||||
template <class _AlgPolicy, class _BinaryPredicate, class _ForwardIterator, class _Sent, class _OutputIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI pair<_ForwardIterator, _OutputIterator>
|
||||
__unique_copy(_ForwardIterator __first,
|
||||
_Sent __last,
|
||||
_OutputIterator __result,
|
||||
_BinaryPredicate&& __pred,
|
||||
__unique_copy_tags::__reread_from_input_tag) {
|
||||
if (__first != __last) {
|
||||
_ForwardIterator __i = __first;
|
||||
*__result = *__i;
|
||||
++__result;
|
||||
while (++__first != __last) {
|
||||
if (!__pred(*__i, *__first)) {
|
||||
*__result = *__first;
|
||||
while (++__first != __last)
|
||||
if (!__pred(*__result, *__first))
|
||||
*++__result = *__first;
|
||||
++__result;
|
||||
__i = __first;
|
||||
}
|
||||
}
|
||||
return __result;
|
||||
}
|
||||
return pair<_ForwardIterator, _OutputIterator>(std::move(__first), std::move(__result));
|
||||
}
|
||||
|
||||
template <class _AlgPolicy, class _BinaryPredicate, class _InputIterator, class _Sent, class _InputAndOutputIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _InputAndOutputIterator>
|
||||
__unique_copy(_InputIterator __first,
|
||||
_Sent __last,
|
||||
_InputAndOutputIterator __result,
|
||||
_BinaryPredicate&& __pred,
|
||||
__unique_copy_tags::__reread_from_output_tag) {
|
||||
if (__first != __last) {
|
||||
*__result = *__first;
|
||||
while (++__first != __last)
|
||||
if (!__pred(*__result, *__first))
|
||||
*++__result = *__first;
|
||||
++__result;
|
||||
}
|
||||
return pair<_InputIterator, _InputAndOutputIterator>(std::move(__first), std::move(__result));
|
||||
}
|
||||
|
||||
template <class _InputIterator, class _OutputIterator, class _BinaryPredicate>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
_OutputIterator
|
||||
unique_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryPredicate __pred)
|
||||
{
|
||||
return _VSTD::__unique_copy<_BinaryPredicate&>(__first, __last, __result, __pred,
|
||||
typename iterator_traits<_InputIterator>::iterator_category(),
|
||||
typename iterator_traits<_OutputIterator>::iterator_category());
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator
|
||||
unique_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryPredicate __pred) {
|
||||
using __algo_tag = typename conditional<
|
||||
is_base_of<forward_iterator_tag, typename iterator_traits<_InputIterator>::iterator_category>::value,
|
||||
__unique_copy_tags::__reread_from_input_tag,
|
||||
typename conditional<
|
||||
is_base_of<forward_iterator_tag, typename iterator_traits<_OutputIterator>::iterator_category>::value &&
|
||||
is_same< typename iterator_traits<_InputIterator>::value_type,
|
||||
typename iterator_traits<_OutputIterator>::value_type>::value,
|
||||
__unique_copy_tags::__reread_from_output_tag,
|
||||
__unique_copy_tags::__read_from_tmp_value_tag>::type >::type;
|
||||
return std::__unique_copy<_ClassicAlgPolicy>(
|
||||
std::move(__first), std::move(__last), std::move(__result), __pred, __algo_tag())
|
||||
.second;
|
||||
}
|
||||
|
||||
template <class _InputIterator, class _OutputIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
_OutputIterator
|
||||
unique_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result)
|
||||
{
|
||||
typedef typename iterator_traits<_InputIterator>::value_type __v;
|
||||
return _VSTD::unique_copy(__first, __last, __result, __equal_to<__v>());
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator
|
||||
unique_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
|
||||
typedef typename iterator_traits<_InputIterator>::value_type __v;
|
||||
return std::unique_copy(std::move(__first), std::move(__last), std::move(__result), __equal_to<__v>());
|
||||
}
|
||||
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___ALGORITHM_UNIQUE_COPY_H
|
||||
|
|
|
@ -865,6 +865,34 @@ namespace ranges {
|
|||
borrowed_iterator_t<R>
|
||||
inplace_merge(R&& r, iterator_t<R> middle, Comp comp = {},
|
||||
Proj proj = {}); // Since C++20
|
||||
|
||||
template<permutable I, sentinel_for<I> S, class Proj = identity,
|
||||
indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
|
||||
constexpr subrange<I> unique(I first, S last, C comp = {}, Proj proj = {}); // Since C++20
|
||||
|
||||
template<forward_range R, class Proj = identity,
|
||||
indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
|
||||
requires permutable<iterator_t<R>>
|
||||
constexpr borrowed_subrange_t<R>
|
||||
unique(R&& r, C comp = {}, Proj proj = {}); // Since C++20
|
||||
|
||||
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
|
||||
indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
|
||||
requires indirectly_copyable<I, O> &&
|
||||
(forward_iterator<I> ||
|
||||
(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) ||
|
||||
indirectly_copyable_storable<I, O>)
|
||||
constexpr unique_copy_result<I, O>
|
||||
unique_copy(I first, S last, O result, C comp = {}, Proj proj = {}); // Since C++20
|
||||
|
||||
template<input_range R, weakly_incrementable O, class Proj = identity,
|
||||
indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
|
||||
requires indirectly_copyable<iterator_t<R>, O> &&
|
||||
(forward_iterator<iterator_t<R>> ||
|
||||
(input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) ||
|
||||
indirectly_copyable_storable<iterator_t<R>, O>)
|
||||
constexpr unique_copy_result<borrowed_iterator_t<R>, O>
|
||||
unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); // Since C++20
|
||||
}
|
||||
|
||||
constexpr bool // constexpr in C++20
|
||||
|
@ -1665,6 +1693,8 @@ template <class BidirectionalIterator, class Compare>
|
|||
#include <__algorithm/ranges_stable_sort.h>
|
||||
#include <__algorithm/ranges_swap_ranges.h>
|
||||
#include <__algorithm/ranges_transform.h>
|
||||
#include <__algorithm/ranges_unique.h>
|
||||
#include <__algorithm/ranges_unique_copy.h>
|
||||
#include <__algorithm/ranges_upper_bound.h>
|
||||
#include <__algorithm/remove.h>
|
||||
#include <__algorithm/remove_copy.h>
|
||||
|
|
|
@ -222,10 +222,10 @@ constexpr bool all_the_algorithms()
|
|||
(void)std::ranges::transform(a, first2, UnaryTransform(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::transform(first, mid, mid, last, first2, BinaryTransform(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::transform(a, b, first2, BinaryTransform(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::unique(first, last, Equal(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::unique(a, Equal(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::unique_copy(first, last, first2, Equal(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::unique_copy(a, first2, Equal(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::unique(first, last, Equal(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::unique(a, Equal(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::unique_copy(first, last, first2, Equal(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::unique_copy(a, first2, Equal(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::upper_bound(first, last, value, Less(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::upper_bound(a, value, Less(&copies)); assert(copies == 0);
|
||||
|
||||
|
|
|
@ -213,10 +213,10 @@ constexpr bool all_the_algorithms()
|
|||
(void)std::ranges::transform(a, first2, UnaryTransform(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::transform(first, mid, mid, last, first2, BinaryTransform(), Proj(&copies), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::transform(a, b, first2, BinaryTransform(), Proj(&copies), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::unique(first, last, Equal(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::unique(a, Equal(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::unique_copy(first, last, first2, Equal(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::unique_copy(a, first2, Equal(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::unique(first, last, Equal(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::unique(a, Equal(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::unique_copy(first, last, first2, Equal(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::unique_copy(a, first2, Equal(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::upper_bound(first, last, value, Less(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::upper_bound(a, value, Less(), Proj(&copies)); assert(copies == 0);
|
||||
|
||||
|
|
|
@ -28,14 +28,214 @@
|
|||
#include <ranges>
|
||||
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "counting_predicates.h"
|
||||
#include "counting_projection.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// TODO: SFINAE tests.
|
||||
template <class Iter = int*, class Sent = int*, class Comp = std::ranges::equal_to, class Proj = std::identity>
|
||||
concept HasUniqueIter =
|
||||
requires(Iter&& iter, Sent&& sent, Comp&& comp, Proj&& proj) {
|
||||
std::ranges::unique(
|
||||
std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Comp>(comp), std::forward<Proj>(proj));
|
||||
};
|
||||
|
||||
static_assert(HasUniqueIter<int*, int*>);
|
||||
|
||||
// !permutable<I>
|
||||
static_assert(!HasUniqueIter<PermutableNotForwardIterator>);
|
||||
static_assert(!HasUniqueIter<PermutableNotSwappable>);
|
||||
|
||||
// !sentinel_for<S, I>
|
||||
static_assert(!HasUniqueIter<int*, SentinelForNotSemiregular>);
|
||||
|
||||
// !indirect_equivalence_relation<Comp, projected<I, Proj>>
|
||||
static_assert(!HasUniqueIter<int*, int*, ComparatorNotCopyable<int>>);
|
||||
|
||||
template <class Range, class Comp = std::ranges::equal_to, class Proj = std::identity>
|
||||
concept HasUniqueRange =
|
||||
requires(Range&& range, Comp&& comp, Proj&& proj) {
|
||||
std::ranges::unique(std::forward<Range>(range), std::forward<Comp>(comp), std::forward<Proj>(proj));
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using R = UncheckedRange<T>;
|
||||
|
||||
static_assert(HasUniqueRange<R<int*>>);
|
||||
|
||||
// !forward_range<R>
|
||||
static_assert(!HasUniqueRange<ForwardRangeNotDerivedFrom>);
|
||||
static_assert(!HasUniqueRange<ForwardRangeNotIncrementable>);
|
||||
|
||||
// permutable<ranges::iterator_t<R>>
|
||||
static_assert(!HasUniqueRange<R<PermutableNotForwardIterator>>);
|
||||
static_assert(!HasUniqueRange<R<PermutableNotSwappable>>);
|
||||
|
||||
// !indirect_equivalence_relation<Comp, projected<ranges::iterator_t<R>, Proj>>
|
||||
static_assert(!HasUniqueRange<R<int*>, ComparatorNotCopyable<int>>);
|
||||
|
||||
template <class Iter, template <class> class SentWrapper, std::size_t N1, std::size_t N2>
|
||||
constexpr void testUniqueImpl(std::array<int, N1> input, std::array<int, N2> expected) {
|
||||
using Sent = SentWrapper<Iter>;
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
auto in = input;
|
||||
std::same_as<std::ranges::subrange<Iter>> decltype(auto) result =
|
||||
std::ranges::unique(Iter{in.data()}, Sent{Iter{in.data() + in.size()}});
|
||||
assert(std::ranges::equal(std::ranges::subrange<Iter>{Iter{in.data()}, result.begin()}, expected));
|
||||
assert(base(result.end()) == in.data() + in.size());
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::subrange r{Iter{in.data()}, Sent{Iter{in.data() + in.size()}}};
|
||||
std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::unique(r);
|
||||
assert(std::ranges::equal(std::ranges::subrange<Iter>{Iter{in.data()}, result.begin()}, expected));
|
||||
assert(base(result.end()) == in.data() + in.size());
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iter, template <class> class SentWrapper>
|
||||
constexpr void testImpl() {
|
||||
// no consecutive elements
|
||||
{
|
||||
std::array in{1, 2, 3, 2, 1};
|
||||
std::array expected{1, 2, 3, 2, 1};
|
||||
testUniqueImpl<Iter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
// one group of consecutive elements
|
||||
{
|
||||
std::array in{2, 3, 3, 3, 4, 3};
|
||||
std::array expected{2, 3, 4, 3};
|
||||
testUniqueImpl<Iter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
// multiple groups of consecutive elements
|
||||
{
|
||||
std::array in{2, 3, 3, 3, 4, 3, 3, 5, 5, 5};
|
||||
std::array expected{2, 3, 4, 3, 5};
|
||||
testUniqueImpl<Iter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
// all the same
|
||||
{
|
||||
std::array in{1, 1, 1, 1, 1, 1};
|
||||
std::array expected{1};
|
||||
testUniqueImpl<Iter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
// empty range
|
||||
{
|
||||
std::array<int, 0> in{};
|
||||
std::array<int, 0> expected{};
|
||||
testUniqueImpl<Iter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
// single element range
|
||||
std::array in{1};
|
||||
std::array expected{1};
|
||||
testUniqueImpl<Iter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
template <template <class> class SentWrapper>
|
||||
constexpr void withAllPermutationsOfIter() {
|
||||
testImpl<forward_iterator<int*>, SentWrapper>();
|
||||
testImpl<bidirectional_iterator<int*>, SentWrapper>();
|
||||
testImpl<random_access_iterator<int*>, SentWrapper>();
|
||||
testImpl<contiguous_iterator<int*>, SentWrapper>();
|
||||
testImpl<int*, SentWrapper>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// TODO: main tests.
|
||||
// TODO: A custom comparator works.
|
||||
// TODO: A custom projection works.
|
||||
withAllPermutationsOfIter<std::type_identity_t>();
|
||||
withAllPermutationsOfIter<sentinel_wrapper>();
|
||||
|
||||
struct Data {
|
||||
int data;
|
||||
};
|
||||
|
||||
// Test custom comparator
|
||||
{
|
||||
std::array input{Data{4}, Data{8}, Data{8}, Data{8}};
|
||||
std::array expected{Data{4}, Data{8}};
|
||||
const auto comp = [](const Data& x, const Data& y) { return x.data == y.data; };
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::unique(in.begin(), in.end(), comp);
|
||||
assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end(), comp));
|
||||
assert(base(result.end()) == in.end());
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::unique(in, comp);
|
||||
assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end(), comp));
|
||||
assert(base(result.end()) == in.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Test custom projection
|
||||
{
|
||||
std::array input{Data{4}, Data{8}, Data{8}, Data{8}};
|
||||
std::array expected{Data{4}, Data{8}};
|
||||
|
||||
const auto proj = &Data::data;
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::unique(in.begin(), in.end(), {}, proj);
|
||||
assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end(), {}, proj, proj));
|
||||
assert(base(result.end()) == in.end());
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::unique(in, {}, proj);
|
||||
assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end(), {}, proj, proj));
|
||||
assert(base(result.end()) == in.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Complexity: For nonempty ranges, exactly (last - first) - 1 applications of the corresponding predicate
|
||||
// and no more than twice as many applications of any projection.
|
||||
{
|
||||
std::array input{1, 2, 3, 3, 3, 4, 3, 3, 5, 5, 6, 6, 1};
|
||||
std::array expected{1, 2, 3, 4, 3, 5, 6, 1};
|
||||
// iterator overload
|
||||
{
|
||||
auto in = input;
|
||||
int numberOfComp = 0;
|
||||
int numberOfProj = 0;
|
||||
auto result = std::ranges::unique(
|
||||
in.begin(),
|
||||
in.end(),
|
||||
counting_predicate{std::ranges::equal_to{}, numberOfComp},
|
||||
counting_projection{numberOfProj});
|
||||
assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end()));
|
||||
assert(base(result.end()) == in.end());
|
||||
assert(numberOfComp == in.size() - 1);
|
||||
assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
|
||||
}
|
||||
// range overload
|
||||
{
|
||||
auto in = input;
|
||||
int numberOfComp = 0;
|
||||
int numberOfProj = 0;
|
||||
auto result = std::ranges::unique(
|
||||
in, counting_predicate{std::ranges::equal_to{}, numberOfComp}, counting_projection{numberOfProj});
|
||||
assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end()));
|
||||
assert(base(result.end()) == in.end());
|
||||
assert(numberOfComp == in.size() - 1);
|
||||
assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -36,15 +36,409 @@
|
|||
#include <ranges>
|
||||
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "counting_predicates.h"
|
||||
#include "counting_projection.h"
|
||||
#include "MoveOnly.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// TODO: SFINAE tests.
|
||||
template <
|
||||
class InIter = int*,
|
||||
class Sent = int*,
|
||||
class OutIter = int*,
|
||||
class Comp = std::ranges::equal_to,
|
||||
class Proj = std::identity>
|
||||
concept HasUniqueCopyIter =
|
||||
requires(InIter&& in, Sent&& sent, OutIter&& out, Comp&& comp, Proj&& proj) {
|
||||
std::ranges::unique_copy(
|
||||
std::forward<InIter>(in),
|
||||
std::forward<Sent>(sent),
|
||||
std::forward<OutIter>(out),
|
||||
std::forward<Comp>(comp),
|
||||
std::forward<Proj>(proj));
|
||||
};
|
||||
|
||||
static_assert(HasUniqueCopyIter<int*, int*, int*>);
|
||||
|
||||
// !input_iterator<I>
|
||||
static_assert(!HasUniqueCopyIter<InputIteratorNotDerivedFrom, sentinel_wrapper<InputIteratorNotDerivedFrom>>);
|
||||
|
||||
// !sentinel_for<S, I>
|
||||
static_assert(!HasUniqueCopyIter<int*, SentinelForNotSemiregular>);
|
||||
|
||||
// !weakly_incrementable<O>
|
||||
static_assert(!HasUniqueCopyIter<int*, int*, WeaklyIncrementableNotMovable>);
|
||||
|
||||
// !indirect_equivalence_relation<Comp, projected<I, Proj>>
|
||||
static_assert(!HasUniqueCopyIter<int*, int*, int*, ComparatorNotCopyable<int>>);
|
||||
|
||||
// !indirectly_copyable<I, O>
|
||||
static_assert(!HasUniqueCopyIter<const int*, const int*, const int*>);
|
||||
|
||||
// forward_iterator<I>
|
||||
// !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
|
||||
// !indirectly_copyable_storable<I, O>
|
||||
struct AssignableFromMoveOnly {
|
||||
int data;
|
||||
constexpr AssignableFromMoveOnly& operator=(MoveOnly const& m) {
|
||||
data = m.get();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
static_assert(HasUniqueCopyIter<MoveOnly*, MoveOnly*, AssignableFromMoveOnly*>);
|
||||
// because:
|
||||
static_assert(std::forward_iterator<MoveOnly*>);
|
||||
static_assert(!std::same_as<std::iter_value_t<MoveOnly*>, std::iter_value_t<AssignableFromMoveOnly*>>);
|
||||
static_assert(!std::indirectly_copyable_storable<MoveOnly*, AssignableFromMoveOnly*>);
|
||||
|
||||
// !forward_iterator<I>
|
||||
// (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
|
||||
// !indirectly_copyable_storable<I, O>
|
||||
struct CopyAssignableNotCopyConstructible {
|
||||
int data;
|
||||
constexpr CopyAssignableNotCopyConstructible(int i = 0) : data(i) {}
|
||||
CopyAssignableNotCopyConstructible(const CopyAssignableNotCopyConstructible&) = delete;
|
||||
CopyAssignableNotCopyConstructible& operator=(const CopyAssignableNotCopyConstructible&) = default;
|
||||
friend constexpr bool
|
||||
operator==(CopyAssignableNotCopyConstructible const&, CopyAssignableNotCopyConstructible const&) = default;
|
||||
};
|
||||
|
||||
using InputAndOutputIterator = cpp17_input_iterator<CopyAssignableNotCopyConstructible*>;
|
||||
static_assert(std::input_iterator<InputAndOutputIterator>);
|
||||
static_assert(std::output_iterator<InputAndOutputIterator, CopyAssignableNotCopyConstructible>);
|
||||
|
||||
static_assert(
|
||||
HasUniqueCopyIter<
|
||||
cpp20_input_iterator<CopyAssignableNotCopyConstructible*>,
|
||||
sentinel_wrapper<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>,
|
||||
InputAndOutputIterator>);
|
||||
// because:
|
||||
static_assert(!std::forward_iterator< cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>);
|
||||
static_assert(
|
||||
std::input_iterator<InputAndOutputIterator> &&
|
||||
std::same_as<std::iter_value_t<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>,
|
||||
std::iter_value_t<InputAndOutputIterator>>);
|
||||
static_assert(
|
||||
!std::indirectly_copyable_storable<
|
||||
cpp20_input_iterator<CopyAssignableNotCopyConstructible*>,
|
||||
InputAndOutputIterator>);
|
||||
|
||||
// !forward_iterator<I>
|
||||
// !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
|
||||
// indirectly_copyable_storable<I, O>
|
||||
static_assert(
|
||||
HasUniqueCopyIter<
|
||||
cpp20_input_iterator<int*>,
|
||||
sentinel_wrapper<cpp20_input_iterator<int*>>,
|
||||
cpp20_output_iterator<int*>>);
|
||||
// because:
|
||||
static_assert(!std::forward_iterator<cpp20_input_iterator<int*>>);
|
||||
static_assert(!std::input_iterator<cpp20_output_iterator<int*>>);
|
||||
static_assert(std::indirectly_copyable_storable<cpp20_input_iterator<int*>, cpp20_output_iterator<int*>>);
|
||||
|
||||
// !forward_iterator<I>
|
||||
// !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
|
||||
// !indirectly_copyable_storable<I, O>
|
||||
static_assert(
|
||||
!HasUniqueCopyIter<
|
||||
cpp20_input_iterator<MoveOnly*>,
|
||||
sentinel_wrapper<cpp20_input_iterator<MoveOnly*>>,
|
||||
cpp20_output_iterator<AssignableFromMoveOnly*>>);
|
||||
// because:
|
||||
static_assert(!std::forward_iterator<cpp20_input_iterator<MoveOnly*>>);
|
||||
static_assert(!std::input_iterator<cpp20_output_iterator<MoveOnly*>>);
|
||||
static_assert(
|
||||
!std::
|
||||
indirectly_copyable_storable<cpp20_input_iterator<MoveOnly*>, cpp20_output_iterator<AssignableFromMoveOnly*>>);
|
||||
|
||||
template < class Range, class OutIter = int*, class Comp = std::ranges::equal_to, class Proj = std::identity>
|
||||
concept HasUniqueCopyRange =
|
||||
requires(Range&& range, OutIter&& out, Comp&& comp, Proj&& proj) {
|
||||
std::ranges::unique_copy(
|
||||
std::forward<Range>(range), std::forward<OutIter>(out), std::forward<Comp>(comp), std::forward<Proj>(proj));
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using R = UncheckedRange<T>;
|
||||
|
||||
static_assert(HasUniqueCopyRange<R<int*>, int*>);
|
||||
|
||||
// !input_range<R>
|
||||
static_assert(!HasUniqueCopyRange<R<InputIteratorNotDerivedFrom>>);
|
||||
|
||||
// !weakly_incrementable<O>
|
||||
static_assert(!HasUniqueCopyIter<R<int*>, WeaklyIncrementableNotMovable>);
|
||||
|
||||
// !indirect_equivalence_relation<Comp, projected<I, Proj>>
|
||||
static_assert(!HasUniqueCopyIter<R<int*>, int*, ComparatorNotCopyable<int>>);
|
||||
|
||||
// !indirectly_copyable<I, O>
|
||||
static_assert(!HasUniqueCopyIter<R<const int*>, const int*>);
|
||||
|
||||
// !forward_iterator<iterator_t<R>>
|
||||
// !(input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>)
|
||||
// !indirectly_copyable_storable<iterator_t<R>, O>
|
||||
static_assert(!HasUniqueCopyIter< R<cpp20_input_iterator<MoveOnly*>>, cpp20_output_iterator<AssignableFromMoveOnly*>>);
|
||||
|
||||
template <class InIter, class OutIter, template <class> class SentWrapper, std::size_t N1, std::size_t N2>
|
||||
constexpr void testUniqueCopyImpl(std::array<int, N1> in, std::array<int, N2> expected) {
|
||||
using Sent = SentWrapper<InIter>;
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
std::array<int, N2> out;
|
||||
std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result =
|
||||
std::ranges::unique_copy(InIter{in.data()}, Sent{InIter{in.data() + in.size()}}, OutIter{out.begin()});
|
||||
assert(std::ranges::equal(out, expected));
|
||||
assert(base(result.in) == in.data() + in.size());
|
||||
assert(base(result.out) == out.data() + out.size());
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
std::array<int, N2> out;
|
||||
std::ranges::subrange r{InIter{in.data()}, Sent{InIter{in.data() + in.size()}}};
|
||||
std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result =
|
||||
std::ranges::unique_copy(r, OutIter{out.begin()});
|
||||
assert(std::ranges::equal(out, expected));
|
||||
assert(base(result.in) == in.data() + in.size());
|
||||
assert(base(result.out) == out.data() + out.size());
|
||||
}
|
||||
}
|
||||
|
||||
template <class InIter, class OutIter, template <class> class SentWrapper>
|
||||
constexpr void testImpl() {
|
||||
// no consecutive elements
|
||||
{
|
||||
std::array in{1, 2, 3, 2, 1};
|
||||
std::array expected{1, 2, 3, 2, 1};
|
||||
testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
// one group of consecutive elements
|
||||
{
|
||||
std::array in{2, 3, 3, 3, 4, 3};
|
||||
std::array expected{2, 3, 4, 3};
|
||||
testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
// multiple groups of consecutive elements
|
||||
{
|
||||
std::array in{2, 3, 3, 3, 4, 3, 3, 5, 5, 5};
|
||||
std::array expected{2, 3, 4, 3, 5};
|
||||
testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
// all the same
|
||||
{
|
||||
std::array in{1, 1, 1, 1, 1, 1};
|
||||
std::array expected{1};
|
||||
testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
|
||||
}
|
||||
|
||||
// empty range
|
||||
{
|
||||
std::array<int, 0> in{};
|
||||
std::array<int, 0> expected{};
|
||||
testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
|
||||
}
|
||||
}
|
||||
|
||||
template <class OutIter, template <class> class SentWrapper>
|
||||
constexpr void withAllPermutationsOfInIter() {
|
||||
testImpl<cpp20_input_iterator<int*>, OutIter, sentinel_wrapper>();
|
||||
testImpl<forward_iterator<int*>, OutIter, SentWrapper>();
|
||||
testImpl<bidirectional_iterator<int*>, OutIter, SentWrapper>();
|
||||
testImpl<random_access_iterator<int*>, OutIter, SentWrapper>();
|
||||
testImpl<contiguous_iterator<int*>, OutIter, SentWrapper>();
|
||||
testImpl<int*, OutIter, SentWrapper>();
|
||||
}
|
||||
|
||||
template <template <class> class SentWrapper>
|
||||
constexpr void withAllPermutationsOfInIterAndOutIter() {
|
||||
withAllPermutationsOfInIter<cpp20_output_iterator<int*>, SentWrapper>();
|
||||
withAllPermutationsOfInIter<forward_iterator<int*>, SentWrapper>();
|
||||
withAllPermutationsOfInIter<bidirectional_iterator<int*>, SentWrapper>();
|
||||
withAllPermutationsOfInIter<random_access_iterator<int*>, SentWrapper>();
|
||||
withAllPermutationsOfInIter<contiguous_iterator<int*>, SentWrapper>();
|
||||
withAllPermutationsOfInIter<int*, SentWrapper>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// TODO: main tests.
|
||||
// TODO: A custom comparator works.
|
||||
// TODO: A custom projection works.
|
||||
withAllPermutationsOfInIterAndOutIter<std::type_identity_t>();
|
||||
withAllPermutationsOfInIterAndOutIter<sentinel_wrapper>();
|
||||
|
||||
// Test the overload that re-reads from the input iterator
|
||||
// forward_iterator<I>
|
||||
// !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
|
||||
// !indirectly_copyable_storable<I, O>
|
||||
{
|
||||
MoveOnly in[5] = {1, 3, 3, 3, 1};
|
||||
// iterator overload
|
||||
{
|
||||
AssignableFromMoveOnly out[3] = {};
|
||||
auto result = std::ranges::unique_copy(in, in + 5, out);
|
||||
assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data));
|
||||
assert(result.in == in + 5);
|
||||
assert(result.out == out + 3);
|
||||
}
|
||||
// range overload
|
||||
{
|
||||
AssignableFromMoveOnly out[3] = {};
|
||||
auto result = std::ranges::unique_copy(std::ranges::subrange{in, in + 5}, out);
|
||||
assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data));
|
||||
assert(result.in == in + 5);
|
||||
assert(result.out == out + 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Test the overload that re-reads from the output iterator
|
||||
// !forward_iterator<I>
|
||||
// (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
|
||||
// !indirectly_copyable_storable<I, O>
|
||||
{
|
||||
using InIter = cpp20_input_iterator<CopyAssignableNotCopyConstructible*>;
|
||||
using Sent = sentinel_wrapper<InIter>;
|
||||
CopyAssignableNotCopyConstructible in[6] = {1, 1, 2, 2, 3, 3};
|
||||
// iterator overload
|
||||
{
|
||||
CopyAssignableNotCopyConstructible out[3];
|
||||
auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 6}}, InputAndOutputIterator{out});
|
||||
assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data));
|
||||
assert(base(result.in) == in + 6);
|
||||
assert(base(result.out) == out + 3);
|
||||
}
|
||||
// range overload
|
||||
{
|
||||
CopyAssignableNotCopyConstructible out[3];
|
||||
auto r = std::ranges::subrange(InIter{in}, Sent{InIter{in + 6}});
|
||||
auto result = std::ranges::unique_copy(r, InputAndOutputIterator{out});
|
||||
assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data));
|
||||
assert(base(result.in) == in + 6);
|
||||
assert(base(result.out) == out + 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Test the overload that reads from the temporary copy of the value
|
||||
// !forward_iterator<I>
|
||||
// !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
|
||||
// indirectly_copyable_storable<I, O>
|
||||
{
|
||||
using InIter = cpp20_input_iterator<int*>;
|
||||
using Sent = sentinel_wrapper<InIter>;
|
||||
int in[4] = {1, 1, 1, 2};
|
||||
// iterator overload
|
||||
{
|
||||
int out[2];
|
||||
auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 4}}, cpp20_output_iterator<int*>{out});
|
||||
assert(std::ranges::equal(out, std::array{1, 2}));
|
||||
assert(base(result.in) == in + 4);
|
||||
assert(base(result.out) == out + 2);
|
||||
}
|
||||
// range overload
|
||||
{
|
||||
int out[2];
|
||||
auto r = std::ranges::subrange(InIter{in}, Sent{InIter{in + 4}});
|
||||
auto result = std::ranges::unique_copy(r, cpp20_output_iterator<int*>{out});
|
||||
assert(std::ranges::equal(out, std::array{1, 2}));
|
||||
assert(base(result.in) == in + 4);
|
||||
assert(base(result.out) == out + 2);
|
||||
}
|
||||
}
|
||||
|
||||
struct Data {
|
||||
int data;
|
||||
};
|
||||
|
||||
// Test custom comparator
|
||||
{
|
||||
std::array in{Data{4}, Data{8}, Data{8}, Data{8}};
|
||||
std::array expected{Data{4}, Data{8}};
|
||||
const auto comp = [](const Data& x, const Data& y) { return x.data == y.data; };
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
std::array<Data, 2> out;
|
||||
auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), comp);
|
||||
assert(std::ranges::equal(out, expected, comp));
|
||||
assert(base(result.in) == in.begin() + 4);
|
||||
assert(base(result.out) == out.begin() + 2);
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
std::array<Data, 2> out;
|
||||
auto result = std::ranges::unique_copy(in, out.begin(), comp);
|
||||
assert(std::ranges::equal(out, expected, comp));
|
||||
assert(base(result.in) == in.begin() + 4);
|
||||
assert(base(result.out) == out.begin() + 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Test custom projection
|
||||
{
|
||||
std::array in{Data{4}, Data{8}, Data{8}, Data{8}};
|
||||
std::array expected{Data{4}, Data{8}};
|
||||
|
||||
const auto proj = &Data::data;
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
std::array<Data, 2> out;
|
||||
auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), {}, proj);
|
||||
assert(std::ranges::equal(out, expected, {}, proj, proj));
|
||||
assert(base(result.in) == in.begin() + 4);
|
||||
assert(base(result.out) == out.begin() + 2);
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
std::array<Data, 2> out;
|
||||
auto result = std::ranges::unique_copy(in, out.begin(), {}, proj);
|
||||
assert(std::ranges::equal(out, expected, {}, proj, proj));
|
||||
assert(base(result.in) == in.begin() + 4);
|
||||
assert(base(result.out) == out.begin() + 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Exactly last - first - 1 applications of the corresponding predicate and no
|
||||
// more than twice as many applications of any projection.
|
||||
{
|
||||
std::array in{1, 2, 3, 3, 3, 4, 3, 3, 5, 5, 6, 6, 1};
|
||||
std::array expected{1, 2, 3, 4, 3, 5, 6, 1};
|
||||
// iterator overload
|
||||
{
|
||||
std::array<int, 8> out;
|
||||
int numberOfComp = 0;
|
||||
int numberOfProj = 0;
|
||||
auto result = std::ranges::unique_copy(
|
||||
in.begin(),
|
||||
in.end(),
|
||||
out.begin(),
|
||||
counting_predicate{std::ranges::equal_to{}, numberOfComp},
|
||||
counting_projection{numberOfProj});
|
||||
assert(std::ranges::equal(out, expected));
|
||||
assert(base(result.in) == in.end());
|
||||
assert(base(result.out) == out.end());
|
||||
assert(numberOfComp == in.size() - 1);
|
||||
assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
|
||||
}
|
||||
// range overload
|
||||
{
|
||||
std::array<int, 8> out;
|
||||
int numberOfComp = 0;
|
||||
int numberOfProj = 0;
|
||||
auto result = std::ranges::unique_copy(
|
||||
in,
|
||||
out.begin(),
|
||||
counting_predicate{std::ranges::equal_to{}, numberOfComp},
|
||||
counting_projection{numberOfProj});
|
||||
assert(std::ranges::equal(out, expected));
|
||||
assert(base(result.in) == in.end());
|
||||
assert(base(result.out) == out.end());
|
||||
assert(numberOfComp == in.size() - 1);
|
||||
assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,21 @@
|
|||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include "MoveOnly.h"
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct AssignableFromMoveOnly {
|
||||
AssignableFromMoveOnly(int i) : data(i) {}
|
||||
AssignableFromMoveOnly() : data(0) {}
|
||||
int data;
|
||||
AssignableFromMoveOnly& operator=(MoveOnly const& m) {
|
||||
data = m.get();
|
||||
return *this;
|
||||
}
|
||||
bool operator==(AssignableFromMoveOnly const& rhs) const { return data == rhs.data; }
|
||||
};
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
TEST_CONSTEXPR bool test_constexpr() {
|
||||
int ia[] = {0, 1, 2, 2, 4};
|
||||
|
@ -107,6 +119,7 @@ test()
|
|||
|
||||
int main(int, char**)
|
||||
{
|
||||
test<cpp17_input_iterator<const int*>, cpp17_input_iterator<int*> >();
|
||||
test<cpp17_input_iterator<const int*>, cpp17_output_iterator<int*> >();
|
||||
test<cpp17_input_iterator<const int*>, forward_iterator<int*> >();
|
||||
test<cpp17_input_iterator<const int*>, bidirectional_iterator<int*> >();
|
||||
|
@ -137,6 +150,16 @@ int main(int, char**)
|
|||
test<const int*, random_access_iterator<int*> >();
|
||||
test<const int*, int*>();
|
||||
|
||||
// Move only inputs
|
||||
{
|
||||
MoveOnly in[5] = {1, 3, 3, 3, 1};
|
||||
AssignableFromMoveOnly out[3] = {};
|
||||
auto result = std::unique_copy(in, in + 5, out);
|
||||
AssignableFromMoveOnly expected[3] = {1, 3, 1};
|
||||
assert(std::equal(out, out + 3, expected));
|
||||
assert(result == out + 3);
|
||||
}
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test_constexpr());
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,7 @@ static_assert(std::is_same_v<in_out_result<int, long>, uninitialized_copy_result
|
|||
static_assert(std::is_same_v<in_out_result<int, long>, uninitialized_copy_n_result<int, long>>);
|
||||
static_assert(std::is_same_v<in_out_result<int, long>, uninitialized_move_result<int, long>>);
|
||||
static_assert(std::is_same_v<in_out_result<int, long>, uninitialized_move_n_result<int, long>>);
|
||||
// static_assert(std::is_same_v<in_out_result<int, long>, unique_copy_result<int, long>>);
|
||||
static_assert(std::is_same_v<in_out_result<int, long>, unique_copy_result<int, long>>);
|
||||
|
||||
static_assert(std::is_same_v<in_in_out_result<int, long, char>, binary_transform_result<int, long, char>>);
|
||||
static_assert(std::is_same_v<in_in_out_result<int, long, char>, merge_result<int, long, char>>);
|
||||
|
|
|
@ -88,7 +88,7 @@ constexpr bool test_all() {
|
|||
using std::ranges::set_union_result;
|
||||
using std::ranges::swap_ranges_result;
|
||||
using std::ranges::unary_transform_result;
|
||||
//using std::ranges::unique_copy_result;
|
||||
using std::ranges::unique_copy_result;
|
||||
|
||||
auto unary_pred = [](int i) { return i > 0; };
|
||||
auto binary_pred = [](int i, int j) { return i < j; };
|
||||
|
@ -117,7 +117,7 @@ constexpr bool test_all() {
|
|||
dangling_1st(std::ranges::partition_point, in, unary_pred);
|
||||
dangling_1st(std::ranges::lower_bound, in, x);
|
||||
dangling_1st(std::ranges::upper_bound, in, x);
|
||||
//dangling_1st(std::ranges::equal_range, in, x);
|
||||
dangling_1st(std::ranges::equal_range, in, x);
|
||||
dangling_1st(std::ranges::min_element, in);
|
||||
dangling_1st(std::ranges::max_element, in);
|
||||
dangling_1st<minmax_result<dangling>>(std::ranges::minmax_element, in);
|
||||
|
@ -157,7 +157,7 @@ constexpr bool test_all() {
|
|||
dangling_both<swap_ranges_result<dangling, dangling>>(std::ranges::swap_ranges, in, in2);
|
||||
dangling_1st<reverse_copy_result<dangling, int*>>(std::ranges::reverse_copy, in, out);
|
||||
dangling_1st<rotate_copy_result<dangling, int*>>(std::ranges::rotate_copy, in, mid, out);
|
||||
//dangling_1st<unique_copy_result<dangling, int*>>(std::ranges::unique_copy, in, out);
|
||||
dangling_1st<unique_copy_result<dangling, int*>>(std::ranges::unique_copy, in, out);
|
||||
dangling_1st<partition_copy_result<dangling, int*, int*>>(std::ranges::partition_copy, in, out, out2, unary_pred);
|
||||
//dangling_1st<partial_sort_copy_result<dangling, int*>>(std::ranges::partial_sort_copy, in, in2);
|
||||
//dangling_2nd<partial_sort_copy_result<int*, dangling>>(std::ranges::partial_sort_copy, in, in2);
|
||||
|
@ -184,7 +184,7 @@ constexpr bool test_all() {
|
|||
//dangling_1st(std::ranges::rotate, in, mid);
|
||||
if (!std::is_constant_evaluated()) // `shuffle` isn't `constexpr`.
|
||||
dangling_1st(std::ranges::shuffle, in, rand_gen());
|
||||
//dangling_1st(std::ranges::unique, in);
|
||||
dangling_1st(std::ranges::unique, in);
|
||||
dangling_1st(std::ranges::partition, in, unary_pred);
|
||||
if (!std::is_constant_evaluated())
|
||||
dangling_1st(std::ranges::stable_partition, in, unary_pred);
|
||||
|
|
|
@ -115,7 +115,7 @@ constexpr bool test_all() {
|
|||
//test(std::ranges::remove_copy_if, in, out, unary_pred);
|
||||
test(std::ranges::replace_if, in, unary_pred, x);
|
||||
//test(std::ranges::replace_copy_if, in, out, unary_pred, x);
|
||||
//test(std::ranges::unique_copy, in, out, binary_pred);
|
||||
test(std::ranges::unique_copy, in, out, binary_pred);
|
||||
test(std::ranges::partition_copy, in, out, out2, unary_pred);
|
||||
//test(std::ranges::partial_sort_copy, in, in2, binary_pred);
|
||||
test(std::ranges::merge, in, in2, out, binary_pred);
|
||||
|
@ -124,7 +124,7 @@ constexpr bool test_all() {
|
|||
test(std::ranges::set_symmetric_difference, in, in2, out, binary_pred);
|
||||
test(std::ranges::set_union, in, in2, out, binary_pred);
|
||||
test(std::ranges::remove_if, in, unary_pred);
|
||||
//test(std::ranges::unique, in, binary_pred);
|
||||
test(std::ranges::unique, in, binary_pred);
|
||||
test(std::ranges::partition, in, unary_pred);
|
||||
if (!std::is_constant_evaluated())
|
||||
test(std::ranges::stable_partition, in, unary_pred);
|
||||
|
|
|
@ -140,7 +140,7 @@ constexpr bool test_all() {
|
|||
// `reverse_copy` has neither a projection nor a predicate.
|
||||
// `rotate_copy` has neither a projection nor a predicate.
|
||||
// `sample` has no requirement that the given generator be invoked via `std::invoke`.
|
||||
//test(std::ranges::unique_copy, in, out, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::unique_copy, in, out, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::partition_copy, in, out, out2, &Foo::unary_pred, &Bar::val);
|
||||
//test(std::ranges::partial_sort_copy, in, in2, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::merge, in, in2, out, &Foo::binary_pred, &Bar::val, &Bar::val);
|
||||
|
@ -153,7 +153,7 @@ constexpr bool test_all() {
|
|||
// `reverse` has neither a projection nor a predicate.
|
||||
// `rotate` has neither a projection nor a predicate.
|
||||
// `shuffle` has neither a projection nor a predicate.
|
||||
//test(std::ranges::unique, in, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::unique, in, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::partition, in, &Foo::unary_pred, &Bar::val);
|
||||
if (!std::is_constant_evaluated())
|
||||
test(std::ranges::stable_partition, in, &Foo::unary_pred, &Bar::val);
|
||||
|
|
|
@ -136,7 +136,7 @@ constexpr void run_tests() {
|
|||
if constexpr (std::copyable<T>) {
|
||||
test(std::ranges::reverse_copy, in, out);
|
||||
test_mid(std::ranges::rotate_copy, in, mid, out);
|
||||
//test(std::ranges::unique_copy, in, out);
|
||||
test(std::ranges::unique_copy, in, out);
|
||||
test(std::ranges::partition_copy, in, out, out2, unary_pred);
|
||||
//test_mid(std::ranges::partial_sort_copy, in, in2);
|
||||
test(std::ranges::merge, in, in2, out);
|
||||
|
@ -153,7 +153,7 @@ constexpr void run_tests() {
|
|||
test(std::ranges::shuffle, in, rand_gen());
|
||||
//if (!std::is_constant_evaluated())
|
||||
// test(std::ranges::sample, in, out, count, rand_gen());
|
||||
//test(std::ranges::unique, in);
|
||||
test(std::ranges::unique, in);
|
||||
test(std::ranges::partition, in, unary_pred);
|
||||
// TODO(ranges): `stable_partition` requires `ranges::rotate` to be implemented.
|
||||
//if (!std::is_constant_evaluated())
|
||||
|
|
|
@ -145,8 +145,8 @@ static_assert(test(std::ranges::stable_sort, a));
|
|||
//static_assert(test(std::ranges::starts_with, a, a));
|
||||
static_assert(test(std::ranges::swap_ranges, a, a));
|
||||
static_assert(test(std::ranges::transform, a, a, triple));
|
||||
//static_assert(test(std::ranges::unique, a));
|
||||
//static_assert(test(std::ranges::unique_copy, a, a));
|
||||
static_assert(test(std::ranges::unique, a));
|
||||
static_assert(test(std::ranges::unique_copy, a, a));
|
||||
static_assert(test(std::ranges::upper_bound, a, 42));
|
||||
|
||||
// [memory.syn]
|
||||
|
|
Loading…
Reference in New Issue