1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H
10#define SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H
11
12#include <algorithm>
13#include <array>
14#include <cassert>
15#include <cstddef>
16#include <iterator>
17#include <ranges>
18#include <utility>
19
20#include "../exception_safety_helpers.h"
21#include "../from_range_helpers.h"
22#include "MoveOnly.h"
23#include "almost_satisfies_types.h"
24#include "count_new.h"
25#include "test_iterators.h"
26#include "test_macros.h"
27
28template <class T>
29concept HasSize = requires(const T& value) { value.size(); };
30
31template <class Container, class Range>
32concept HasFromRangeCtr = requires(Range&& range) {
33 Container(std::from_range, std::forward<Range>(range));
34 Container(std::from_range, std::forward<Range>(range), std::allocator<typename Container::value_type>());
35};
36
37template <template <class...> class Container, class T, class U>
38constexpr bool test_constraints() {
39 // Input range with the same value type.
40 static_assert(HasFromRangeCtr<Container<T>, InputRange<T>>);
41 // Input range with a convertible value type.
42 static_assert(HasFromRangeCtr<Container<T>, InputRange<U>>);
43 // Input range with a non-convertible value type.
44 static_assert(!HasFromRangeCtr<Container<T>, InputRange<Empty>>);
45 // Not an input range.
46 static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotDerivedFrom>);
47 static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotIndirectlyReadable>);
48 static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotInputOrOutputIterator>);
49
50 // Note: there are no constraints on the allocator (it's not a separate template type of the constructor)`.
51
52 return true;
53}
54
55// Note: `std::array` is used to avoid dealing with `vector<bool>`.
56template <template <class...> class Container,
57 class T,
58 class Iter,
59 class Sent,
60 class Alloc,
61 std::size_t N,
62 class ValidateFunc>
63constexpr void test_sequence_container_with_input(std::array<T, N>&& input, ValidateFunc validate) {
64 { // (range)
65 auto in = wrap_input<Iter, Sent>(input);
66 Container<T> c(std::from_range, in);
67
68 if constexpr (HasSize<Container<T>>) {
69 assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
70 }
71 assert(std::ranges::equal(input, c));
72 validate(c);
73 }
74
75 { // (range, allocator)
76 auto in = wrap_input<Iter, Sent>(input);
77 Alloc alloc;
78 Container<T, Alloc> c(std::from_range, in, alloc);
79
80 assert(c.get_allocator() == alloc);
81 if constexpr (HasSize<Container<T, Alloc>>) {
82 assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
83 }
84 assert(std::ranges::equal(input, c));
85 validate(c);
86 }
87}
88
89template <template <class...> class Container, class T, class Iter, class Sent, class Alloc, class ValidateFunc>
90constexpr void test_sequence_container(ValidateFunc validate) {
91 // Normal input.
92 test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array{0, 5, 12, 7, -1, 8, 26}, validate);
93 // Empty input.
94 test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array<int, 0>{}, validate);
95 // Single-element input.
96 test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array{5}, validate);
97}
98
99template <template <class...> class Container>
100constexpr void test_sequence_container_move_only() {
101 MoveOnly input[5];
102 std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
103
104 [[maybe_unused]] Container<MoveOnly> c(std::from_range, in);
105}
106
107template <class Iter, class Sent, class Alloc, class ValidateFunc>
108constexpr void test_vector_bool(ValidateFunc validate) {
109 // Normal input.
110 test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(
111 std::array{true, false, false, true, false, true, true, true, false, true}, validate);
112 // Empty input.
113 test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(std::array<bool, 0>{}, validate);
114 // Single-element input.
115 test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(std::array{true}, validate);
116}
117
118template <template <class...> class Container>
119void test_exception_safety_throwing_copy() {
120#if !defined(TEST_HAS_NO_EXCEPTIONS)
121 constexpr int ThrowOn = 3;
122 using T = ThrowingCopy<ThrowOn>;
123 test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {
124 [[maybe_unused]] Container<T> c(std::from_range, std::ranges::subrange(from, to));
125 });
126#endif
127}
128
129template <template <class...> class Container, class T>
130void test_exception_safety_throwing_allocator() {
131#if !defined(TEST_HAS_NO_EXCEPTIONS)
132 T in[] = {0, 1};
133
134 try {
135 ThrowingAllocator<T> alloc;
136
137 globalMemCounter.reset();
138 Container<T, ThrowingAllocator<T>> c(std::from_range, in, alloc);
139 assert(false); // The constructor call above should throw.
140
141 } catch (int) {
142 assert(globalMemCounter.new_called == globalMemCounter.delete_called);
143 }
144#endif
145}
146
147#endif // SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H
148

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of libcxx/test/std/containers/sequences/from_range_sequence_containers.h