
* Guard `std::__make_from_tuple_impl` tests with `#ifdef _LIBCPP_VERSION` and `LIBCPP_STATIC_ASSERT`.
* Change `_LIBCPP_CONSTEXPR_SINCE_CXX20` to `TEST_CONSTEXPR_CXX20`.
+ Other functions in `variant.swap/swap.pass.cpp` were already using the proper test macro.
* Mark `what` as `[[maybe_unused]]` when used by `TEST_LIBCPP_REQUIRE`.
+ This updates one occurrence in `libcxx/test/libcxx` for consistency.
* Windows `_putenv_s()` takes 2 arguments, not 3.
+ See MSVC documentation: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-s-wputenv-s?view=msvc-170
+ POSIX `setenv()` takes `int overwrite`, but Windows `_putenv_s()` always overwrites.
* Avoid non-Standard zero-length arrays.
+ Followup to #74183 and #79792.
* Add `operator++()` to `unsized_it`.
+ The Standard requires this due to [N4981][] [move.iter.requirements]/1 "The template parameter `Iterator` shall
either meet the *Cpp17InputIterator* requirements ([input.iterators])
or model `input_iterator` ([iterator.concept.input])."
+ MSVC's STL requires this because it has a strengthened exception
specification in `move_iterator` that inspects the underlying iterator's
increment operator.
* `uniform_int_distribution` forbids `int8_t`/`uint8_t`.
+ See [N4981][] [rand.req.genl]/1.5. MSVC's STL enforces this.
+ Note that when changing the distribution's `IntType`, we need to be
careful to preserve the original value range of `[0, max_input]`.
* fstreams are constructible from `const fs::path::value_type*` on wide systems.
+ See [ifstream.cons], [ofstream.cons], [fstream.cons].
* In `msvc_stdlib_force_include.h`, map `_HAS_CXX23` to `TEST_STD_VER` 23 instead of 99.
+ On 2023-05-23, 71400505ca
started recognizing 23 as a distinct value.
* Fix test name typo: `destory_elements.pass.cpp` => `destroy_elements.pass.cpp`
[N4981]: https://wg21.link/N4981
326 lines
12 KiB
C++
326 lines
12 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// <algorithm>
|
|
|
|
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
|
// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000
|
|
|
|
// template<forward_iterator I1, sentinel_for<I1> S1,
|
|
// forward_iterator I2, sentinel_for<I2> S2, class Proj = identity>
|
|
// requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
|
|
// constexpr bool ranges::contains_subrange(I1 first1, S1 last1, I2 first2, S2 last2,
|
|
// Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++23
|
|
|
|
// template<forward_range R1, forward_range R2,
|
|
// class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
|
|
// requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
|
|
// constexpr bool ranges::contains_subrange(R1&& r1, R2&& r2, Pred pred = {},
|
|
// Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++23
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cassert>
|
|
#include <concepts>
|
|
#include <ranges>
|
|
#include <utility>
|
|
|
|
#include "almost_satisfies_types.h"
|
|
#include "test_iterators.h"
|
|
|
|
struct NotEqualityComparable {};
|
|
|
|
template <class Iter1, class Sent1 = Iter1, class Iter2 = int*, class Sent2 = Iter2>
|
|
concept HasContainsSubrangeIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) {
|
|
std::ranges::contains_subrange(first1, last1, first2, last2);
|
|
};
|
|
|
|
static_assert(HasContainsSubrangeIt<int*>);
|
|
static_assert(!HasContainsSubrangeIt<ForwardIteratorNotDerivedFrom>);
|
|
static_assert(!HasContainsSubrangeIt<ForwardIteratorNotIncrementable>);
|
|
static_assert(!HasContainsSubrangeIt<int*, SentinelForNotSemiregular>);
|
|
static_assert(!HasContainsSubrangeIt<int*, int*, int**>); // not indirectly comparable
|
|
static_assert(!HasContainsSubrangeIt<int*, SentinelForNotWeaklyEqualityComparableWith>);
|
|
static_assert(!HasContainsSubrangeIt<int*, int*, ForwardIteratorNotDerivedFrom>);
|
|
static_assert(!HasContainsSubrangeIt<int*, int*, ForwardIteratorNotIncrementable>);
|
|
static_assert(!HasContainsSubrangeIt<int*, int*, int*, SentinelForNotSemiregular>);
|
|
static_assert(!HasContainsSubrangeIt<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith>);
|
|
|
|
template <class Range1, class Range2 = UncheckedRange<int*>>
|
|
concept HasContainsSubrangeR = requires(Range1&& range1, Range2&& range2) {
|
|
std::ranges::contains_subrange(std::forward<Range1>(range1), std::forward<Range2>(range2));
|
|
};
|
|
|
|
static_assert(HasContainsSubrangeR<UncheckedRange<int*>>);
|
|
static_assert(!HasContainsSubrangeR<ForwardRangeNotDerivedFrom>);
|
|
static_assert(!HasContainsSubrangeR<ForwardIteratorNotIncrementable>);
|
|
static_assert(!HasContainsSubrangeR<ForwardRangeNotSentinelSemiregular>);
|
|
static_assert(!HasContainsSubrangeR<ForwardRangeNotSentinelEqualityComparableWith>);
|
|
static_assert(!HasContainsSubrangeR<UncheckedRange<int*>, UncheckedRange<int**>>); // not indirectly comparable
|
|
static_assert(!HasContainsSubrangeR<UncheckedRange<int*>, ForwardRangeNotDerivedFrom>);
|
|
static_assert(!HasContainsSubrangeR<UncheckedRange<int*>, ForwardRangeNotIncrementable>);
|
|
static_assert(!HasContainsSubrangeR<UncheckedRange<int*>, ForwardRangeNotSentinelSemiregular>);
|
|
static_assert(!HasContainsSubrangeR<UncheckedRange<int*>, ForwardRangeNotSentinelEqualityComparableWith>);
|
|
|
|
template <class Iter1, class Sent1 = Iter1, class Iter2, class Sent2 = Iter2>
|
|
constexpr void test_iterators() {
|
|
{ // simple tests
|
|
int a[] = {1, 2, 3, 4, 5, 6};
|
|
int p[] = {3, 4, 5};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
std::same_as<bool> decltype(auto) ret =
|
|
std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(ret);
|
|
}
|
|
{
|
|
std::same_as<bool> decltype(auto) ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(ret);
|
|
}
|
|
}
|
|
|
|
{ // no match
|
|
int a[] = {1, 2, 3, 4, 5, 6};
|
|
int p[] = {3, 4, 2};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(!ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(!ret);
|
|
}
|
|
}
|
|
|
|
{ // range consists of just one element
|
|
int a[] = {3};
|
|
int p[] = {3, 4, 2};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(!ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(!ret);
|
|
}
|
|
}
|
|
|
|
{ // subrange consists of just one element
|
|
int a[] = {23, 1, 20, 3, 54, 2};
|
|
int p[] = {3};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(ret);
|
|
}
|
|
}
|
|
|
|
{ // range has zero length
|
|
std::array<int, 0> a = {};
|
|
int p[] = {3, 4, 2};
|
|
auto whole = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data())));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(!ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(!ret);
|
|
}
|
|
}
|
|
|
|
{ // subrange has zero length
|
|
int a[] = {3, 4, 2};
|
|
std::array<int, 0> p = {};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data())));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(ret);
|
|
}
|
|
}
|
|
|
|
{ // range and subrange both have zero length
|
|
std::array<int, 0> a = {};
|
|
std::array<int, 0> p = {};
|
|
auto whole = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data())));
|
|
auto subrange = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data())));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(ret);
|
|
}
|
|
}
|
|
|
|
{ // range and subrange are identical
|
|
int a[] = {3, 4, 11, 32, 54, 2};
|
|
int p[] = {3, 4, 11, 32, 54, 2};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(ret);
|
|
}
|
|
}
|
|
|
|
{ // subrange is longer than range
|
|
int a[] = {3, 4, 2};
|
|
int p[] = {23, 3, 4, 2, 11, 32, 54, 2};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(!ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(!ret);
|
|
}
|
|
}
|
|
|
|
{ // subrange is the prefix
|
|
int a[] = {3, 43, 5, 100, 433, 278, 6457, 900};
|
|
int p[] = {3, 43, 5};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(ret);
|
|
}
|
|
}
|
|
|
|
{ // subrange is the suffix
|
|
int a[] = {3, 43, 5, 7, 68, 100, 433, 900};
|
|
int p[] = {100, 433, 900};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(ret);
|
|
}
|
|
}
|
|
|
|
{ // subrange is a subsequence
|
|
int a[] = {23, 1, 0, 54, 2};
|
|
int p[] = {1, 0, 2};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(!ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(!ret);
|
|
}
|
|
}
|
|
|
|
{ // repeated subrange
|
|
int a[] = {23, 1, 0, 2, 54, 1, 0, 2, 23, 33};
|
|
int p[] = {1, 0, 2};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end());
|
|
assert(ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange);
|
|
assert(ret);
|
|
}
|
|
}
|
|
|
|
{ // check that the predicate is used
|
|
int a[] = {23, 81, 61, 0, 42, 25, 1, 2, 1, 29, 2};
|
|
int p[] = {-1, -2, -1};
|
|
auto pred = [](int l, int r) { return l * -1 == r; };
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole.begin(), whole.end(), subrange.begin(), subrange.end(), pred);
|
|
assert(ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange, pred);
|
|
assert(ret);
|
|
}
|
|
}
|
|
|
|
{ // check that the projections are used
|
|
int a[] = {1, 3, 15, 1, 2, 1, 8};
|
|
int p[] = {2, 1, 2};
|
|
auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(std::end(a))));
|
|
auto subrange = std::ranges::subrange(Iter2(p), Sent2(Iter2(std::end(p))));
|
|
auto proj1 = [](int i) { return i - 3; };
|
|
auto proj2 = [](int i) { return i * -1; };
|
|
{
|
|
bool ret = std::ranges::contains_subrange(
|
|
whole.begin(), whole.end(), subrange.begin(), subrange.end(), {}, proj1, proj2);
|
|
assert(ret);
|
|
}
|
|
{
|
|
bool ret = std::ranges::contains_subrange(whole, subrange, {}, proj1, proj2);
|
|
assert(ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
constexpr bool test() {
|
|
types::for_each(types::forward_iterator_list<int*>{}, []<class Iter1> {
|
|
types::for_each(types::forward_iterator_list<int*>{}, []<class Iter2> {
|
|
test_iterators<Iter1, Iter1, Iter2, Iter2>();
|
|
test_iterators<Iter1, Iter1, Iter2, sized_sentinel<Iter2>>();
|
|
test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, Iter2>();
|
|
test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, sized_sentinel<Iter2>>();
|
|
});
|
|
});
|
|
|
|
assert(std::ranges::contains_subrange(
|
|
std::views::iota(0, 5), std::views::iota(0, 5) | std::views::filter([](int) { return true; })));
|
|
assert(!std::ranges::contains_subrange(std::views::iota(0ULL, 42ULL), std::views::iota(0ULL, 1ULL << 32)));
|
|
|
|
return true;
|
|
}
|
|
|
|
int main(int, char**) {
|
|
test();
|
|
static_assert(test());
|
|
|
|
return 0;
|
|
}
|