| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef _LIBCPP___ALGORITHM_RANGES_CLAMP_H | ||
| #define _LIBCPP___ALGORITHM_RANGES_CLAMP_H | ||
|
|
||
| #include <__assert> | ||
| #include <__config> | ||
| #include <__functional/identity.h> | ||
| #include <__functional/invoke.h> | ||
| #include <__functional/ranges_operations.h> | ||
| #include <__iterator/concepts.h> | ||
| #include <__iterator/projected.h> | ||
| #include <__utility/forward.h> | ||
|
|
||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
| # pragma GCC system_header | ||
| #endif | ||
|
|
||
| #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) | ||
|
|
||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||
|
|
||
| namespace ranges { | ||
| namespace __clamp { | ||
| struct __fn { | ||
|
|
||
| template <class _Type, | ||
| class _Proj = identity, | ||
| indirect_strict_weak_order<projected<const _Type*, _Proj>> _Comp = ranges::less> | ||
| _LIBCPP_HIDE_FROM_ABI constexpr | ||
| const _Type& operator()(const _Type& __value, | ||
| const _Type& __low, | ||
| const _Type& __high, | ||
| _Comp __comp = {}, | ||
| _Proj __proj = {}) const { | ||
| _LIBCPP_ASSERT(!bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))), | ||
| "Bad bounds passed to std::ranges::clamp"); | ||
|
|
||
| if (std::invoke(__comp, std::invoke(__proj, __value), std::invoke(__proj, __low))) | ||
| return __low; | ||
| else if (std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __value))) | ||
| return __high; | ||
| else | ||
| return __value; | ||
| } | ||
|
|
||
| }; | ||
| } // namespace __clamp | ||
|
|
||
| inline namespace __cpo { | ||
| inline constexpr auto clamp = __clamp::__fn{}; | ||
| } // namespace __cpo | ||
| } // namespace ranges | ||
|
|
||
| _LIBCPP_END_NAMESPACE_STD | ||
|
|
||
| #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) | ||
|
|
||
| #endif // _LIBCPP___ALGORITHM_RANGES_CLAMP_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef _LIBCPP___ALGORITHM_RANGES_IS_PERMUTATION_H | ||
| #define _LIBCPP___ALGORITHM_RANGES_IS_PERMUTATION_H | ||
|
|
||
| #include <__algorithm/is_permutation.h> | ||
| #include <__algorithm/iterator_operations.h> | ||
| #include <__config> | ||
| #include <__functional/identity.h> | ||
| #include <__functional/ranges_operations.h> | ||
| #include <__iterator/concepts.h> | ||
| #include <__iterator/distance.h> | ||
| #include <__iterator/projected.h> | ||
| #include <__ranges/access.h> | ||
| #include <__ranges/concepts.h> | ||
| #include <__utility/move.h> | ||
|
|
||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
| # pragma GCC system_header | ||
| #endif | ||
|
|
||
| #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) | ||
|
|
||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||
|
|
||
| namespace ranges { | ||
| namespace __is_permutation { | ||
| struct __fn { | ||
|
|
||
| template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, | ||
| class _Proj1, class _Proj2, class _Pred> | ||
| _LIBCPP_HIDE_FROM_ABI constexpr static | ||
| bool __is_permutation_func_impl(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, | ||
| _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { | ||
| return std::__is_permutation<_RangeAlgPolicy>( | ||
| std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), | ||
| __pred, __proj1, __proj2); | ||
| } | ||
|
|
||
| template <forward_iterator _Iter1, sentinel_for<_Iter1> _Sent1, | ||
| forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2, | ||
| class _Proj1 = identity, | ||
| class _Proj2 = identity, | ||
| indirect_equivalence_relation<projected<_Iter1, _Proj1>, | ||
| projected<_Iter2, _Proj2>> _Pred = ranges::equal_to> | ||
| _LIBCPP_HIDE_FROM_ABI constexpr | ||
| bool operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, | ||
| _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { | ||
| return __is_permutation_func_impl( | ||
| std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), | ||
| __pred, __proj1, __proj2); | ||
| } | ||
|
|
||
| template <forward_range _Range1, | ||
| forward_range _Range2, | ||
| class _Proj1 = identity, | ||
| class _Proj2 = identity, | ||
| indirect_equivalence_relation<projected<iterator_t<_Range1>, _Proj1>, projected<iterator_t<_Range2>, _Proj2>> _Pred = ranges::equal_to> | ||
| _LIBCPP_HIDE_FROM_ABI constexpr | ||
| bool operator()(_Range1&& __range1, _Range2&& __range2, | ||
| _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { | ||
| if constexpr (sized_range<_Range1> && sized_range<_Range2>) { | ||
| if (ranges::distance(__range1) != ranges::distance(__range2)) | ||
| return false; | ||
| } | ||
|
|
||
| return __is_permutation_func_impl( | ||
| ranges::begin(__range1), ranges::end(__range1), ranges::begin(__range2), ranges::end(__range2), | ||
| __pred, __proj1, __proj2); | ||
| } | ||
| }; | ||
| } // namespace __is_permutation | ||
|
|
||
| inline namespace __cpo { | ||
| inline constexpr auto is_permutation = __is_permutation::__fn{}; | ||
| } // namespace __cpo | ||
| } // namespace ranges | ||
|
|
||
| _LIBCPP_END_NAMESPACE_STD | ||
|
|
||
| #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) | ||
|
|
||
| #endif // _LIBCPP___ALGORITHM_RANGES_IS_PERMUTATION_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef _LIBCPP___ALGORITHM_RANGES_ROTATE_H | ||
| #define _LIBCPP___ALGORITHM_RANGES_ROTATE_H | ||
|
|
||
| #include <__algorithm/iterator_operations.h> | ||
| #include <__algorithm/ranges_iterator_concept.h> | ||
| #include <__algorithm/rotate.h> | ||
| #include <__config> | ||
| #include <__iterator/concepts.h> | ||
| #include <__iterator/iterator_traits.h> | ||
| #include <__iterator/permutable.h> | ||
| #include <__ranges/access.h> | ||
| #include <__ranges/concepts.h> | ||
| #include <__ranges/subrange.h> | ||
| #include <__utility/move.h> | ||
|
|
||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
| # pragma GCC system_header | ||
| #endif | ||
|
|
||
| #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) | ||
|
|
||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||
|
|
||
| namespace ranges { | ||
| namespace __rotate { | ||
|
|
||
| struct __fn { | ||
|
|
||
| template <class _Iter, class _Sent> | ||
| _LIBCPP_HIDE_FROM_ABI constexpr | ||
| static subrange<_Iter> __rotate_fn_impl(_Iter __first, _Iter __middle, _Sent __last) { | ||
| auto __ret = std::__rotate<_RangeAlgPolicy>( | ||
| std::move(__first), std::move(__middle), std::move(__last)); | ||
| return {std::move(__ret.first), std::move(__ret.second)}; | ||
| } | ||
|
|
||
| template <permutable _Iter, sentinel_for<_Iter> _Sent> | ||
| _LIBCPP_HIDE_FROM_ABI constexpr | ||
| subrange<_Iter> operator()(_Iter __first, _Iter __middle, _Sent __last) const { | ||
| return __rotate_fn_impl(std::move(__first), std::move(__middle), std::move(__last)); | ||
| } | ||
|
|
||
| template <forward_range _Range> | ||
| requires permutable<iterator_t<_Range>> | ||
| _LIBCPP_HIDE_FROM_ABI constexpr | ||
| borrowed_subrange_t<_Range> operator()(_Range&& __range, iterator_t<_Range> __middle) const { | ||
| return __rotate_fn_impl(ranges::begin(__range), std::move(__middle), ranges::end(__range)); | ||
| } | ||
|
|
||
| }; | ||
|
|
||
| } // namespace __rotate | ||
|
|
||
| inline namespace __cpo { | ||
| inline constexpr auto rotate = __rotate::__fn{}; | ||
| } // namespace __cpo | ||
| } // namespace ranges | ||
|
|
||
| _LIBCPP_END_NAMESPACE_STD | ||
|
|
||
| #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) | ||
|
|
||
| #endif // _LIBCPP___ALGORITHM_RANGES_ROTATE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,10 +10,6 @@ | |
|
|
||
| // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 | ||
|
|
||
| #include <csignal> | ||
| #include <cstdlib> | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // UNSUPPORTED: c++03, c++11, c++14, c++17 | ||
| // UNSUPPORTED: libcpp-has-no-incomplete-ranges | ||
|
|
||
| // <algorithm> | ||
|
|
||
| // template<permutable I, sentinel_for<I> S> | ||
| // constexpr subrange<I> rotate(I first, I middle, S last); // since C++20 | ||
| // | ||
| // template<forward_range R> | ||
| // requires permutable<iterator_t<R>> | ||
| // constexpr borrowed_subrange_t<R> rotate(R&& r, iterator_t<R> middle); // Since C++20 | ||
|
|
||
| #include <algorithm> | ||
| #include <array> | ||
| #include <cassert> | ||
| #include <ranges> | ||
|
|
||
| #include "almost_satisfies_types.h" | ||
| #include "test_iterators.h" | ||
|
|
||
| // Test constraints of the (iterator, sentinel) overload. | ||
| // ====================================================== | ||
|
|
||
| template <class Iter = int*, class Sent = int*> | ||
| concept HasRotateIter = | ||
| requires(Iter&& iter, Sent&& sent) { | ||
| std::ranges::rotate(std::forward<Iter>(iter), std::forward<Iter>(iter), std::forward<Sent>(sent)); | ||
| }; | ||
|
|
||
| static_assert(HasRotateIter<int*, int*>); | ||
|
|
||
| // !permutable<I> | ||
| static_assert(!HasRotateIter<PermutableNotForwardIterator>); | ||
| static_assert(!HasRotateIter<PermutableNotSwappable>); | ||
|
|
||
| // !sentinel_for<S, I> | ||
| static_assert(!HasRotateIter<int*, SentinelForNotSemiregular>); | ||
| static_assert(!HasRotateIter<int*, SentinelForNotWeaklyEqualityComparableWith>); | ||
|
|
||
| // Test constraints of the (range) overload. | ||
| // ========================================= | ||
|
|
||
| template <class Range> | ||
| concept HasRotateRange = | ||
| requires(Range&& range, std::ranges::iterator_t<Range> iter) { | ||
| std::ranges::rotate(std::forward<Range>(range), iter); | ||
| }; | ||
|
|
||
| template <class T> | ||
| using R = UncheckedRange<T>; | ||
|
|
||
| static_assert(HasRotateRange<R<int*>>); | ||
|
|
||
| // !forward_range<R> | ||
| static_assert(!HasRotateRange<ForwardRangeNotDerivedFrom>); | ||
| static_assert(!HasRotateRange<ForwardRangeNotIncrementable>); | ||
| static_assert(!HasRotateRange<ForwardRangeNotSentinelSemiregular>); | ||
| static_assert(!HasRotateRange<ForwardRangeNotSentinelEqualityComparableWith>); | ||
|
|
||
| // !permutable<iterator_t<R>> | ||
| static_assert(!HasRotateRange<PermutableRangeNotForwardIterator>); | ||
| static_assert(!HasRotateRange<PermutableRangeNotSwappable>); | ||
|
|
||
| template <class Iter, class Sent, size_t N> | ||
| constexpr void test_one(const std::array<int, N> input, size_t mid_index, std::array<int, N> expected) { | ||
| assert(mid_index <= N); | ||
|
|
||
| { // (iterator, sentinel) overload. | ||
| auto in = input; | ||
| auto begin = Iter(in.data()); | ||
| auto mid = Iter(in.data() + mid_index); | ||
| auto end = Sent(Iter(in.data() + in.size())); | ||
|
|
||
| std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::rotate(begin, mid, end); | ||
| assert(base(result.begin()) == in.data() + in.size() - mid_index); | ||
| assert(base(result.end()) == in.data() + in.size()); | ||
| assert(in == expected); | ||
| } | ||
|
|
||
| { // (range) overload. | ||
| auto in = input; | ||
| auto begin = Iter(in.data()); | ||
| auto mid = Iter(in.data() + mid_index); | ||
| auto end = Sent(Iter(in.data() + in.size())); | ||
| auto range = std::ranges::subrange(std::move(begin), std::move(end)); | ||
|
|
||
| std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::rotate(range, mid); | ||
| assert(base(result.begin()) == in.data() + in.size() - mid_index); | ||
| assert(base(result.end()) == in.data() + in.size()); | ||
| assert(in == expected); | ||
| } | ||
| } | ||
|
|
||
| template <class Iter, class Sent> | ||
| constexpr void test_iter_sent() { | ||
| // Empty sequence. | ||
| test_one<Iter, Sent, 0>({}, 0, {}); | ||
|
|
||
| // 1-element sequence. | ||
| test_one<Iter, Sent, 1>({1}, 0, {1}); | ||
|
|
||
| // 2-element sequence. | ||
| test_one<Iter, Sent, 2>({1, 2}, 1, {2, 1}); | ||
|
|
||
| // 3-element sequence. | ||
| test_one<Iter, Sent, 3>({1, 2, 3}, 1, {2, 3, 1}); | ||
| test_one<Iter, Sent, 3>({1, 2, 3}, 2, {3, 1, 2}); | ||
|
|
||
| // Longer sequence. | ||
| test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 2, {3, 4, 5, 6, 7, 1, 2}); | ||
|
|
||
| // Rotate around the middle. | ||
| test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 3, {4, 5, 6, 7, 1, 2, 3}); | ||
|
|
||
| // Rotate around the 1st element (no-op). | ||
| test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 0, {1, 2, 3, 4, 5, 6, 7}); | ||
|
|
||
| // Rotate around the 2nd element. | ||
| test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 1, {2, 3, 4, 5, 6, 7, 1}); | ||
|
|
||
| // Rotate around the last element. | ||
| test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 6, {7, 1, 2, 3, 4, 5, 6}); | ||
|
|
||
| // Pass `end()` as `mid` (no-op). | ||
| test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 7, {1, 2, 3, 4, 5, 6, 7}); | ||
| } | ||
|
|
||
| template <class Iter> | ||
| constexpr void test_iter() { | ||
| test_iter_sent<Iter, Iter>(); | ||
| test_iter_sent<Iter, sentinel_wrapper<Iter>>(); | ||
| } | ||
|
|
||
| constexpr void test_iterators() { | ||
| test_iter<forward_iterator<int*>>(); | ||
| test_iter<bidirectional_iterator<int*>>(); | ||
| test_iter<random_access_iterator<int*>>(); | ||
| test_iter<contiguous_iterator<int*>>(); | ||
| test_iter<int*>(); | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| test_iterators(); | ||
|
|
||
| { // Complexity: at most `last - first` swaps. | ||
| const std::array input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; | ||
| auto expected = static_cast<int>(input.size()); | ||
|
|
||
| { | ||
| auto in = input; | ||
| int swaps = 0; | ||
| auto begin = adl::Iterator::TrackSwaps(in.data(), swaps); | ||
| auto end = adl::Iterator::TrackSwaps(in.data() + in.size(), swaps); | ||
|
|
||
| for (size_t mid = 0; mid != input.size(); ++mid) { | ||
| std::ranges::rotate(begin, begin + mid, end); | ||
| assert(swaps <= expected); | ||
| } | ||
| } | ||
|
|
||
| { | ||
| auto in = input; | ||
| int swaps = 0; | ||
| auto begin = adl::Iterator::TrackSwaps(in.data(), swaps); | ||
| auto end = adl::Iterator::TrackSwaps(in.data() + in.size(), swaps); | ||
| auto range = std::ranges::subrange(begin, end); | ||
|
|
||
| for (size_t mid = 0; mid != input.size(); ++mid) { | ||
| std::ranges::rotate(range, begin + mid); | ||
| assert(swaps <= expected); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,281 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // UNSUPPORTED: c++03, c++11, c++14, c++17 | ||
| // UNSUPPORTED: libcpp-has-no-incomplete-ranges | ||
|
|
||
| // <algorithm> | ||
|
|
||
| // template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2, | ||
| // sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity, | ||
| // indirect_equivalence_relation<projected<I1, Proj1>, | ||
| // projected<I2, Proj2>> Pred = ranges::equal_to> | ||
| // constexpr bool ranges::is_permutation(I1 first1, S1 last1, I2 first2, S2 last2, | ||
| // Pred pred = {}, | ||
| // Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20 | ||
| // | ||
| // template<forward_range R1, forward_range R2, | ||
| // class Proj1 = identity, class Proj2 = identity, | ||
| // indirect_equivalence_relation<projected<iterator_t<R1>, Proj1>, | ||
| // projected<iterator_t<R2>, Proj2>> Pred = ranges::equal_to> | ||
| // constexpr bool ranges::is_permutation(R1&& r1, R2&& r2, Pred pred = {}, | ||
| // Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20 | ||
|
|
||
| #include <algorithm> | ||
| #include <array> | ||
| #include <concepts> | ||
| #include <list> | ||
| #include <ranges> | ||
|
|
||
| #include "almost_satisfies_types.h" | ||
| #include "counting_predicates.h" | ||
| #include "counting_projection.h" | ||
| #include "test_iterators.h" | ||
|
|
||
| template <class Iter1, class Sent1 = int*, class Iter2 = int*, class Sent2 = int*> | ||
| concept HasIsPermutationIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { | ||
| std::ranges::is_permutation(first1, last1, first2, last2); | ||
| }; | ||
|
|
||
| template <class Range1, class Range2 = UncheckedRange<int*>> | ||
| concept HasIsPermutationR = requires(Range1 range1, Range2 range2) { | ||
| std::ranges::is_permutation(range1, range2); | ||
| }; | ||
|
|
||
| static_assert(HasIsPermutationIt<int*>); | ||
| static_assert(!HasIsPermutationIt<ForwardIteratorNotDerivedFrom>); | ||
| static_assert(!HasIsPermutationIt<ForwardIteratorNotIncrementable>); | ||
| static_assert(!HasIsPermutationIt<int*, SentinelForNotSemiregular>); | ||
| static_assert(!HasIsPermutationIt<int*, SentinelForNotWeaklyEqualityComparableWith>); | ||
| static_assert(!HasIsPermutationIt<int*, int*, ForwardIteratorNotDerivedFrom>); | ||
| static_assert(!HasIsPermutationIt<int*, int*, ForwardIteratorNotIncrementable>); | ||
| static_assert(!HasIsPermutationIt<int*, int*, int*, SentinelForNotSemiregular>); | ||
| static_assert(!HasIsPermutationIt<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith>); | ||
| // !indirect_equivalence_relation<Pred, projected<I1, Proj1>, projected<I2, Proj2>>; | ||
| static_assert(!HasIsPermutationIt<int*, int*, int**, int**>); | ||
|
|
||
| static_assert(HasIsPermutationR<UncheckedRange<int*>>); | ||
| static_assert(!HasIsPermutationR<ForwardRangeNotDerivedFrom>); | ||
| static_assert(!HasIsPermutationR<ForwardRangeNotIncrementable>); | ||
| static_assert(!HasIsPermutationR<int*, ForwardRangeNotSentinelSemiregular>); | ||
| static_assert(!HasIsPermutationR<int*, ForwardRangeNotSentinelEqualityComparableWith>); | ||
| static_assert(!HasIsPermutationR<UncheckedRange<int*>, ForwardRangeNotDerivedFrom>); | ||
| static_assert(!HasIsPermutationR<UncheckedRange<int*>, ForwardRangeNotIncrementable>); | ||
| static_assert(!HasIsPermutationR<UncheckedRange<int*>, ForwardRangeNotSentinelSemiregular>); | ||
| static_assert(!HasIsPermutationR<UncheckedRange<int*>, ForwardRangeNotSentinelEqualityComparableWith>); | ||
| // !indirect_equivalence_relation<Pred, projected<iterator_t<I1>, Proj1>, projected<iterator_t<I2>, Proj2>>; | ||
| static_assert(!HasIsPermutationIt<UncheckedRange<int*>, UncheckedRange<int**>>); | ||
|
|
||
| template <int N, int M> | ||
| struct Data { | ||
| std::array<int, N> input1; | ||
| std::array<int, M> input2; | ||
| bool expected; | ||
| }; | ||
|
|
||
| template <class Iter1, class Sent1, class Iter2, class Sent2, int N, int M> | ||
| constexpr void test(Data<N, M> d) { | ||
| { | ||
| std::same_as<bool> decltype(auto) ret = std::ranges::is_permutation(Iter1(d.input1.data()), | ||
| Sent1(Iter1(d.input1.data() + N)), | ||
| Iter1(d.input2.data()), | ||
| Sent1(Iter1(d.input2.data() + M))); | ||
| assert(ret == d.expected); | ||
| } | ||
| { | ||
| auto range1 = std::ranges::subrange(Iter1(d.input1.data()), Sent1(Iter1(d.input1.data() + N))); | ||
| auto range2 = std::ranges::subrange(Iter1(d.input2.data()), Sent1(Iter1(d.input2.data() + M))); | ||
| std::same_as<bool> decltype(auto) ret = std::ranges::is_permutation(range1, range2); | ||
| assert(ret == d.expected); | ||
| } | ||
| } | ||
|
|
||
| template <class Iter1, class Sent1, class Iter2, class Sent2 = Iter2> | ||
| constexpr void test_iterators() { | ||
| // Ranges are identical. | ||
| test<Iter1, Sent1, Iter2, Sent2, 4, 4>({.input1 = {1, 2, 3, 4}, .input2 = {1, 2, 3, 4}, .expected = true}); | ||
|
|
||
| // Ranges are reversed. | ||
| test<Iter1, Sent1, Iter2, Sent2, 4, 4>({.input1 = {1, 2, 3, 4}, .input2 = {4, 3, 2, 1}, .expected = true}); | ||
|
|
||
| // Two elements are swapped. | ||
| test<Iter1, Sent1, Iter2, Sent2, 4, 4>({.input1 = {4, 2, 3, 1}, .input2 = {1, 2, 3, 4}, .expected = true}); | ||
|
|
||
| // The first range is shorter. | ||
| test<Iter1, Sent1, Iter2, Sent2, 4, 5>({.input1 = {4, 2, 3, 1}, .input2 = {4, 3, 2, 1, 5}, .expected = false}); | ||
|
|
||
| // The first range is longer. | ||
| test<Iter1, Sent1, Iter2, Sent2, 5, 4>({.input1 = {4, 2, 3, 1, 5}, .input2 = {4, 3, 2, 1}, .expected = false}); | ||
|
|
||
| // The first range is empty. | ||
| test<Iter1, Sent1, Iter2, Sent2, 0, 4>({.input1 = {}, .input2 = {4, 3, 2, 1}, .expected = false}); | ||
|
|
||
| // The second range is empty. | ||
| test<Iter1, Sent1, Iter2, Sent2, 5, 0>({.input1 = {4, 2, 3, 1, 5}, .input2 = {}, .expected = false}); | ||
|
|
||
| // Both ranges are empty. | ||
| test<Iter1, Sent1, Iter2, Sent2, 0, 0>({.input1 = {}, .input2 = {}, .expected = true}); | ||
|
|
||
| // 1-element range, same value. | ||
| test<Iter1, Sent1, Iter2, Sent2, 1, 1>({.input1 = {1}, .input2 = {1}, .expected = true}); | ||
|
|
||
| // 1-element range, different values. | ||
| test<Iter1, Sent1, Iter2, Sent2, 1, 1>({.input1 = {1}, .input2 = {2}, .expected = false}); | ||
| } | ||
|
|
||
| template <class Iter1, class Sent1 = Iter1> | ||
| constexpr void test_iterators1() { | ||
| test_iterators<Iter1, Sent1, forward_iterator<int*>, sentinel_wrapper<forward_iterator<int*>>>(); | ||
| test_iterators<Iter1, Sent1, forward_iterator<int*>>(); | ||
| test_iterators<Iter1, Sent1, bidirectional_iterator<int*>>(); | ||
| test_iterators<Iter1, Sent1, random_access_iterator<int*>>(); | ||
| test_iterators<Iter1, Sent1, contiguous_iterator<int*>>(); | ||
| test_iterators<Iter1, Sent1, int*>(); | ||
| test_iterators<Iter1, Sent1, const int*>(); | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| test_iterators1<forward_iterator<int*>, sentinel_wrapper<forward_iterator<int*>>>(); | ||
| test_iterators1<forward_iterator<int*>>(); | ||
| test_iterators1<bidirectional_iterator<int*>>(); | ||
| test_iterators1<random_access_iterator<int*>>(); | ||
| test_iterators1<contiguous_iterator<int*>>(); | ||
| test_iterators1<int*>(); | ||
| test_iterators1<const int*>(); | ||
|
|
||
| { // A custom comparator works. | ||
| struct A { | ||
| int a; | ||
| constexpr bool pred(const A& rhs) const { return a == rhs.a; } | ||
| }; | ||
|
|
||
| std::array in1 = {A{2}, A{3}, A{1}}; | ||
| std::array in2 = {A{1}, A{2}, A{3}}; | ||
|
|
||
| { | ||
| auto ret = std::ranges::is_permutation(in1.begin(), in1.end(), in2.begin(), in2.end(), &A::pred); | ||
| assert(ret); | ||
| } | ||
|
|
||
| { | ||
| auto ret = std::ranges::is_permutation(in1, in2, &A::pred); | ||
| assert(ret); | ||
| } | ||
| } | ||
|
|
||
| { // A custom projection works. | ||
| struct A { | ||
| int a; | ||
|
|
||
| constexpr bool operator==(const A&) const = default; | ||
|
|
||
| constexpr A x2() const { return A{a * 2}; } | ||
| constexpr A div2() const { return A{a / 2}; } | ||
| }; | ||
|
|
||
| std::array in1 = {A{1}, A{2}, A{3}}; // [2, 4, 6] after applying `x2`. | ||
| std::array in2 = {A{4}, A{8}, A{12}}; // [2, 4, 6] after applying `div2`. | ||
|
|
||
| { | ||
| auto ret = std::ranges::is_permutation( | ||
| in1.begin(), in1.end(), in2.begin(), in2.end(), {}, &A::x2, &A::div2); | ||
| assert(ret); | ||
| } | ||
|
|
||
| { | ||
| auto ret = std::ranges::is_permutation(in1, in2, {}, &A::x2, &A::div2); | ||
| assert(ret); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| { // Check that complexity requirements are met. | ||
| int predCount = 0; | ||
| int proj1Count = 0; | ||
| int proj2Count = 0; | ||
| auto reset_counters = [&] { | ||
| predCount = proj1Count = proj2Count = 0; | ||
| }; | ||
|
|
||
| counting_predicate pred(std::ranges::equal_to{}, predCount); | ||
| counting_projection<> proj1(proj1Count); | ||
| counting_projection<> proj2(proj2Count); | ||
|
|
||
| { | ||
| // 1. No applications of the corresponding predicate if `ForwardIterator1` and `ForwardIterator2` meet the | ||
| // requirements of random access iterators and `last1 - first1 != last2 - first2`. | ||
| int a[] = {1, 2, 3, 4, 5}; | ||
| int b[] = {1, 2, 3, 4}; | ||
| // Make sure that the iterators have different types. | ||
| auto b_begin = random_access_iterator<int*>(std::begin(b)); | ||
| auto b_end = random_access_iterator<int*>(std::end(b)); | ||
|
|
||
| { | ||
| auto ret = std::ranges::is_permutation(a, a + 5, b_begin, b_end, pred, proj1, proj2); | ||
| assert(!ret); | ||
|
|
||
| assert(predCount == 0); | ||
| assert(proj1Count == 0); | ||
| assert(proj2Count == 0); | ||
| reset_counters(); | ||
| } | ||
|
|
||
| { | ||
| auto ret = std::ranges::is_permutation(a, std::ranges::subrange(b_begin, b_end), pred, proj1, proj2); | ||
| assert(!ret); | ||
|
|
||
| assert(predCount == 0); | ||
| assert(proj1Count == 0); | ||
| assert(proj2Count == 0); | ||
| reset_counters(); | ||
| } | ||
| } | ||
|
|
||
| // 2. Otherwise, exactly last1 - first1 applications of the corresponding predicate if | ||
| // `equal(first1, last1, first2, last2, pred)` would return true. | ||
| { | ||
| int a[] = {1, 2, 3, 4, 5}; | ||
| int b[] = {1, 2, 3, 4, 5}; | ||
| int expected = 5; | ||
|
|
||
| { | ||
| auto ret = std::ranges::is_permutation(a, a + 5, b, b + 5, pred, proj1, proj2); | ||
| assert(ret); | ||
|
|
||
| assert(predCount == expected); | ||
| assert(proj1Count == expected); | ||
| assert(proj2Count == expected); | ||
| reset_counters(); | ||
| } | ||
|
|
||
| { | ||
| auto ret = std::ranges::is_permutation(a, b, pred, proj1, proj2); | ||
| assert(ret); | ||
|
|
||
| assert(predCount == expected); | ||
| assert(proj1Count == expected); | ||
| assert(proj2Count == expected); | ||
| reset_counters(); | ||
| } | ||
| } | ||
|
|
||
| // Note: we currently don't have the setup to test big-O complexity, but copying the requirement for completeness' | ||
| // sake. | ||
| // 3. Otherwise, at worst `O(N^2)`, where `N` has the value `last1 - first1`. | ||
| } | ||
|
|
||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // REQUIRES: has-unix-headers | ||
| // UNSUPPORTED: c++03, c++11, c++14, c++17, libcpp-has-no-incomplete-ranges | ||
| // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}} | ||
| // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 | ||
|
|
||
| // <algorithm> | ||
|
|
||
| // In a call to `ranges::clamp(val, low, high)`, `low` must be `<= high`. | ||
|
|
||
| #include <algorithm> | ||
| #include <functional> | ||
|
|
||
| #include "check_assertion.h" | ||
|
|
||
| int main(int, char**) { | ||
| std::ranges::clamp(1, 2, 0, std::ranges::greater{}); | ||
| TEST_LIBCPP_ASSERT_FAILURE(std::ranges::clamp(1, 2, 0), "Bad bounds passed to std::ranges::clamp"); | ||
|
|
||
| std::ranges::clamp(1, 0, 2); | ||
| TEST_LIBCPP_ASSERT_FAILURE(std::ranges::clamp(1, 0, 2, std::ranges::greater{}), | ||
| "Bad bounds passed to std::ranges::clamp"); | ||
|
|
||
| std::ranges::clamp(1, 1, 1); // Equal bounds should be fine. | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // <algorithm> | ||
|
|
||
| // UNSUPPORTED: c++03, c++11, c++14, c++17 | ||
| // UNSUPPORTED: libcpp-has-no-incomplete-ranges | ||
|
|
||
| // Older Clangs don't properly deduce decltype(auto) with a concept constraint | ||
| // XFAIL: apple-clang-13.0 | ||
|
|
||
| // template<class T, class Proj = identity, | ||
| // indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less> | ||
| // constexpr const T& | ||
| // ranges::clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {}); | ||
|
|
||
| #include <algorithm> | ||
| #include <cassert> | ||
| #include <functional> | ||
| #include <utility> | ||
|
|
||
| template <class T, class Comp = std::ranges::less, class Proj = std::identity> | ||
| concept HasClamp = | ||
| requires(T&& val, T&& low, T&& high, Comp&& comp, Proj&& proj) { | ||
| std::ranges::clamp(std::forward<T>(val), std::forward<T>(low), std::forward<T>(high), | ||
| std::forward<Comp>(comp), std::forward<Proj>(proj)); | ||
| }; | ||
|
|
||
| struct NoComp {}; | ||
| struct CreateNoComp { | ||
| auto operator()(int) const { return NoComp(); } | ||
| }; | ||
|
|
||
| static_assert(HasClamp<int, std::ranges::less, std::identity>); | ||
| static_assert(!HasClamp<NoComp>); | ||
| static_assert(!HasClamp<int, NoComp>); | ||
| static_assert(!HasClamp<int, std::ranges::less, CreateNoComp>); | ||
|
|
||
| constexpr bool test() { | ||
| { // low < val < high | ||
| int val = 2; | ||
| int low = 1; | ||
| int high = 3; | ||
| std::same_as<const int&> decltype(auto) ret = std::ranges::clamp(val, low, high); | ||
| assert(ret == 2); | ||
| assert(&ret == &val); | ||
| } | ||
|
|
||
| { // low > val < high | ||
| assert(std::ranges::clamp(10, 20, 30) == 20); | ||
| } | ||
|
|
||
| { // low < val > high | ||
| assert(std::ranges::clamp(15, 5, 10) == 10); | ||
| } | ||
|
|
||
| { // low == val == high | ||
| int val = 10; | ||
| assert(&std::ranges::clamp(val, 10, 10) == &val); | ||
| } | ||
|
|
||
| { // Check that a custom comparator works. | ||
| assert(std::ranges::clamp(10, 30, 20, std::ranges::greater{}) == 20); | ||
| } | ||
|
|
||
| { // Check that a custom projection works. | ||
| struct S { | ||
| int i; | ||
|
|
||
| constexpr const int& lvalue_proj() const { return i; } | ||
| constexpr int prvalue_proj() const { return i; } | ||
| }; | ||
|
|
||
| struct Comp { | ||
| constexpr bool operator()(const int& lhs, const int& rhs) const { return lhs < rhs; } | ||
| constexpr bool operator()(int&& lhs, int&& rhs) const { return lhs > rhs; } | ||
| }; | ||
|
|
||
| auto val = S{10}; | ||
| auto low = S{20}; | ||
| auto high = S{30}; | ||
| // Check that the value category of the projection return type is preserved. | ||
| assert(&std::ranges::clamp(val, low, high, Comp{}, &S::lvalue_proj) == &low); | ||
| assert(&std::ranges::clamp(val, high, low, Comp{}, &S::prvalue_proj) == &low); | ||
| } | ||
|
|
||
| { // Check that the implementation doesn't cause double moves (which could result from calling the projection on | ||
| // `value` once and then forwarding the result into the comparator). | ||
| struct CheckDoubleMove { | ||
| int i; | ||
| bool moved = false; | ||
|
|
||
| constexpr explicit CheckDoubleMove(int set_i) : i(set_i) {} | ||
| constexpr CheckDoubleMove(const CheckDoubleMove&) = default; | ||
| constexpr CheckDoubleMove(CheckDoubleMove&& rhs) noexcept : i(rhs.i) { | ||
| assert(!rhs.moved); | ||
| rhs.moved = true; | ||
| } | ||
| }; | ||
|
|
||
| auto val = CheckDoubleMove{20}; | ||
| auto low = CheckDoubleMove{10}; | ||
| auto high = CheckDoubleMove{30}; | ||
|
|
||
| auto moving_comp = [](CheckDoubleMove lhs, CheckDoubleMove rhs) { return lhs.i < rhs.i; }; | ||
| auto prvalue_proj = [](const CheckDoubleMove& x) -> CheckDoubleMove { return x; }; | ||
| assert(&std::ranges::clamp(val, low, high, moving_comp, prvalue_proj) == &val); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
|
|
||
| return 0; | ||
| } |