//===----------------------------------------------------------------------===//
//
// 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
// <algorithm>
// These tests checks that `std::copy` and `std::move` (including their variations like `copy_n`) can unwrap multiple
// layers of reverse iterators.
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <iterator>
#include <ranges>
#include <type_traits>
#include "test_iterators.h"
template <std::size_t N, class Iter>
requires (N == 0)
constexpr auto wrap_n_times(Iter i) {
return i;
}
template <std::size_t N, class Iter>
requires (N != 0)
constexpr auto wrap_n_times(Iter i) {
return std::make_reverse_iterator(wrap_n_times<N - 1>(i));
}
static_assert(std::is_same_v<decltype(wrap_n_times<2>(std::declval<int*>())),
std::reverse_iterator<std::reverse_iterator<int*>>>);
template <class InIter, template <class> class SentWrapper, class OutIter, std::size_t W1, size_t W2, class Func>
constexpr void test_one(Func func) {
using From = std::iter_value_t<InIter>;
using To = std::iter_value_t<OutIter>;
const std::size_t N = 4;
From input[N] = {{1}, {2}, {3}, {4}};
To output[N];
auto in = wrap_n_times<W1>(InIter(input));
auto in_end = wrap_n_times<W1>(InIter(input + N));
auto sent = SentWrapper<decltype(in_end)>(in_end);
auto out = wrap_n_times<W2>(OutIter(output));
func(in, sent, out, N);
assert(std::equal(input, input + N, output, [](const From& lhs, const To& rhs) {
// Prevents warnings/errors due to mismatched signed-ness.
return lhs == static_cast<From>(rhs);
}));
}
template <class InIter, template <class> class SentWrapper, class OutIter, std::size_t W1, size_t W2>
constexpr void test_copy_and_move() {
// Classic.
if constexpr (std::same_as<InIter, SentWrapper<InIter>>) {
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t) {
std::copy(first, last, out);
});
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t n) {
std::copy_backward(first, last, out + n);
});
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto, auto out, std::size_t n) {
std::copy_n(first, n, out);
});
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t) {
std::move(first, last, out);
});
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t n) {
std::move_backward(first, last, out + n);
});
}
// Ranges.
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t) {
std::ranges::copy(first, last, out);
});
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t n) {
std::ranges::copy_backward(first, last, out + n);
});
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto, auto out, std::size_t n) {
std::ranges::copy_n(first, n, out);
});
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t) {
std::ranges::move(first, last, out);
});
test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t n) {
std::ranges::move_backward(first, last, out + n);
});
}
template <std::size_t W1, size_t W2, class From, class To, template <class> class SentWrapper>
constexpr void test_all_permutations_with_counts_from_to_sent() {
test_copy_and_move<From*, SentWrapper, To*, W1, W2>();
test_copy_and_move<contiguous_iterator<From*>, SentWrapper, To*, W1, W2>();
test_copy_and_move<From*, SentWrapper, contiguous_iterator<To*>, W1, W2>();
test_copy_and_move<contiguous_iterator<From*>, SentWrapper, contiguous_iterator<To*>, W1, W2>();
if (!std::same_as<From, To>) {
test_copy_and_move<To*, SentWrapper, From*, W1, W2>();
test_copy_and_move<contiguous_iterator<To*>, SentWrapper, From*, W1, W2>();
test_copy_and_move<To*, SentWrapper, contiguous_iterator<From*>, W1, W2>();
test_copy_and_move<contiguous_iterator<To*>, SentWrapper, contiguous_iterator<From*>, W1, W2>();
}
}
template <std::size_t W1, size_t W2>
constexpr void test_all_permutations_with_counts() {
test_all_permutations_with_counts_from_to_sent<W1, W2, int, int, std::type_identity_t>();
test_all_permutations_with_counts_from_to_sent<W1, W2, int, int, sized_sentinel>();
test_all_permutations_with_counts_from_to_sent<W1, W2, std::int32_t, std::uint32_t, std::type_identity_t>();
test_all_permutations_with_counts_from_to_sent<W1, W2, std::int32_t, std::uint32_t, sized_sentinel>();
}
constexpr bool test() {
test_all_permutations_with_counts<0, 0>();
test_all_permutations_with_counts<0, 2>();
test_all_permutations_with_counts<2, 0>();
test_all_permutations_with_counts<2, 2>();
test_all_permutations_with_counts<2, 4>();
test_all_permutations_with_counts<4, 4>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}