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 | // <forward_list> |
10 | |
11 | // UNSUPPORTED: c++03, no-exceptions |
12 | |
13 | // TODO: |
14 | // - throwing upon moving; |
15 | // - initializer lists; |
16 | // - throwing when constructing the element in place. |
17 | |
18 | // forward_list(size_type n, const value_type& v); |
19 | // forward_list(size_type n, const value_type& v, const allocator_type& a); |
20 | // template <class InputIterator> |
21 | // forward_list(InputIterator first, InputIterator last); |
22 | // template <class InputIterator> |
23 | // forward_list(InputIterator first, InputIterator last, const allocator_type& a); |
24 | // forward_list(const forward_list& x); |
25 | // forward_list(const forward_list& x, const allocator_type& a); |
26 | // template<container-compatible-range<T> R> |
27 | // forward_list(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23 |
28 | // |
29 | // forward_list& operator=(const forward_list& x); |
30 | // |
31 | // template <class InputIterator> |
32 | // void assign(InputIterator first, InputIterator last); |
33 | // void assign(size_type n, const value_type& v); |
34 | // template<container-compatible-range<T> R> |
35 | // void assign_range(R&& rg); // C++23 |
36 | // |
37 | // void push_front(const value_type& v); |
38 | // template <class... Args> reference emplace_front(Args&&... args); // reference in C++17 |
39 | // template<container-compatible-range<T> R> |
40 | // void prepend_range(R&& rg); // C++23 |
41 | // |
42 | // iterator insert_after(const_iterator p, const value_type& v); |
43 | // iterator insert_after(const_iterator p, value_type&& v); |
44 | // iterator insert_after(const_iterator p, size_type n, const value_type& v); |
45 | // iterator insert_after(const_iterator p, initializer_list<value_type> il); |
46 | // template <class InputIterator> |
47 | // iterator insert_after(const_iterator p, |
48 | // InputIterator first, InputIterator last); |
49 | // template<container-compatible-range<T> R> |
50 | // iterator insert_range_after(const_iterator position, R&& rg); // C++23 |
51 | // template <class... Args> |
52 | // iterator emplace_after(const_iterator p, Args&&... args); |
53 | // void resize(size_type n, const value_type& v); |
54 | // void resize(size_type n); |
55 | |
56 | #include <forward_list> |
57 | |
58 | #include <cassert> |
59 | #include "../../exception_safety_helpers.h" |
60 | #include "test_macros.h" |
61 | |
62 | #if TEST_STD_VER >= 23 |
63 | # include <ranges> |
64 | #endif |
65 | |
66 | int main(int, char**) { |
67 | { |
68 | constexpr int ThrowOn = 1; |
69 | constexpr int Size = 1; |
70 | using T = ThrowingCopy<ThrowOn>; |
71 | |
72 | // void push_front(const value_type& v); |
73 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [](std::forward_list<T>& c, T* from, T*) { |
74 | c.push_front(val: *from); |
75 | }); |
76 | |
77 | // template <class... Args> reference emplace_front(Args&&... args); |
78 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [](std::forward_list<T>& c, T* from, T*) { |
79 | c.push_front(val: *from); |
80 | }); |
81 | |
82 | // iterator insert_after(const_iterator p, const value_type& v); |
83 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [](std::forward_list<T>& c, T* from, T*) { |
84 | c.insert_after(pos: c.before_begin(), val: *from); |
85 | }); |
86 | |
87 | // iterator insert_after(const_iterator p, value_type&& v); |
88 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [](std::forward_list<T>& c, T* from, T*) { |
89 | c.insert_after(pos: c.before_begin(), val: std::move(*from)); |
90 | }); |
91 | |
92 | // template <class... Args> |
93 | // iterator emplace_after(const_iterator p, Args&&... args); |
94 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [](std::forward_list<T>& c, T* from, T*) { |
95 | c.emplace_after(pos: c.before_begin(), args&: *from); |
96 | }); |
97 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [](std::forward_list<T>& c, T* from, T*) { |
98 | c.emplace_after(pos: c.before_begin(), args: std::move(*from)); |
99 | }); |
100 | } |
101 | |
102 | { |
103 | constexpr int ThrowOn = 3; |
104 | constexpr int Size = 5; |
105 | using T = ThrowingCopy<ThrowOn>; |
106 | using C = std::forward_list<T>; |
107 | using Alloc = std::allocator<T>; |
108 | |
109 | // forward_list(size_type n, const value_type& v); |
110 | test_exception_safety_throwing_copy<ThrowOn, Size>(func: [](T* from, T*) { |
111 | std::forward_list<T> c(Size, *from); |
112 | (void)c; |
113 | }); |
114 | |
115 | // forward_list(size_type n, const value_type& v, const allocator_type& a); |
116 | test_exception_safety_throwing_copy<ThrowOn, Size>(func: [](T* from, T*) { |
117 | std::forward_list<T> c(Size, *from, Alloc()); |
118 | (void)c; |
119 | }); |
120 | |
121 | // template <class InputIterator> |
122 | // forward_list(InputIterator first, InputIterator last); |
123 | test_exception_safety_throwing_copy<ThrowOn, Size>(func: [](T* from, T* to) { |
124 | std::forward_list<T> c(from, to); |
125 | (void)c; |
126 | }); |
127 | |
128 | #if TEST_STD_VER >= 23 |
129 | // template<container-compatible-range<T> R> |
130 | // forward_list(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23 |
131 | test_exception_safety_throwing_copy<ThrowOn, Size>([](T* from, T* to) { |
132 | { |
133 | std::forward_list<T> c(std::from_range, std::ranges::subrange(from, to)); |
134 | (void)c; |
135 | } |
136 | |
137 | { |
138 | std::forward_list<T> c(std::from_range, std::ranges::subrange(from, to), Alloc()); |
139 | (void)c; |
140 | } |
141 | }); |
142 | #endif |
143 | |
144 | // template <class InputIterator> |
145 | // forward_list(InputIterator first, InputIterator last, const allocator_type& a); |
146 | test_exception_safety_throwing_copy<ThrowOn, Size>(func: [](T* from, T* to) { |
147 | std::forward_list<T> c(from, to, Alloc()); |
148 | (void)c; |
149 | }); |
150 | |
151 | // forward_list(const forward_list& x); |
152 | test_exception_safety_throwing_copy_container<C, ThrowOn, Size>(func: [](C&& in) { |
153 | std::forward_list<T> c(in); |
154 | (void)c; |
155 | }); |
156 | |
157 | // forward_list(const forward_list& x, const allocator_type& a); |
158 | test_exception_safety_throwing_copy_container<C, ThrowOn, Size>(func: [](C&& in) { |
159 | std::forward_list<T> c(in, Alloc()); |
160 | (void)c; |
161 | }); |
162 | |
163 | // forward_list& operator=(const forward_list& x); |
164 | test_exception_safety_throwing_copy_container<C, ThrowOn, Size>(func: [](C&& in) { |
165 | std::forward_list<T> c; |
166 | c = in; |
167 | }); |
168 | |
169 | // template <class InputIterator> |
170 | // void assign(InputIterator first, InputIterator last); |
171 | test_exception_safety_throwing_copy<ThrowOn, Size>(func: [](T* from, T* to) { |
172 | std::forward_list<T> c; |
173 | c.assign(first: from, last: to); |
174 | }); |
175 | |
176 | #if TEST_STD_VER >= 23 |
177 | // template<container-compatible-range<T> R> |
178 | // void assign_range(R&& rg); // C++23 |
179 | test_exception_safety_throwing_copy<ThrowOn, Size>([](T* from, T* to) { |
180 | std::forward_list<T> c; |
181 | c.assign_range(std::ranges::subrange(from, to)); |
182 | }); |
183 | #endif |
184 | |
185 | // void assign(size_type n, const value_type& v); |
186 | test_exception_safety_throwing_copy<ThrowOn, Size>(func: [](T* from, T*) { |
187 | std::forward_list<T> c; |
188 | c.assign(n: Size, val: *from); |
189 | }); |
190 | |
191 | #if TEST_STD_VER >= 23 |
192 | // template<container-compatible-range<T> R> |
193 | // void prepend_range(R&& rg); // C++23 |
194 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>([](std::forward_list<T>& c, T* from, T* to) { |
195 | c.prepend_range(std::ranges::subrange(from, to)); |
196 | }); |
197 | #endif |
198 | |
199 | // iterator insert_after(const_iterator p, size_type n, const value_type& v); |
200 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [](std::forward_list<T>& c, T* from, T*) { |
201 | c.insert_after(pos: c.before_begin(), n: Size, val: *from); |
202 | }); |
203 | |
204 | // template <class InputIterator> |
205 | // iterator insert_after(const_iterator p, |
206 | // InputIterator first, InputIterator last); |
207 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [](std::forward_list<T>& c, T* from, T* to) { |
208 | c.insert_after(pos: c.before_begin(), first: from, last: to); |
209 | }); |
210 | |
211 | // iterator insert_after(const_iterator p, initializer_list<value_type> il); |
212 | std::initializer_list<T> il{1, 2, 3, 4, 5}; |
213 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [&](std::forward_list<T>& c, T*, T*) { |
214 | c.insert_after(pos: c.before_begin(), il: il); |
215 | }); |
216 | |
217 | #if TEST_STD_VER >= 23 |
218 | // template<container-compatible-range<T> R> |
219 | // iterator insert_range_after(const_iterator position, R&& rg); // C++23 |
220 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>([](std::forward_list<T>& c, T* from, T* to) { |
221 | c.insert_range_after(c.before_begin(), std::ranges::subrange(from, to)); |
222 | }); |
223 | #endif |
224 | |
225 | // void resize(size_type n, const value_type& v); |
226 | test_strong_exception_safety_throwing_copy<ThrowOn, Size>(func: [](std::forward_list<T>& c, T* from, T*) { |
227 | c.resize(sz: Size * 3, val: *from); |
228 | }); |
229 | |
230 | { // void resize(size_type n); |
231 | using X = ThrowingDefault<ThrowOn>; |
232 | std::forward_list<X> c0{X{1}, X{2}, X{3}}; |
233 | std::forward_list<X> c = c0; |
234 | try { |
235 | c.resize(sz: 3 * ThrowOn); |
236 | assert(false); |
237 | } catch (int) { |
238 | assert(c == c0); |
239 | } |
240 | } |
241 | } |
242 | |
243 | return 0; |
244 | } |
245 | |