forked from OSchip/llvm-project
[libc++] Refactor the tests for std::prev, next and advance
This started as an attempt to fix a GCC 11 warning of misplaced parentheses. I then noticed that trying to fix the parentheses warning actually triggered errors in the tests, showing that we were incorrectly assuming that the implementation of ranges::advance was using operator+= or operator-=. This commit fixes that issue and makes the tests easier to follow by localizing the assertions it makes. Differential Revision: https://reviews.llvm.org/D103272
This commit is contained in:
parent
ac031c8db2
commit
8e93aa304b
|
@ -70,11 +70,9 @@ namespace ranges {
|
|||
// [range.iter.op.advance]
|
||||
struct __advance_fn final : __function_like {
|
||||
private:
|
||||
template <signed_integral _Tp>
|
||||
static constexpr make_unsigned_t<_Tp> __abs(_Tp const __n) noexcept {
|
||||
auto const __unsigned_n = __to_unsigned_like(__n);
|
||||
auto const __complement = ~__unsigned_n + 1;
|
||||
return __n < 0 ? __complement : __unsigned_n;
|
||||
template <class _Tp>
|
||||
static constexpr _Tp __abs(_Tp __n) noexcept {
|
||||
return __n < 0 ? -__n : __n;
|
||||
}
|
||||
|
||||
template <class _Ip>
|
||||
|
|
|
@ -1,272 +0,0 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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::advance
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_standard_function.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
static_assert(is_function_like<decltype(std::ranges::advance)>());
|
||||
|
||||
using range_t = std::array<int, 10>;
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(output_iterator<int*> const x, output_iterator<int*> const y) {
|
||||
return x.base() == y.base();
|
||||
}
|
||||
|
||||
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() == 0 || i.stride_count() == 1);
|
||||
assert(i.stride_displacement() == n < 0 ? -1 : 1);
|
||||
}
|
||||
|
||||
namespace iterator_count {
|
||||
template <std::input_or_output_iterator I>
|
||||
constexpr void check_move_forward(std::ptrdiff_t const n) {
|
||||
auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
auto first = stride_counting_iterator(I(range.begin()));
|
||||
std::ranges::advance(first, n);
|
||||
assert(std::move(first).base().base() == range.begin() + n);
|
||||
check_round_trip(first, n);
|
||||
}
|
||||
|
||||
template <std::bidirectional_iterator I>
|
||||
constexpr void check_move_backward(std::ptrdiff_t const n) {
|
||||
auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
auto first = stride_counting_iterator(I(range.begin() + n));
|
||||
std::ranges::advance(first, -n);
|
||||
assert(std::move(first).base().base() == range.begin());
|
||||
check_round_trip(first, -n);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool test() {
|
||||
check_move_forward<cpp17_input_iterator<range_t::const_iterator> >(1);
|
||||
check_move_forward<cpp20_input_iterator<range_t::const_iterator> >(2);
|
||||
check_move_forward<forward_iterator<range_t::const_iterator> >(3);
|
||||
check_move_forward<bidirectional_iterator<range_t::const_iterator> >(4);
|
||||
check_move_forward<random_access_iterator<range_t::const_iterator> >(5);
|
||||
check_move_forward<contiguous_iterator<range_t::const_iterator> >(6);
|
||||
check_move_forward<output_iterator<range_t::iterator> >(7);
|
||||
|
||||
check_move_backward<bidirectional_iterator<range_t::const_iterator> >(4);
|
||||
check_move_backward<random_access_iterator<range_t::const_iterator> >(5);
|
||||
check_move_backward<contiguous_iterator<range_t::const_iterator> >(6);
|
||||
|
||||
// Zero should be checked for each case and each overload
|
||||
check_move_forward<cpp17_input_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<cpp20_input_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<forward_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<bidirectional_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<random_access_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<output_iterator<range_t::iterator> >(0);
|
||||
check_move_backward<bidirectional_iterator<range_t::const_iterator> >(0);
|
||||
check_move_backward<random_access_iterator<range_t::const_iterator> >(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace iterator_count
|
||||
|
||||
class distance_apriori_sentinel {
|
||||
public:
|
||||
distance_apriori_sentinel() = default;
|
||||
constexpr explicit distance_apriori_sentinel(std::ptrdiff_t const count) : count_(count) {}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(std::input_or_output_iterator auto const&) const {
|
||||
assert(false && "difference op should take precedence");
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend std::ptrdiff_t operator-(std::input_or_output_iterator auto const&,
|
||||
distance_apriori_sentinel const y) {
|
||||
return -y.count_;
|
||||
}
|
||||
|
||||
[[nodiscard]] 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;
|
||||
};
|
||||
|
||||
namespace iterator_sentinel {
|
||||
template <std::input_or_output_iterator I, std::sentinel_for<I> S = 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 first = stride_counting_iterator(I(range.begin()));
|
||||
std::ranges::advance(first, stride_counting_iterator(S(I(range.begin() + n))));
|
||||
assert(std::move(first).base().base() == range.begin() + n);
|
||||
assert(first.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 first = stride_counting_iterator(I(range.begin()));
|
||||
std::ranges::advance(first, distance_apriori_sentinel(n));
|
||||
assert(std::move(first).base().base() == range.begin() + n);
|
||||
check_round_trip(first, 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 first = stride_counting_iterator(I(range.begin()));
|
||||
auto const last = I(range.begin() + n);
|
||||
std::ranges::advance(first, sentinel_wrapper(last));
|
||||
assert(first.base() == last);
|
||||
assert(first.stride_count() == n); // always `n`, so don't use `check_round_trip`
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool test() {
|
||||
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;
|
||||
}
|
||||
} // namespace iterator_sentinel
|
||||
|
||||
namespace iterator_count_sentinel {
|
||||
struct expected_t {
|
||||
range_t::const_iterator coordinate;
|
||||
std::ptrdiff_t result;
|
||||
};
|
||||
|
||||
template <std::input_or_output_iterator I>
|
||||
constexpr void check_forward_sized_sentinel_case(std::ptrdiff_t const n, expected_t const expected, range_t& range) {
|
||||
auto current = stride_counting_iterator(I(range.begin()));
|
||||
auto const result = std::ranges::advance(current, n, distance_apriori_sentinel(range.size()));
|
||||
assert(current.base().base() == expected.coordinate);
|
||||
assert(result == expected.result);
|
||||
check_round_trip(current, n - expected.result);
|
||||
}
|
||||
|
||||
template <std::random_access_iterator I>
|
||||
constexpr void check_backward_sized_sentinel_case(std::ptrdiff_t const n, expected_t const expected, range_t& range) {
|
||||
auto current = stride_counting_iterator(I(range.end()));
|
||||
auto const result = std::ranges::advance(current, -n, stride_counting_iterator(I(range.begin())));
|
||||
assert(current.base().base() == expected.coordinate);
|
||||
assert(result == expected.result);
|
||||
check_round_trip(current, n - expected.result);
|
||||
}
|
||||
|
||||
template <std::input_or_output_iterator I>
|
||||
constexpr void check_forward_case(std::ptrdiff_t const n, expected_t const expected, range_t& range) {
|
||||
auto current = stride_counting_iterator(I(range.begin()));
|
||||
auto const result = std::ranges::advance(current, n, sentinel_wrapper(I(range.end())));
|
||||
assert(current.base().base() == expected.coordinate);
|
||||
assert(result == expected.result);
|
||||
assert(current.stride_count() == n - expected.result);
|
||||
}
|
||||
|
||||
template <std::bidirectional_iterator I>
|
||||
constexpr void check_backward_case(std::ptrdiff_t const n, expected_t const expected, range_t& range) {
|
||||
auto current = stride_counting_iterator(I(range.end()));
|
||||
auto const result = std::ranges::advance(current, -n, stride_counting_iterator(I(range.begin())));
|
||||
assert(current.base().base() == expected.coordinate);
|
||||
assert(result == expected.result);
|
||||
assert(current.stride_count() == n + expected.result);
|
||||
assert(current.stride_count() == -current.stride_displacement());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool test() {
|
||||
auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
check_forward_sized_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(1, {range.begin() + 1, 0}, range);
|
||||
// cpp20_input_iterator not copyable, so is omitted
|
||||
check_forward_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(3, {range.begin() + 3, 0}, range);
|
||||
check_forward_sized_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4, {range.begin() + 4, 0}, range);
|
||||
check_forward_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
|
||||
check_forward_sized_sentinel_case<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 6, 0}, range);
|
||||
check_forward_sized_sentinel_case<output_iterator<range_t::iterator> >(7, {range.begin() + 7, 0}, range);
|
||||
|
||||
// bidirectional_iterator omitted because `n < 0` case requires `same_as<I, S>`
|
||||
check_backward_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0},
|
||||
range);
|
||||
check_backward_sized_sentinel_case<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 4, 0}, range);
|
||||
|
||||
// disntance == range.size()
|
||||
check_forward_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(10, {range.end(), 0}, range);
|
||||
check_forward_sized_sentinel_case<output_iterator<range_t::iterator> >(10, {range.end(), 0}, range);
|
||||
check_backward_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(10, {range.begin(), 0}, range);
|
||||
|
||||
// distance > range.size()
|
||||
check_forward_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(1000, {range.end(), 990}, range);
|
||||
check_forward_sized_sentinel_case<output_iterator<range_t::iterator> >(1000, {range.end(), 990}, range);
|
||||
check_backward_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(1000, {range.begin(), -990},
|
||||
range);
|
||||
|
||||
check_forward_case<cpp17_input_iterator<range_t::const_iterator> >(1, {range.begin() + 1, 0}, range);
|
||||
check_forward_case<forward_iterator<range_t::const_iterator> >(3, {range.begin() + 3, 0}, range);
|
||||
check_forward_case<bidirectional_iterator<range_t::const_iterator> >(4, {range.begin() + 4, 0}, range);
|
||||
check_forward_case<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
|
||||
check_forward_case<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 6, 0}, range);
|
||||
check_forward_case<output_iterator<range_t::iterator> >(7, {range.begin() + 7, 0}, range);
|
||||
check_backward_case<bidirectional_iterator<range_t::const_iterator> >(8, {range.begin() + 2, 0}, range);
|
||||
|
||||
// disntance == range.size()
|
||||
check_forward_case<forward_iterator<range_t::const_iterator> >(10, {range.end(), 0}, range);
|
||||
check_forward_case<output_iterator<range_t::iterator> >(10, {range.end(), 0}, range);
|
||||
check_backward_case<bidirectional_iterator<range_t::const_iterator> >(10, {range.begin(), 0}, range);
|
||||
|
||||
// distance > range.size()
|
||||
check_forward_case<forward_iterator<range_t::const_iterator> >(1000, {range.end(), 990}, range);
|
||||
check_forward_case<output_iterator<range_t::iterator> >(1000, {range.end(), 990}, range);
|
||||
check_backward_case<bidirectional_iterator<range_t::const_iterator> >(1000, {range.begin(), -990}, range);
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace iterator_count_sentinel
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(iterator_count::test());
|
||||
assert(iterator_count::test());
|
||||
|
||||
static_assert(iterator_sentinel::test());
|
||||
assert(iterator_sentinel::test());
|
||||
|
||||
static_assert(iterator_count_sentinel::test());
|
||||
assert(iterator_count_sentinel::test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::advance(it, n)
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_standard_function.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
static_assert(is_function_like<decltype(std::ranges::advance)>());
|
||||
|
||||
using range_t = std::array<int, 10>;
|
||||
|
||||
template <std::input_or_output_iterator I>
|
||||
constexpr void check_move_forward(std::ptrdiff_t const n) {
|
||||
auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
auto first = stride_counting_iterator(I(range.begin()));
|
||||
std::ranges::advance(first, n);
|
||||
|
||||
assert(first.base().base() == range.begin() + n);
|
||||
if constexpr (std::random_access_iterator<I>) {
|
||||
assert(first.stride_count() == 0 || first.stride_count() == 1);
|
||||
assert(first.stride_displacement() == 1);
|
||||
} else {
|
||||
assert(first.stride_count() == n);
|
||||
assert(first.stride_displacement() == n);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::bidirectional_iterator I>
|
||||
constexpr void check_move_backward(std::ptrdiff_t const n) {
|
||||
auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
auto first = stride_counting_iterator(I(range.begin() + n));
|
||||
std::ranges::advance(first, -n);
|
||||
assert(first.base().base() == range.begin());
|
||||
|
||||
if constexpr (std::random_access_iterator<I>) {
|
||||
assert(first.stride_count() == 0 || first.stride_count() == 1);
|
||||
assert(first.stride_displacement() == 1);
|
||||
} else {
|
||||
assert(first.stride_count() == n);
|
||||
assert(first.stride_displacement() == -n);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
check_move_forward<cpp17_input_iterator<range_t::const_iterator> >(1);
|
||||
check_move_forward<cpp20_input_iterator<range_t::const_iterator> >(2);
|
||||
check_move_forward<forward_iterator<range_t::const_iterator> >(3);
|
||||
check_move_forward<bidirectional_iterator<range_t::const_iterator> >(4);
|
||||
check_move_forward<random_access_iterator<range_t::const_iterator> >(5);
|
||||
check_move_forward<contiguous_iterator<range_t::const_iterator> >(6);
|
||||
check_move_forward<output_iterator<range_t::iterator> >(7);
|
||||
|
||||
check_move_backward<bidirectional_iterator<range_t::const_iterator> >(4);
|
||||
check_move_backward<random_access_iterator<range_t::const_iterator> >(5);
|
||||
check_move_backward<contiguous_iterator<range_t::const_iterator> >(6);
|
||||
|
||||
// Zero should be checked for each case and each overload
|
||||
check_move_forward<cpp17_input_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<cpp20_input_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<forward_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<bidirectional_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<random_access_iterator<range_t::const_iterator> >(0);
|
||||
check_move_forward<output_iterator<range_t::iterator> >(0);
|
||||
check_move_backward<bidirectional_iterator<range_t::const_iterator> >(0);
|
||||
check_move_backward<random_access_iterator<range_t::const_iterator> >(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(test());
|
||||
assert(test());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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::advance(it, n, sent)
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_standard_function.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
static_assert(is_function_like<decltype(std::ranges::advance)>());
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct expected_t {
|
||||
range_t::const_iterator coordinate;
|
||||
std::ptrdiff_t result;
|
||||
};
|
||||
|
||||
template <std::input_or_output_iterator I>
|
||||
constexpr void check_forward_sized_sentinel(std::ptrdiff_t const n, expected_t const expected, range_t& range) {
|
||||
auto current = stride_counting_iterator(I(range.begin()));
|
||||
auto const result = std::ranges::advance(current, n, distance_apriori_sentinel(range.size()));
|
||||
assert(current.base().base() == expected.coordinate);
|
||||
assert(result == expected.result);
|
||||
|
||||
if constexpr (std::random_access_iterator<I>) {
|
||||
assert(current.stride_count() == 0 || current.stride_count() == 1);
|
||||
assert(current.stride_displacement() == current.stride_count());
|
||||
} else {
|
||||
assert(current.stride_count() == (n - result));
|
||||
assert(current.stride_displacement() == (n - result));
|
||||
}
|
||||
}
|
||||
|
||||
template <std::random_access_iterator I>
|
||||
constexpr void check_backward_sized_sentinel(std::ptrdiff_t const n, expected_t const expected, range_t& range) {
|
||||
auto current = stride_counting_iterator(I(range.end()));
|
||||
auto const result = std::ranges::advance(current, -n, stride_counting_iterator(I(range.begin())));
|
||||
assert(current.base().base() == expected.coordinate);
|
||||
assert(result == expected.result);
|
||||
|
||||
assert(current.stride_count() == 0 || current.stride_count() == 1);
|
||||
assert(current.stride_displacement() == current.stride_count());
|
||||
}
|
||||
|
||||
template <std::input_or_output_iterator I>
|
||||
constexpr void check_forward(std::ptrdiff_t const n, expected_t const expected, range_t& range) {
|
||||
auto current = stride_counting_iterator(I(range.begin()));
|
||||
auto const result = std::ranges::advance(current, n, sentinel_wrapper(I(range.end())));
|
||||
assert(current.base().base() == expected.coordinate);
|
||||
assert(result == expected.result);
|
||||
assert(current.stride_count() == n - result);
|
||||
}
|
||||
|
||||
template <std::bidirectional_iterator I>
|
||||
constexpr void check_backward(std::ptrdiff_t const n, expected_t const expected, range_t& range) {
|
||||
auto current = stride_counting_iterator(I(range.end()));
|
||||
auto const result = std::ranges::advance(current, -n, stride_counting_iterator(I(range.begin())));
|
||||
assert(current.base().base() == expected.coordinate);
|
||||
assert(result == expected.result);
|
||||
assert(current.stride_count() == n + result);
|
||||
assert(current.stride_count() == -current.stride_displacement());
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
check_forward_sized_sentinel<cpp17_input_iterator<range_t::const_iterator> >(1, {range.begin() + 1, 0}, range);
|
||||
// cpp20_input_iterator not copyable, so is omitted
|
||||
check_forward_sized_sentinel<forward_iterator<range_t::const_iterator> >(3, {range.begin() + 3, 0}, range);
|
||||
check_forward_sized_sentinel<bidirectional_iterator<range_t::const_iterator> >(4, {range.begin() + 4, 0}, range);
|
||||
check_forward_sized_sentinel<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
|
||||
check_forward_sized_sentinel<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 6, 0}, range);
|
||||
|
||||
// bidirectional_iterator omitted because the `n < 0` case requires `same_as<I, S>`
|
||||
check_backward_sized_sentinel<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
|
||||
check_backward_sized_sentinel<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 4, 0}, range);
|
||||
|
||||
// distance == range.size()
|
||||
check_forward_sized_sentinel<forward_iterator<range_t::const_iterator> >(10, {range.end(), 0}, range);
|
||||
check_backward_sized_sentinel<random_access_iterator<range_t::const_iterator> >(10, {range.begin(), 0}, range);
|
||||
|
||||
// distance > range.size()
|
||||
check_forward_sized_sentinel<forward_iterator<range_t::const_iterator> >(1000, {range.end(), 990}, range);
|
||||
check_backward_sized_sentinel<random_access_iterator<range_t::const_iterator> >(1000, {range.begin(), -990}, range);
|
||||
|
||||
check_forward<cpp17_input_iterator<range_t::const_iterator> >(1, {range.begin() + 1, 0}, range);
|
||||
check_forward<forward_iterator<range_t::const_iterator> >(3, {range.begin() + 3, 0}, range);
|
||||
check_forward<bidirectional_iterator<range_t::const_iterator> >(4, {range.begin() + 4, 0}, range);
|
||||
check_forward<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
|
||||
check_forward<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 6, 0}, range);
|
||||
check_backward<bidirectional_iterator<range_t::const_iterator> >(8, {range.begin() + 2, 0}, range);
|
||||
|
||||
// distance == range.size()
|
||||
check_forward<forward_iterator<range_t::const_iterator> >(10, {range.end(), 0}, range);
|
||||
check_backward<bidirectional_iterator<range_t::const_iterator> >(10, {range.begin(), 0}, range);
|
||||
|
||||
// distance > range.size()
|
||||
check_forward<forward_iterator<range_t::const_iterator> >(1000, {range.end(), 990}, range);
|
||||
check_backward<bidirectional_iterator<range_t::const_iterator> >(1000, {range.begin(), -990}, range);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(test());
|
||||
assert(test());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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::advance(it, sent)
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_standard_function.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
static_assert(is_function_like<decltype(std::ranges::advance)>());
|
||||
|
||||
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, std::sentinel_for<I> S = 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 first = stride_counting_iterator(I(range.begin()));
|
||||
std::ranges::advance(first, stride_counting_iterator(S(I(range.begin() + n))));
|
||||
assert(first.base().base() == range.begin() + n);
|
||||
assert(first.stride_count() == 0); // because we got here by assigning from last, not by incrementing
|
||||
}
|
||||
|
||||
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 first = stride_counting_iterator(I(range.begin()));
|
||||
std::ranges::advance(first, distance_apriori_sentinel(n));
|
||||
|
||||
assert(first.base().base() == range.begin() + n);
|
||||
if constexpr (std::random_access_iterator<I>) {
|
||||
assert(first.stride_count() == 1);
|
||||
assert(first.stride_displacement() == 1);
|
||||
} else {
|
||||
assert(first.stride_count() == n);
|
||||
assert(first.stride_displacement() == 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 first = stride_counting_iterator(I(range.begin()));
|
||||
auto const last = I(range.begin() + n);
|
||||
std::ranges::advance(first, sentinel_wrapper(last));
|
||||
assert(first.base() == last);
|
||||
assert(first.stride_count() == n);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
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_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_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);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(test());
|
||||
assert(test());
|
||||
return 0;
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_CHECK_ROUND_TRIP_H
|
||||
#define LIBCXX_TEST_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);
|
||||
}
|
||||
|
||||
template <std::input_or_output_iterator I>
|
||||
constexpr bool operator==(output_iterator<I> const& x, output_iterator<I> const& y) {
|
||||
return x.base() == y.base();
|
||||
}
|
||||
|
||||
#endif // LIBCXX_TEST_CHECK_ROUND_TRIP_H
|
|
@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::next
|
||||
// Make sure we're SFINAE-friendly when the template argument constraints are not met.
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
template <class ...Args>
|
||||
concept has_ranges_next = requires (Args ...args) {
|
||||
{ std::ranges::next(std::forward<Args>(args)...) };
|
||||
};
|
||||
|
||||
using It = std::unique_ptr<int>;
|
||||
static_assert(!has_ranges_next<It>);
|
||||
static_assert(!has_ranges_next<It, std::ptrdiff_t>);
|
||||
static_assert(!has_ranges_next<It, It>);
|
||||
static_assert(!has_ranges_next<It, std::ptrdiff_t, It>);
|
||||
|
||||
// Test the test
|
||||
static_assert(has_ranges_next<int*, std::ptrdiff_t, int*>);
|
|
@ -1,27 +0,0 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 <memory>
|
||||
|
||||
#include "test_iterators.h"
|
||||
|
||||
void proper_constraints() {
|
||||
auto p = std::unique_ptr<int>();
|
||||
std::ranges::next(p); // expected-error {{no matching function for call}}
|
||||
std::ranges::next(p, p); // expected-error {{no matching function for call}}
|
||||
std::ranges::next(p, 5); // expected-error {{no matching function for call}}
|
||||
std::ranges::next(p, 7); // expected-error {{no matching function for call}}
|
||||
}
|
|
@ -10,32 +10,37 @@
|
|||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::next(first, n)
|
||||
// ranges::next(it)
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "check_round_trip.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
using range_t = std::array<int, 10>;
|
||||
template <class It>
|
||||
constexpr void check() {
|
||||
int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
assert(&*std::ranges::next(It(&range[0])) == &range[1]);
|
||||
assert(&*std::ranges::next(It(&range[1])) == &range[2]);
|
||||
assert(&*std::ranges::next(It(&range[2])) == &range[3]);
|
||||
assert(&*std::ranges::next(It(&range[3])) == &range[4]);
|
||||
assert(&*std::ranges::next(It(&range[4])) == &range[5]);
|
||||
assert(&*std::ranges::next(It(&range[5])) == &range[6]);
|
||||
}
|
||||
|
||||
constexpr bool check_iterator() {
|
||||
constexpr auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
assert(std::ranges::next(cpp17_input_iterator(&range[0])) == cpp17_input_iterator(&range[1]));
|
||||
assert(std::ranges::next(cpp20_input_iterator(&range[1])).base() == &range[2]);
|
||||
assert(std::ranges::next(forward_iterator(&range[2])) == forward_iterator(&range[3]));
|
||||
assert(std::ranges::next(bidirectional_iterator(&range[3])) == bidirectional_iterator(&range[4]));
|
||||
assert(std::ranges::next(random_access_iterator(&range[4])) == random_access_iterator(&range[5]));
|
||||
assert(std::ranges::next(contiguous_iterator(&range[5])) == contiguous_iterator(&range[6]));
|
||||
assert(std::ranges::next(output_iterator(&range[6])).base() == &range[7]);
|
||||
constexpr bool test() {
|
||||
check<cpp17_input_iterator<int*>>();
|
||||
check<cpp20_input_iterator<int*>>();
|
||||
check<forward_iterator<int*>>();
|
||||
check<bidirectional_iterator<int*>>();
|
||||
check<random_access_iterator<int*>>();
|
||||
check<contiguous_iterator<int*>>();
|
||||
check<output_iterator<int*>>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(check_iterator());
|
||||
check_iterator();
|
||||
static_assert(test());
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,52 +10,65 @@
|
|||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::next(first, n)
|
||||
// ranges::next(it, n)
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#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::next(stride_counting_iterator(std::move(first)), n);
|
||||
assert(std::move(result).base().base() == expected);
|
||||
check_round_trip(result, n);
|
||||
constexpr void check_steps(I it, std::ptrdiff_t n, int const* expected) {
|
||||
{
|
||||
auto result = std::ranges::next(std::move(it), n);
|
||||
assert(&*result == expected);
|
||||
}
|
||||
|
||||
// Count the number of operations
|
||||
{
|
||||
stride_counting_iterator strided_it(std::move(it));
|
||||
auto result = std::ranges::next(std::move(strided_it), n);
|
||||
assert(&*result == expected);
|
||||
if constexpr (std::random_access_iterator<I>) {
|
||||
assert(result.stride_count() == 1); // uses += exactly once
|
||||
assert(result.stride_displacement() == 1);
|
||||
} else {
|
||||
auto const abs_n = n < 0 ? -n : n;
|
||||
assert(result.stride_count() == abs_n);
|
||||
assert(result.stride_displacement() == n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool check_iterator_count() {
|
||||
constexpr auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
constexpr bool test() {
|
||||
int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
iterator_count_impl(cpp17_input_iterator(&range[0]), 1, &range[1]);
|
||||
iterator_count_impl(cpp20_input_iterator(&range[6]), 2, &range[8]);
|
||||
iterator_count_impl(forward_iterator(&range[0]), 3, &range[3]);
|
||||
iterator_count_impl(bidirectional_iterator(&range[2]), 6, &range[8]);
|
||||
iterator_count_impl(random_access_iterator(&range[3]), 4, &range[7]);
|
||||
iterator_count_impl(contiguous_iterator(&range[0]), 5, &range[5]);
|
||||
iterator_count_impl(output_iterator(&range[0]), 6, &range[6]);
|
||||
check_steps(cpp17_input_iterator(&range[0]), 1, &range[1]);
|
||||
check_steps(cpp20_input_iterator(&range[6]), 2, &range[8]);
|
||||
check_steps(forward_iterator(&range[0]), 3, &range[3]);
|
||||
check_steps(bidirectional_iterator(&range[2]), 6, &range[8]);
|
||||
check_steps(random_access_iterator(&range[3]), 4, &range[7]);
|
||||
check_steps(contiguous_iterator(&range[0]), 5, &range[5]);
|
||||
check_steps(output_iterator(&range[0]), 6, &range[6]);
|
||||
|
||||
iterator_count_impl(cpp17_input_iterator(&range[0]), 0, &range[0]);
|
||||
iterator_count_impl(cpp20_input_iterator(&range[6]), 0, &range[6]);
|
||||
iterator_count_impl(forward_iterator(&range[0]), 0, &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(output_iterator(&range[0]), 0, &range[0]);
|
||||
check_steps(cpp17_input_iterator(&range[0]), 0, &range[0]);
|
||||
check_steps(cpp20_input_iterator(&range[6]), 0, &range[6]);
|
||||
check_steps(forward_iterator(&range[0]), 0, &range[0]);
|
||||
check_steps(bidirectional_iterator(&range[2]), 0, &range[2]);
|
||||
check_steps(random_access_iterator(&range[3]), 0, &range[3]);
|
||||
check_steps(contiguous_iterator(&range[0]), 0, &range[0]);
|
||||
check_steps(output_iterator(&range[0]), 0, &range[0]);
|
||||
|
||||
iterator_count_impl(bidirectional_iterator(&range[8]), -5, &range[3]);
|
||||
iterator_count_impl(random_access_iterator(&range[6]), -3, &range[3]);
|
||||
iterator_count_impl(contiguous_iterator(&range[4]), -1, &range[3]);
|
||||
check_steps(bidirectional_iterator(&range[8]), -5, &range[3]);
|
||||
check_steps(random_access_iterator(&range[6]), -3, &range[3]);
|
||||
check_steps(contiguous_iterator(&range[4]), -1, &range[3]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(check_iterator_count());
|
||||
check_iterator_count();
|
||||
static_assert(test());
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,48 +10,63 @@
|
|||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::next
|
||||
// ranges::next(it, n, bound)
|
||||
|
||||
#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::next(stride_counting_iterator(first), steps, stride_counting_iterator(last));
|
||||
assert(result == last);
|
||||
check_round_trip(result, steps);
|
||||
constexpr void check(I it, std::ptrdiff_t n, I last) {
|
||||
{
|
||||
auto result = std::ranges::next(it, n, last);
|
||||
assert(result == last);
|
||||
}
|
||||
|
||||
// Count the number of operations
|
||||
{
|
||||
stride_counting_iterator strided_it(it), strided_last(last);
|
||||
auto result = std::ranges::next(strided_it, n, strided_last);
|
||||
assert(result == strided_last);
|
||||
if constexpr (std::random_access_iterator<I>) {
|
||||
if (n == 0 || n >= (last - it)) {
|
||||
assert(result.stride_count() == 0); // uses the assign-from-sentinel codepath
|
||||
} else {
|
||||
assert(result.stride_count() == 1); // uses += exactly once
|
||||
}
|
||||
} else {
|
||||
auto const abs_n = n < 0 ? -n : n;
|
||||
assert(result.stride_count() == abs_n);
|
||||
assert(result.stride_displacement() == n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(cpp17_input_iterator(&range[0]), 1, cpp17_input_iterator(&range[1]));
|
||||
check_iterator_count_sentinel_impl(forward_iterator(&range[0]), 2, forward_iterator(&range[2]));
|
||||
check_iterator_count_sentinel_impl(bidirectional_iterator(&range[2]), 6, bidirectional_iterator(&range[8]));
|
||||
check_iterator_count_sentinel_impl(random_access_iterator(&range[3]), 2, random_access_iterator(&range[5]));
|
||||
check_iterator_count_sentinel_impl(contiguous_iterator(&range[0]), 5, contiguous_iterator(&range[5]));
|
||||
check_iterator_count_sentinel_impl(output_iterator(&range[3]), 2, output_iterator(&range[5]));
|
||||
constexpr bool test() {
|
||||
int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
check_iterator_count_sentinel_impl(cpp17_input_iterator(&range[0]), 0, cpp17_input_iterator(&range[0]));
|
||||
check_iterator_count_sentinel_impl(forward_iterator(&range[0]), 0, forward_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(output_iterator(&range[3]), 0, output_iterator(&range[3]));
|
||||
check(cpp17_input_iterator(&range[0]), 1, cpp17_input_iterator(&range[1]));
|
||||
check(forward_iterator(&range[0]), 2, forward_iterator(&range[2]));
|
||||
check(bidirectional_iterator(&range[2]), 6, bidirectional_iterator(&range[8]));
|
||||
check(random_access_iterator(&range[3]), 2, random_access_iterator(&range[5]));
|
||||
check(contiguous_iterator(&range[0]), 5, contiguous_iterator(&range[5]));
|
||||
|
||||
check_iterator_count_sentinel_impl(bidirectional_iterator(&range[6]), -1, bidirectional_iterator(&range[5]));
|
||||
check_iterator_count_sentinel_impl(random_access_iterator(&range[7]), -2, random_access_iterator(&range[5]));
|
||||
check_iterator_count_sentinel_impl(contiguous_iterator(&range[8]), -3, contiguous_iterator(&range[5]));
|
||||
check(cpp17_input_iterator(&range[0]), 0, cpp17_input_iterator(&range[0]));
|
||||
check(forward_iterator(&range[0]), 0, forward_iterator(&range[0]));
|
||||
check(bidirectional_iterator(&range[2]), 0, bidirectional_iterator(&range[2]));
|
||||
check(random_access_iterator(&range[3]), 0, random_access_iterator(&range[3]));
|
||||
check(contiguous_iterator(&range[0]), 0, contiguous_iterator(&range[0]));
|
||||
|
||||
check(bidirectional_iterator(&range[6]), -1, bidirectional_iterator(&range[5]));
|
||||
check(random_access_iterator(&range[7]), -2, random_access_iterator(&range[5]));
|
||||
check(contiguous_iterator(&range[8]), -3, contiguous_iterator(&range[5]));
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(check_iterator_count_sentinel());
|
||||
assert(check_iterator_count_sentinel());
|
||||
static_assert(test());
|
||||
assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::next
|
||||
// ranges::next(it, bound)
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#include "check_round_trip.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
using range_t = std::array<int, 10>;
|
||||
|
@ -47,59 +47,96 @@ private:
|
|||
};
|
||||
|
||||
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`
|
||||
constexpr void check_assignable(I it, I last, int const* expected) {
|
||||
{
|
||||
auto result = std::ranges::next(std::move(it), std::move(last));
|
||||
assert(&*result == expected);
|
||||
}
|
||||
|
||||
// Count operations
|
||||
{
|
||||
auto strided_it = stride_counting_iterator(std::move(it));
|
||||
auto strided_last = stride_counting_iterator(std::move(last));
|
||||
auto result = std::ranges::next(std::move(strided_it), std::move(strided_last));
|
||||
assert(&*result == expected);
|
||||
assert(result.stride_count() == 0); // because we got here by assigning from last, not by incrementing
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
constexpr void check_sized_sentinel(I it, I last, int const* expected) {
|
||||
auto n = (last.base() - it.base());
|
||||
|
||||
{
|
||||
auto sent = distance_apriori_sentinel(n);
|
||||
auto result = std::ranges::next(std::move(it), sent);
|
||||
assert(&*result == expected);
|
||||
}
|
||||
|
||||
// Count operations
|
||||
{
|
||||
auto strided_it = stride_counting_iterator(std::move(it));
|
||||
auto sent = distance_apriori_sentinel(n);
|
||||
auto result = std::ranges::next(std::move(strided_it), sent);
|
||||
assert(&*result == expected);
|
||||
|
||||
if constexpr (std::random_access_iterator<I>) {
|
||||
assert(result.stride_count() == 1); // should have used exactly one +=
|
||||
assert(result.stride_displacement() == 1);
|
||||
} else {
|
||||
assert(result.stride_count() == n);
|
||||
assert(result.stride_displacement() == 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 void check_sentinel(I it, I last, int const* expected) {
|
||||
auto n = (last.base() - it.base());
|
||||
|
||||
{
|
||||
auto sent = sentinel_wrapper(last);
|
||||
auto result = std::ranges::next(std::move(it), sent);
|
||||
assert(&*result == expected);
|
||||
}
|
||||
|
||||
// Count operations
|
||||
{
|
||||
auto strided_it = stride_counting_iterator(it);
|
||||
auto sent = sentinel_wrapper(stride_counting_iterator(last));
|
||||
auto result = std::ranges::next(std::move(strided_it), sent);
|
||||
assert(&*result == expected);
|
||||
assert(result.stride_count() == n); // must have used ++ until it hit the sentinel
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
constexpr bool test() {
|
||||
int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
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_assignable(cpp17_input_iterator(&range[0]), cpp17_input_iterator(&range[2]), &range[2]);
|
||||
check_assignable(forward_iterator(&range[0]), forward_iterator(&range[3]), &range[3]);
|
||||
check_assignable(bidirectional_iterator(&range[0]), bidirectional_iterator(&range[4]), &range[4]);
|
||||
check_assignable(random_access_iterator(&range[0]), random_access_iterator(&range[5]), &range[5]);
|
||||
check_assignable(contiguous_iterator(&range[0]), contiguous_iterator(&range[6]), &range[6]);
|
||||
|
||||
check_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(1);
|
||||
check_sized_sentinel(cpp17_input_iterator(&range[0]), cpp17_input_iterator(&range[7]), &range[7]);
|
||||
check_sized_sentinel(cpp20_input_iterator(&range[0]), cpp20_input_iterator(&range[6]), &range[6]);
|
||||
check_sized_sentinel(forward_iterator(&range[0]), forward_iterator(&range[5]), &range[5]);
|
||||
check_sized_sentinel(bidirectional_iterator(&range[0]), bidirectional_iterator(&range[4]), &range[4]);
|
||||
check_sized_sentinel(random_access_iterator(&range[0]), random_access_iterator(&range[3]), &range[3]);
|
||||
check_sized_sentinel(contiguous_iterator(&range[0]), contiguous_iterator(&range[2]), &range[2]);
|
||||
|
||||
check_sentinel(cpp17_input_iterator(&range[0]), cpp17_input_iterator(&range[1]), &range[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);
|
||||
check_sentinel(forward_iterator(&range[0]), forward_iterator(&range[3]), &range[3]);
|
||||
check_sentinel(bidirectional_iterator(&range[0]), bidirectional_iterator(&range[4]), &range[4]);
|
||||
check_sentinel(random_access_iterator(&range[0]), random_access_iterator(&range[5]), &range[5]);
|
||||
check_sentinel(contiguous_iterator(&range[0]), contiguous_iterator(&range[6]), &range[6]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(check_iterator_sentinel());
|
||||
check_iterator_sentinel();
|
||||
static_assert(test());
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
|
@ -11,16 +11,23 @@
|
|||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::prev
|
||||
// Make sure we're SFINAE-friendly when the template argument constraints are not met.
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#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}}
|
||||
}
|
||||
template <class ...Args>
|
||||
concept has_ranges_prev = requires (Args ...args) {
|
||||
{ std::ranges::prev(std::forward<Args>(args)...) };
|
||||
};
|
||||
|
||||
using It = forward_iterator<int*>;
|
||||
static_assert(!has_ranges_prev<It>);
|
||||
static_assert(!has_ranges_prev<It, std::ptrdiff_t>);
|
||||
static_assert(!has_ranges_prev<It, std::ptrdiff_t, It>);
|
||||
|
||||
// Test the test
|
||||
static_assert(has_ranges_prev<int*, std::ptrdiff_t, int*>);
|
|
@ -10,26 +10,31 @@
|
|||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::prev(iterator)
|
||||
// ranges::prev(it)
|
||||
|
||||
#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]));
|
||||
template <class It>
|
||||
constexpr void check() {
|
||||
int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
assert(std::ranges::prev(It(&range[4])) == It(&range[3]));
|
||||
assert(std::ranges::prev(It(&range[5])) == It(&range[4]));
|
||||
assert(std::ranges::prev(It(&range[6])) == It(&range[5]));
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
check<bidirectional_iterator<int*>>();
|
||||
check<random_access_iterator<int*>>();
|
||||
check<contiguous_iterator<int*>>();
|
||||
check<int*>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(check_iterator());
|
||||
check_iterator();
|
||||
static_assert(test());
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,43 +10,48 @@
|
|||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::prev(iterator, count)
|
||||
// ranges::prev(it, n)
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#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 void check(I it, std::ptrdiff_t n, int const* expected) {
|
||||
auto result = std::ranges::prev(stride_counting_iterator(std::move(it)), n);
|
||||
assert(result.base().base() == expected);
|
||||
|
||||
if constexpr (std::random_access_iterator<I>) {
|
||||
assert(result.stride_count() <= 1);
|
||||
// we can't say anything about the stride displacement, cause we could be using -= or +=.
|
||||
} else {
|
||||
auto const distance = n < 0 ? -n : n;
|
||||
assert(result.stride_count() == distance);
|
||||
assert(result.stride_displacement() == -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]);
|
||||
constexpr bool test() {
|
||||
int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
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]);
|
||||
check(bidirectional_iterator(&range[8]), 6, &range[2]);
|
||||
check(random_access_iterator(&range[7]), 4, &range[3]);
|
||||
check(contiguous_iterator(&range[5]), 5, &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]);
|
||||
check(bidirectional_iterator(&range[2]), 0, &range[2]);
|
||||
check(random_access_iterator(&range[3]), 0, &range[3]);
|
||||
check(contiguous_iterator(&range[0]), 0, &range[0]);
|
||||
|
||||
check(bidirectional_iterator(&range[3]), -5, &range[8]);
|
||||
check(random_access_iterator(&range[3]), -3, &range[6]);
|
||||
check(contiguous_iterator(&range[3]), -1, &range[4]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(check_iterator_count());
|
||||
check_iterator_count();
|
||||
static_assert(test());
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,42 +10,60 @@
|
|||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::prev(iterator, count, sentinel)
|
||||
// ranges::prev(it, n, bound)
|
||||
|
||||
#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);
|
||||
template <std::bidirectional_iterator I>
|
||||
constexpr void check(I it, std::ptrdiff_t n, I last) {
|
||||
auto abs = [](auto x) { return x < 0 ? -x : x; };
|
||||
|
||||
{
|
||||
auto result = std::ranges::prev(it, n, last);
|
||||
assert(result == last);
|
||||
}
|
||||
|
||||
// Count the number of operations
|
||||
{
|
||||
stride_counting_iterator strided_it(it), strided_last(last);
|
||||
auto result = std::ranges::prev(strided_it, n, strided_last);
|
||||
assert(result == strided_last);
|
||||
if constexpr (std::random_access_iterator<I>) {
|
||||
if (n == 0 || abs(n) >= abs(last - it)) {
|
||||
assert(result.stride_count() == 0); // uses the assign-from-sentinel codepath
|
||||
} else {
|
||||
assert(result.stride_count() == 1); // uses += exactly once
|
||||
}
|
||||
} else {
|
||||
assert(result.stride_count() == abs(n));
|
||||
assert(result.stride_displacement() == -n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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]));
|
||||
constexpr bool test() {
|
||||
int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
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(bidirectional_iterator(&range[8]), 6, bidirectional_iterator(&range[2]));
|
||||
check(random_access_iterator(&range[5]), 2, random_access_iterator(&range[3]));
|
||||
check(contiguous_iterator(&range[5]), 5, 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]));
|
||||
check(bidirectional_iterator(&range[2]), 0, bidirectional_iterator(&range[2]));
|
||||
check(random_access_iterator(&range[3]), 0, random_access_iterator(&range[3]));
|
||||
check(contiguous_iterator(&range[0]), 0, contiguous_iterator(&range[0]));
|
||||
|
||||
check(bidirectional_iterator(&range[5]), -1, bidirectional_iterator(&range[6]));
|
||||
check(random_access_iterator(&range[5]), -2, random_access_iterator(&range[7]));
|
||||
check(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());
|
||||
static_assert(test());
|
||||
assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// ranges::next
|
||||
// ranges::prev
|
||||
|
||||
#include <iterator>
|
||||
|
||||
|
|
|
@ -729,7 +729,7 @@ public:
|
|||
|
||||
constexpr explicit stride_counting_iterator(I current) : base_(std::move(current)) {}
|
||||
|
||||
[[nodiscard]] constexpr I const& base() const& requires std::copyable<I> { return base_; }
|
||||
[[nodiscard]] constexpr I const& base() const& { return base_; }
|
||||
|
||||
[[nodiscard]] constexpr I base() && { return std::move(base_); }
|
||||
|
||||
|
|
Loading…
Reference in New Issue