| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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-no-concepts | ||
| // UNSUPPORTED: gcc-10 | ||
|
|
||
| // ranges::next | ||
|
|
||
| #include <iterator> | ||
|
|
||
| #include <array> | ||
| #include <cassert> | ||
|
|
||
| #include "check_round_trip.h" | ||
| #include "test_iterators.h" | ||
|
|
||
| using range_t = std::array<int, 10>; | ||
|
|
||
| class distance_apriori_sentinel { | ||
| public: | ||
| distance_apriori_sentinel() = default; | ||
| constexpr explicit distance_apriori_sentinel(std::ptrdiff_t const count) : count_(count) {} | ||
|
|
||
| constexpr bool operator==(std::input_or_output_iterator auto const&) const { | ||
| assert(false && "difference op should take precedence"); | ||
| return false; | ||
| } | ||
|
|
||
| constexpr friend std::ptrdiff_t operator-(std::input_or_output_iterator auto const&, | ||
| distance_apriori_sentinel const y) { | ||
| return -y.count_; | ||
| } | ||
|
|
||
| constexpr friend std::ptrdiff_t operator-(distance_apriori_sentinel const x, | ||
| std::input_or_output_iterator auto const&) { | ||
| return x.count_; | ||
| } | ||
|
|
||
| private: | ||
| std::ptrdiff_t count_ = 0; | ||
| }; | ||
|
|
||
| template <std::input_or_output_iterator I> | ||
| constexpr void check_assignable_case(std::ptrdiff_t const n) { | ||
| auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | ||
| auto result = | ||
| std::ranges::next(stride_counting_iterator(I(range.begin())), stride_counting_iterator(I(range.begin() + n))); | ||
| assert(result.base().base() == range.begin() + n); | ||
| assert(result.stride_count() == 0); // always zero, so don't use `check_round_trip` | ||
| } | ||
|
|
||
| template <std::input_or_output_iterator I> | ||
| constexpr void check_sized_sentinel_case(std::ptrdiff_t const n) { | ||
| auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | ||
| auto result = std::ranges::next(stride_counting_iterator(I(range.begin())), distance_apriori_sentinel(n)); | ||
| assert(std::move(result).base().base() == range.begin() + n); | ||
| check_round_trip(result, n); | ||
| } | ||
|
|
||
| template <std::input_or_output_iterator I> | ||
| constexpr void check_sentinel_case(std::ptrdiff_t const n) { | ||
| auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | ||
| auto const last = I(range.begin() + n); | ||
| auto result = std::ranges::next(stride_counting_iterator(I(range.begin())), sentinel_wrapper(last)); | ||
| assert(std::move(result).base() == last); | ||
| assert(result.stride_count() == n); // always `n`, so don't use `check_round_trip` | ||
| } | ||
|
|
||
| constexpr bool check_iterator_sentinel() { | ||
| check_assignable_case<cpp17_input_iterator<range_t::const_iterator> >(1); | ||
| check_assignable_case<forward_iterator<range_t::const_iterator> >(3); | ||
| check_assignable_case<bidirectional_iterator<range_t::const_iterator> >(4); | ||
| check_assignable_case<random_access_iterator<range_t::const_iterator> >(5); | ||
| check_assignable_case<contiguous_iterator<range_t::const_iterator> >(6); | ||
| check_assignable_case<output_iterator<range_t::iterator> >(7); | ||
|
|
||
| check_sized_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(7); | ||
| check_sized_sentinel_case<cpp20_input_iterator<range_t::const_iterator> >(6); | ||
| check_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(5); | ||
| check_sized_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4); | ||
| check_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(3); | ||
| check_sized_sentinel_case<contiguous_iterator<range_t::const_iterator> >(2); | ||
| check_sized_sentinel_case<output_iterator<range_t::iterator> >(1); | ||
|
|
||
| check_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(1); | ||
| // cpp20_input_iterator not copyable, so is omitted | ||
| check_sentinel_case<forward_iterator<range_t::const_iterator> >(3); | ||
| check_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4); | ||
| check_sentinel_case<random_access_iterator<range_t::const_iterator> >(5); | ||
| check_sentinel_case<contiguous_iterator<range_t::const_iterator> >(6); | ||
| check_sentinel_case<output_iterator<range_t::iterator> >(7); | ||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| static_assert(check_iterator_sentinel()); | ||
| check_iterator_sentinel(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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-no-concepts | ||
| // UNSUPPORTED: gcc-10 | ||
|
|
||
| // ranges::next | ||
|
|
||
| #include <iterator> | ||
|
|
||
| #include "test_standard_function.h" | ||
|
|
||
| static_assert(is_function_like<decltype(std::ranges::next)>()); | ||
|
|
||
| // FIXME: We're bending the rules here by adding a new type to namespace std::ranges. Since this is | ||
| // the standard library's test suite, this should be fine (we *are* the implementation), but it's | ||
| // necessary at the time of writing since there aren't any iterators in std::ranges that we can | ||
| // borrow for this test. | ||
| namespace std::ranges { | ||
| class fake_forward_iterator { | ||
| public: | ||
| using value_type = int; | ||
| using difference_type = std::ptrdiff_t; | ||
| using iterator_category = std::forward_iterator_tag; | ||
|
|
||
| fake_forward_iterator() = default; | ||
|
|
||
| value_type operator*() const; | ||
| fake_forward_iterator& operator++(); | ||
| fake_forward_iterator operator++(int); | ||
|
|
||
| bool operator==(fake_forward_iterator const&) const = default; | ||
| }; | ||
| } // namespace std::ranges | ||
|
|
||
| // The function templates defined in [range.iter.ops] are not found by argument-dependent name lookup ([basic.lookup.argdep]). | ||
| template <class I, class... Args> | ||
| constexpr bool unqualified_lookup_works = requires(I i, Args... args) { | ||
| next(i, args...); | ||
| }; | ||
|
|
||
| static_assert(!unqualified_lookup_works<std::ranges::fake_forward_iterator>); | ||
| static_assert(!unqualified_lookup_works<std::ranges::fake_forward_iterator, std::ptrdiff_t>); | ||
| static_assert(!unqualified_lookup_works<std::ranges::fake_forward_iterator, std::ranges::fake_forward_iterator>); | ||
| static_assert( | ||
| !unqualified_lookup_works<std::ranges::fake_forward_iterator, std::ptrdiff_t, std::ranges::fake_forward_iterator>); | ||
|
|
||
| namespace test { | ||
| template <class> | ||
| class forward_iterator { | ||
| public: | ||
| using value_type = int; | ||
| using difference_type = std::ptrdiff_t; | ||
| using iterator_category = std::forward_iterator_tag; | ||
|
|
||
| forward_iterator() = default; | ||
|
|
||
| value_type operator*() const; | ||
| forward_iterator& operator++(); | ||
| forward_iterator operator++(int); | ||
|
|
||
| bool operator==(forward_iterator const&) const = default; | ||
| }; | ||
|
|
||
| template <class I> | ||
| void next(forward_iterator<I>) { | ||
| static_assert(std::same_as<I, I*>); | ||
| } | ||
|
|
||
| template <class I> | ||
| void next(forward_iterator<I>, std::ptrdiff_t) { | ||
| static_assert(std::same_as<I, I*>); | ||
| } | ||
|
|
||
| template <class I> | ||
| void next(forward_iterator<I>, forward_iterator<I>) { | ||
| static_assert(std::same_as<I, I*>); | ||
| } | ||
|
|
||
| template <class I> | ||
| void next(forward_iterator<I>, std::ptrdiff_t, forward_iterator<I>) { | ||
| static_assert(std::same_as<I, I*>); | ||
| } | ||
| } // namespace test | ||
|
|
||
| // When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a | ||
| // function call ([expr.call]), they inhibit argument-dependent name lookup. | ||
| void adl_inhibition() { | ||
| test::forward_iterator<int*> x; | ||
|
|
||
| using std::ranges::next; | ||
|
|
||
| (void)next(x); | ||
| (void)next(x, 5); | ||
| (void)next(x, x); | ||
| (void)next(x, 6, x); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 LIBCXX_TEST_PREV_CHECK_ROUND_TRIP_H | ||
| #define LIBCXX_TEST_PREV_CHECK_ROUND_TRIP_H | ||
|
|
||
| #include "test_iterators.h" | ||
|
|
||
| template <std::input_or_output_iterator I> | ||
| constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptrdiff_t const n) { | ||
| auto const distance = n < 0 ? -n : n; | ||
| assert(i.stride_count() == distance); | ||
| assert(i.stride_displacement() == -n); | ||
| } | ||
|
|
||
| template <std::random_access_iterator I> | ||
| constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptrdiff_t const n) { | ||
| assert(i.stride_count() <= 1); | ||
| assert(i.stride_displacement() == n < 0 ? -1 : 1); | ||
| } | ||
|
|
||
| #endif // LIBCXX_TEST_PREV_CHECK_ROUND_TRIP_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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-no-concepts | ||
| // UNSUPPORTED: gcc-10 | ||
|
|
||
| // ranges::prev | ||
|
|
||
| #include <iterator> | ||
|
|
||
| #include <array> | ||
|
|
||
| #include "test_iterators.h" | ||
|
|
||
| void proper_constraints() { | ||
| auto a = std::array{0, 1, 2}; | ||
| (void)std::ranges::prev(forward_iterator(a.begin())); // expected-error {{no matching function for call}} | ||
| (void)std::ranges::prev(forward_iterator(a.begin()), 5); // expected-error {{no matching function for call}} | ||
| (void)std::ranges::prev(forward_iterator(a.begin()), 7); // expected-error {{no matching function for call}} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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-no-concepts | ||
| // UNSUPPORTED: gcc-10 | ||
|
|
||
| // ranges::prev(iterator) | ||
|
|
||
| #include <iterator> | ||
|
|
||
| #include <array> | ||
| #include <cassert> | ||
|
|
||
| #include "check_round_trip.h" | ||
| #include "test_iterators.h" | ||
|
|
||
| constexpr bool check_iterator() { | ||
| constexpr auto range = std::array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | ||
| assert(std::ranges::prev(bidirectional_iterator(&range[4])) == bidirectional_iterator(&range[3])); | ||
| assert(std::ranges::prev(random_access_iterator(&range[5])) == random_access_iterator(&range[4])); | ||
| assert(std::ranges::prev(contiguous_iterator(&range[6])) == contiguous_iterator(&range[5])); | ||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| static_assert(check_iterator()); | ||
| check_iterator(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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-no-concepts | ||
| // UNSUPPORTED: gcc-10 | ||
|
|
||
| // ranges::prev(iterator, count) | ||
|
|
||
| #include <iterator> | ||
|
|
||
| #include <array> | ||
| #include <cassert> | ||
|
|
||
| #include "check_round_trip.h" | ||
| #include "test_iterators.h" | ||
|
|
||
| using range_t = std::array<int, 10>; | ||
|
|
||
| template <std::input_or_output_iterator I> | ||
| constexpr void iterator_count_impl(I first, std::ptrdiff_t const n, range_t::const_iterator const expected) { | ||
| auto result = std::ranges::prev(stride_counting_iterator(std::move(first)), n); | ||
| assert(std::move(result).base().base() == expected); | ||
| check_round_trip(result, n); | ||
| } | ||
|
|
||
| constexpr bool check_iterator_count() { | ||
| constexpr auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | ||
| iterator_count_impl(bidirectional_iterator(&range[8]), 6, &range[2]); | ||
| iterator_count_impl(random_access_iterator(&range[7]), 4, &range[3]); | ||
| iterator_count_impl(contiguous_iterator(&range[5]), 5, &range[0]); | ||
|
|
||
| iterator_count_impl(bidirectional_iterator(&range[2]), 0, &range[2]); | ||
| iterator_count_impl(random_access_iterator(&range[3]), 0, &range[3]); | ||
| iterator_count_impl(contiguous_iterator(&range[0]), 0, &range[0]); | ||
|
|
||
| iterator_count_impl(bidirectional_iterator(&range[3]), -5, &range[8]); | ||
| iterator_count_impl(random_access_iterator(&range[3]), -3, &range[6]); | ||
| iterator_count_impl(contiguous_iterator(&range[3]), -1, &range[4]); | ||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| static_assert(check_iterator_count()); | ||
| check_iterator_count(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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-no-concepts | ||
| // UNSUPPORTED: gcc-10 | ||
|
|
||
| // ranges::prev(iterator, count, sentinel) | ||
|
|
||
| #include <iterator> | ||
|
|
||
| #include <array> | ||
| #include <cassert> | ||
|
|
||
| #include "check_round_trip.h" | ||
| #include "test_iterators.h" | ||
|
|
||
| template <std::input_or_output_iterator I> | ||
| constexpr void check_iterator_count_sentinel_impl(I first, std::ptrdiff_t const steps, I const last) { | ||
| auto result = std::ranges::prev(stride_counting_iterator(first), steps, stride_counting_iterator(last)); | ||
| assert(result == last); | ||
| check_round_trip(result, steps); | ||
| } | ||
|
|
||
| constexpr bool check_iterator_count_sentinel() { | ||
| constexpr auto range = std::array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | ||
| check_iterator_count_sentinel_impl(bidirectional_iterator(&range[8]), 6, bidirectional_iterator(&range[2])); | ||
| check_iterator_count_sentinel_impl(random_access_iterator(&range[5]), 2, random_access_iterator(&range[3])); | ||
| check_iterator_count_sentinel_impl(contiguous_iterator(&range[5]), 5, contiguous_iterator(&range[0])); | ||
|
|
||
| check_iterator_count_sentinel_impl(bidirectional_iterator(&range[2]), 0, bidirectional_iterator(&range[2])); | ||
| check_iterator_count_sentinel_impl(random_access_iterator(&range[3]), 0, random_access_iterator(&range[3])); | ||
| check_iterator_count_sentinel_impl(contiguous_iterator(&range[0]), 0, contiguous_iterator(&range[0])); | ||
|
|
||
| check_iterator_count_sentinel_impl(bidirectional_iterator(&range[5]), -1, bidirectional_iterator(&range[6])); | ||
| check_iterator_count_sentinel_impl(random_access_iterator(&range[5]), -2, random_access_iterator(&range[7])); | ||
| check_iterator_count_sentinel_impl(contiguous_iterator(&range[5]), -3, contiguous_iterator(&range[8])); | ||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| static_assert(check_iterator_count_sentinel()); | ||
| assert(check_iterator_count_sentinel()); | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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-no-concepts | ||
| // UNSUPPORTED: gcc-10 | ||
|
|
||
| // ranges::next | ||
|
|
||
| #include <iterator> | ||
|
|
||
| #include "test_iterators.h" | ||
| #include "test_standard_function.h" | ||
|
|
||
| static_assert(is_function_like<decltype(std::ranges::prev)>()); | ||
|
|
||
| namespace std::ranges { | ||
| class fake_bidirectional_iterator { | ||
| public: | ||
| using value_type = int; | ||
| using difference_type = std::ptrdiff_t; | ||
| using iterator_category = std::bidirectional_iterator_tag; | ||
|
|
||
| fake_bidirectional_iterator() = default; | ||
|
|
||
| value_type operator*() const; | ||
| fake_bidirectional_iterator& operator++(); | ||
| fake_bidirectional_iterator operator++(int); | ||
| fake_bidirectional_iterator& operator--(); | ||
| fake_bidirectional_iterator operator--(int); | ||
|
|
||
| bool operator==(fake_bidirectional_iterator const&) const = default; | ||
| }; | ||
| } // namespace std::ranges | ||
|
|
||
| // The function templates defined in [range.iter.ops] are not found by argument-dependent name lookup ([basic.lookup.argdep]). | ||
| template <class I, class... Args> | ||
| constexpr bool unqualified_lookup_works = requires(I i, Args... args) { | ||
| prev(i, args...); | ||
| }; | ||
|
|
||
| static_assert(!unqualified_lookup_works<std::ranges::fake_bidirectional_iterator>); | ||
| static_assert(!unqualified_lookup_works<std::ranges::fake_bidirectional_iterator, std::ptrdiff_t>); | ||
| static_assert(!unqualified_lookup_works<std::ranges::fake_bidirectional_iterator, std::ptrdiff_t, | ||
| std::ranges::fake_bidirectional_iterator>); | ||
|
|
||
| namespace test { | ||
| template <class> | ||
| class bidirectional_iterator { | ||
| public: | ||
| using value_type = int; | ||
| using difference_type = std::ptrdiff_t; | ||
| using iterator_category = std::bidirectional_iterator_tag; | ||
|
|
||
| bidirectional_iterator() = default; | ||
|
|
||
| value_type operator*() const; | ||
| bidirectional_iterator& operator++(); | ||
| bidirectional_iterator operator++(int); | ||
| bidirectional_iterator& operator--(); | ||
| bidirectional_iterator operator--(int); | ||
|
|
||
| bool operator==(bidirectional_iterator const&) const = default; | ||
| }; | ||
|
|
||
| template <class I> | ||
| void prev(bidirectional_iterator<I>) { | ||
| static_assert(std::same_as<I, I*>); | ||
| } | ||
|
|
||
| template <class I> | ||
| void prev(bidirectional_iterator<I>, std::ptrdiff_t) { | ||
| static_assert(std::same_as<I, I*>); | ||
| } | ||
|
|
||
| template <class I> | ||
| void prev(bidirectional_iterator<I>, std::ptrdiff_t, bidirectional_iterator<I>) { | ||
| static_assert(std::same_as<I, I*>); | ||
| } | ||
| } // namespace test | ||
|
|
||
| // When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a | ||
| // function call ([expr.call]), they inhibit argument-dependent name lookup. | ||
| void adl_inhibition() { | ||
| test::bidirectional_iterator<int*> x; | ||
|
|
||
| using std::ranges::prev; | ||
|
|
||
| (void)prev(x); | ||
| (void)prev(x, 5); | ||
| (void)prev(x, 6, x); | ||
| } |