]>
Commit | Line | Data |
---|---|---|
a945c346 | 1 | // Copyright (C) 2018-2024 Free Software Foundation, Inc. |
dfaa3c47 JW |
2 | // |
3 | // This file is part of the GNU ISO C++ Library. This library is free | |
4 | // software; you can redistribute it and/or modify it under the | |
5 | // terms of the GNU General Public License as published by the | |
6 | // Free Software Foundation; either version 3, or (at your option) | |
7 | // any later version. | |
8 | ||
9 | // This library is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | ||
14 | // You should have received a copy of the GNU General Public License along | |
15 | // with this library; see the file COPYING3. If not see | |
16 | // <http://www.gnu.org/licenses/>. | |
17 | ||
dfaa3c47 | 18 | // { dg-do run { target c++17 } } |
49ba2588 | 19 | // { dg-require-cstdint "" } |
dfaa3c47 JW |
20 | |
21 | #include <memory_resource> | |
22 | #include <testsuite_allocator.h> | |
23 | ||
24 | void | |
25 | test01() | |
26 | { | |
27 | __gnu_test::memory_resource r; | |
28 | ||
29 | // test that it's possible to allocate after each of the constructors | |
30 | { | |
31 | std::pmr::monotonic_buffer_resource mr(&r); | |
32 | auto p = mr.allocate(1024); | |
33 | VERIFY( p != nullptr ); | |
34 | auto q = mr.allocate(1024); | |
35 | VERIFY( q != nullptr ); | |
36 | VERIFY( p != q ); | |
37 | } | |
38 | VERIFY( r.number_of_active_allocations() == 0 ); | |
39 | { | |
40 | std::pmr::monotonic_buffer_resource mr(128, &r); | |
41 | auto p = mr.allocate(1024); | |
42 | VERIFY( p != nullptr ); | |
43 | auto q = mr.allocate(1024); | |
44 | VERIFY( q != nullptr ); | |
45 | VERIFY( p != q ); | |
46 | } | |
47 | VERIFY( r.number_of_active_allocations() == 0 ); | |
48 | { | |
49 | unsigned char buf[64]; | |
50 | std::pmr::monotonic_buffer_resource mr((void*)buf, sizeof(buf), &r); | |
51 | auto p = mr.allocate(1024); | |
52 | VERIFY( p != nullptr ); | |
53 | auto q = mr.allocate(1024); | |
54 | VERIFY( q != nullptr ); | |
55 | VERIFY( p != q ); | |
56 | } | |
57 | VERIFY( r.number_of_active_allocations() == 0 ); | |
58 | { | |
59 | std::pmr::monotonic_buffer_resource mr; | |
60 | auto p = mr.allocate(1024); | |
61 | VERIFY( p != nullptr ); | |
62 | auto q = mr.allocate(1024); | |
63 | VERIFY( q != nullptr ); | |
64 | VERIFY( p != q ); | |
65 | } | |
66 | { | |
67 | std::pmr::monotonic_buffer_resource mr(64); | |
68 | auto p = mr.allocate(1024); | |
69 | VERIFY( p != nullptr ); | |
70 | auto q = mr.allocate(1024); | |
71 | VERIFY( q != nullptr ); | |
72 | VERIFY( p != q ); | |
73 | } | |
74 | { | |
75 | unsigned char buf[64]; | |
76 | std::pmr::monotonic_buffer_resource mr((void*)buf, sizeof(buf)); | |
77 | auto p = mr.allocate(1024); | |
78 | VERIFY( p != nullptr ); | |
79 | auto q = mr.allocate(1024); | |
80 | VERIFY( q != nullptr ); | |
81 | VERIFY( p != q ); | |
82 | } | |
83 | } | |
84 | ||
85 | void | |
86 | test02() | |
87 | { | |
88 | unsigned char buf[64]; | |
89 | std::pmr::monotonic_buffer_resource mr(buf, sizeof(buf)); | |
90 | ||
91 | auto p = mr.allocate(0); | |
92 | VERIFY( p != nullptr ); | |
93 | auto q = mr.allocate(0); | |
94 | VERIFY( q != nullptr ); | |
95 | VERIFY( p != q ); | |
96 | ||
97 | p = mr.allocate(0, 1); | |
98 | VERIFY( p != nullptr ); | |
99 | q = mr.allocate(0, 1); | |
100 | VERIFY( q != nullptr ); | |
101 | VERIFY( p != q ); | |
102 | } | |
103 | ||
104 | void | |
105 | test03() | |
106 | { | |
107 | #if __cpp_exceptions | |
108 | { | |
109 | std::pmr::monotonic_buffer_resource mr(std::pmr::null_memory_resource()); | |
110 | bool caught = false; | |
111 | try | |
112 | { | |
113 | (void) mr.allocate(1, 1); | |
114 | } | |
115 | catch (const std::bad_alloc&) | |
116 | { | |
117 | caught = true; | |
118 | } | |
119 | VERIFY( caught ); | |
120 | } | |
121 | { | |
122 | unsigned char buf[16]; | |
123 | std::pmr::monotonic_buffer_resource mr(buf, sizeof(buf), | |
124 | std::pmr::null_memory_resource()); | |
125 | (void) mr.allocate(16, 1); | |
126 | bool caught = false; | |
127 | try | |
128 | { | |
129 | (void) mr.allocate(1, 1); | |
130 | } | |
131 | catch (const std::bad_alloc&) | |
132 | { | |
133 | caught = true; | |
134 | } | |
135 | VERIFY( caught ); | |
136 | } | |
137 | #endif | |
138 | } | |
139 | ||
140 | void | |
141 | test04() | |
142 | { | |
143 | auto buf = new unsigned char[512]; | |
144 | std::pmr::monotonic_buffer_resource mr(buf, 512, | |
145 | std::pmr::null_memory_resource()); | |
146 | std::size_t prev_size = 1; | |
147 | void* prev_ptr = mr.allocate(prev_size, 1); | |
148 | for (int i = 0; i < 9; ++i) | |
149 | { | |
150 | std::size_t size = 1 << i; | |
151 | void* ptr = mr.allocate(size, 1); | |
13feb023 | 152 | VERIFY( std::size_t((char*)ptr - (char*)prev_ptr) == prev_size ); |
dfaa3c47 JW |
153 | prev_ptr = ptr; |
154 | prev_size = size; | |
155 | } | |
156 | } | |
157 | ||
158 | void | |
159 | test05() | |
160 | { | |
161 | // test that returned pointer is correctly aligned | |
162 | auto is_aligned = [](void* p, size_t alignment) -> bool { | |
163 | return (reinterpret_cast<std::uintptr_t>(p) % alignment) == 0; | |
164 | }; | |
165 | ||
166 | auto buf = new unsigned char[2048]; | |
167 | std::pmr::monotonic_buffer_resource mr(buf+1, 2047); | |
168 | for (int i = 0; i < 9; ++i) | |
169 | { | |
170 | auto p = mr.allocate(1, 1 << i); | |
171 | VERIFY( is_aligned(p, 1 << i) ); | |
172 | // Make next available byte misaligned: | |
173 | (void) mr.allocate(1 << i, 1); | |
174 | } | |
175 | } | |
176 | ||
177 | void | |
178 | test06() | |
179 | { | |
180 | // check for geometric progression in buffer sizes from upstream | |
181 | ||
182 | struct resource : __gnu_test::memory_resource | |
183 | { | |
184 | bool allocated = false; | |
185 | std::size_t last_size = 0; | |
186 | ||
187 | void* | |
188 | do_allocate(size_t bytes, size_t align) override | |
189 | { | |
190 | allocated = true; | |
191 | last_size = bytes; | |
192 | return __gnu_test::memory_resource::do_allocate(bytes, align); | |
193 | } | |
194 | }; | |
195 | ||
196 | resource r; | |
197 | std::pmr::monotonic_buffer_resource mr(32, &r); | |
198 | std::size_t last_size = 0; | |
199 | ||
200 | for (int i = 0; i < 100; ++i) | |
201 | { | |
202 | (void) mr.allocate(16); | |
203 | if (r.allocated) | |
204 | { | |
205 | VERIFY(r.last_size >= last_size); | |
206 | last_size = r.last_size; | |
207 | r.allocated = false; | |
208 | } | |
209 | } | |
210 | } | |
211 | ||
1e718ec5 JW |
212 | void |
213 | test07() | |
214 | { | |
215 | // Custom exception thrown on expected allocation failure. | |
216 | struct very_bad_alloc : std::bad_alloc { }; | |
217 | ||
218 | struct careful_resource : __gnu_test::memory_resource | |
219 | { | |
220 | void* do_allocate(std::size_t bytes, std::size_t alignment) | |
221 | { | |
222 | // pmr::monotonic_buffer_resource::do_allocate is not allowed to | |
223 | // throw an exception when asked for an allocation it can't satisfy. | |
224 | // The libstdc++ implementation will ask upstream to allocate | |
225 | // bytes=SIZE_MAX and alignment=bit_floor(SIZE_MAX) instead of throwing. | |
226 | // Verify that we got those values: | |
227 | if (bytes != std::numeric_limits<std::size_t>::max()) | |
228 | VERIFY( !"upstream allocation should request maximum number of bytes" ); | |
229 | if (alignment != (1 + std::numeric_limits<std::size_t>::max() / 2)) | |
230 | VERIFY( !"upstream allocation should request maximum alignment" ); | |
231 | ||
232 | // A successful failure: | |
233 | throw very_bad_alloc(); | |
234 | } | |
235 | }; | |
236 | ||
237 | careful_resource cr; | |
238 | std::pmr::monotonic_buffer_resource mbr(&cr); | |
239 | try | |
240 | { | |
b0224734 JW |
241 | #pragma GCC diagnostic push |
242 | #pragma GCC diagnostic ignored "-Walloc-size-larger-than=" | |
1e718ec5 JW |
243 | // Try to allocate a ridiculous size: |
244 | void* p = mbr.allocate(std::size_t(-2), 1); | |
b0224734 | 245 | #pragma GCC diagnostic pop |
1e718ec5 JW |
246 | // Should not reach here! |
247 | VERIFY( !"attempt to allocate SIZE_MAX-1 should not have succeeded" ); | |
248 | throw p; | |
249 | } | |
250 | catch (const very_bad_alloc&) | |
251 | { | |
252 | // Should catch this exception from careful_resource::do_allocate | |
253 | } | |
254 | catch (const std::bad_alloc&) | |
255 | { | |
256 | VERIFY( !"monotonic_buffer_resource::do_allocate is not allowed to throw" ); | |
257 | } | |
258 | } | |
259 | ||
dfaa3c47 JW |
260 | int |
261 | main() | |
262 | { | |
263 | test01(); | |
264 | test02(); | |
265 | test03(); | |
266 | test04(); | |
267 | test05(); | |
268 | test06(); | |
1e718ec5 | 269 | test07(); |
dfaa3c47 | 270 | } |