1/*
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * https://www.boost.org/LICENSE_1_0.txt)
5 *
6 * Copyright (c) 2023-2024 Andrey Semashev
7 */
8/*!
9 * \file unique_resource.cpp
10 * \author Andrey Semashev
11 *
12 * \brief This file contains tests for \c unique_resource.
13 */
14
15#include <boost/scope/unique_resource.hpp>
16#include <boost/core/lightweight_test.hpp>
17#include <boost/core/lightweight_test_trait.hpp>
18#include <boost/config.hpp>
19#include <ostream>
20#include <utility>
21#include <stdexcept>
22#include <type_traits>
23
24template< typename Resource >
25struct empty_resource_deleter
26{
27 void operator() (Resource const&) const noexcept
28 {
29 }
30};
31
32template< typename Resource >
33inline void copy_resource(Resource const& from, Resource& to)
34{
35 to = from;
36}
37
38template< typename Resource >
39class checking_resource_deleter
40{
41private:
42 Resource* m_deleted;
43 int& m_n;
44
45public:
46 explicit checking_resource_deleter(int& n) noexcept :
47 m_deleted(nullptr),
48 m_n(n)
49 {
50 }
51
52 explicit checking_resource_deleter(Resource& deleted, int& n) noexcept :
53 m_deleted(&deleted),
54 m_n(n)
55 {
56 }
57
58 checking_resource_deleter(checking_resource_deleter&& that) noexcept :
59 m_deleted(that.m_deleted),
60 m_n(that.m_n)
61 {
62 }
63
64 checking_resource_deleter(checking_resource_deleter const& that) noexcept :
65 m_deleted(that.m_deleted),
66 m_n(that.m_n)
67 {
68 }
69
70 // Make sure the deleter is move and copy-assignable
71 checking_resource_deleter& operator= (checking_resource_deleter&& that) noexcept
72 {
73 m_deleted = that.m_deleted;
74 return *this;
75 }
76
77 checking_resource_deleter& operator= (checking_resource_deleter const& that) noexcept
78 {
79 m_deleted = that.m_deleted;
80 return *this;
81 }
82
83 Resource* get_deleted() const noexcept
84 {
85 return m_deleted;
86 }
87
88 void operator() (Resource const& res) const noexcept
89 {
90 if (m_deleted)
91 copy_resource(res, *m_deleted);
92 ++m_n;
93 }
94};
95
96int g_n = 0, g_res1 = 0, g_res2 = 0;
97
98void check_int()
99{
100 {
101 boost::scope::unique_resource< int, empty_resource_deleter< int > > ur;
102 BOOST_TEST_EQ(ur.get(), 0);
103 BOOST_TEST(!ur.allocated());
104 BOOST_TEST(!ur);
105 }
106
107 int n = 0;
108 {
109 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur{ boost::scope::default_resource, checking_resource_deleter< int >(n) };
110 BOOST_TEST_EQ(ur.get(), 0);
111 BOOST_TEST(!ur.allocated());
112 BOOST_TEST(!ur);
113 }
114 BOOST_TEST_EQ(n, 0);
115
116 {
117 boost::scope::unique_resource< int, empty_resource_deleter< int > > ur{ 10 };
118 BOOST_TEST_EQ(ur.get(), 10);
119 BOOST_TEST(ur.allocated());
120 BOOST_TEST(!!ur);
121 }
122
123 int deleted_res1 = -1;
124 n = 0;
125 {
126 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur{ 0, checking_resource_deleter< int >(deleted_res1, n) };
127 BOOST_TEST_EQ(ur.get(), 0);
128 BOOST_TEST(ur.allocated());
129 }
130 BOOST_TEST_EQ(n, 1);
131 BOOST_TEST_EQ(deleted_res1, 0);
132
133 n = 0;
134 deleted_res1 = -1;
135 {
136 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur{ 10, checking_resource_deleter< int >(deleted_res1, n) };
137 BOOST_TEST_EQ(ur.get(), 10);
138 BOOST_TEST(ur.allocated());
139 BOOST_TEST_EQ(ur.get_deleter().get_deleted(), &deleted_res1);
140 }
141 BOOST_TEST_EQ(n, 1);
142 BOOST_TEST_EQ(deleted_res1, 10);
143
144 n = 0;
145 deleted_res1 = -1;
146 {
147 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur{ 10, checking_resource_deleter< int >(deleted_res1, n) };
148 BOOST_TEST_EQ(ur.get(), 10);
149 BOOST_TEST(ur.allocated());
150 ur.release();
151 BOOST_TEST(!ur.allocated());
152 }
153 BOOST_TEST_EQ(n, 0);
154 BOOST_TEST_EQ(deleted_res1, -1);
155
156 n = 0;
157 deleted_res1 = -1;
158 {
159 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur{ 10, checking_resource_deleter< int >(deleted_res1, n) };
160 BOOST_TEST_EQ(ur.get(), 10);
161 BOOST_TEST(ur.allocated());
162 BOOST_TEST_EQ(noexcept(ur.reset()), noexcept(std::declval< checking_resource_deleter< int >& >()(10)));
163 ur.reset();
164 BOOST_TEST(!ur.allocated());
165 BOOST_TEST_EQ(n, 1);
166 BOOST_TEST_EQ(deleted_res1, 10);
167 }
168 BOOST_TEST_EQ(n, 1);
169
170 n = 0;
171 deleted_res1 = -1;
172 {
173 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur{ 10, checking_resource_deleter< int >(deleted_res1, n) };
174 BOOST_TEST_EQ(ur.get(), 10);
175 BOOST_TEST(ur.allocated());
176 ur.reset(res: 20);
177 BOOST_TEST_EQ(n, 1);
178 BOOST_TEST_EQ(deleted_res1, 10);
179 deleted_res1 = -1;
180 BOOST_TEST_EQ(ur.get(), 20);
181 BOOST_TEST(ur.allocated());
182 }
183 BOOST_TEST_EQ(n, 2);
184 BOOST_TEST_EQ(deleted_res1, 20);
185
186 n = 0;
187 deleted_res1 = -1;
188 {
189 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur1{ 10, checking_resource_deleter< int >(deleted_res1, n) };
190 BOOST_TEST_EQ(ur1.get(), 10);
191 BOOST_TEST(ur1.allocated());
192 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur2{ std::move(ur1) };
193 BOOST_TEST_EQ(ur2.get(), 10);
194 BOOST_TEST(ur2.allocated());
195 BOOST_TEST(!ur1.allocated());
196 }
197 BOOST_TEST_EQ(n, 1);
198 BOOST_TEST_EQ(deleted_res1, 10);
199
200 n = 0;
201 deleted_res1 = -1;
202 int deleted_res2 = -1;
203 {
204 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur1{ 10, checking_resource_deleter< int >(deleted_res1, n) };
205 BOOST_TEST_EQ(ur1.get(), 10);
206 BOOST_TEST(ur1.allocated());
207 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur2{ 20, checking_resource_deleter< int >(deleted_res2, n) };
208 BOOST_TEST_EQ(ur2.get(), 20);
209 BOOST_TEST(ur2.allocated());
210 ur2 = std::move(ur1);
211 BOOST_TEST_EQ(ur2.get(), 10);
212 BOOST_TEST(ur2.allocated());
213 BOOST_TEST(!ur1.allocated());
214 BOOST_TEST_EQ(n, 1);
215 BOOST_TEST_EQ(deleted_res1, -1);
216 BOOST_TEST_EQ(deleted_res2, 20);
217 deleted_res2 = -1;
218 }
219 BOOST_TEST_EQ(n, 2);
220 BOOST_TEST_EQ(deleted_res1, 10);
221 BOOST_TEST_EQ(deleted_res2, -1);
222
223 {
224 boost::scope::unique_resource< int, empty_resource_deleter< int > > ur1;
225 BOOST_TEST_EQ(ur1.get(), 0);
226 BOOST_TEST(!ur1.allocated());
227 boost::scope::unique_resource< int, empty_resource_deleter< int > > ur2{ 10, empty_resource_deleter< int >() };
228 BOOST_TEST_EQ(ur2.get(), 10);
229 BOOST_TEST(ur2.allocated());
230 using namespace std;
231 swap(left&: ur1, right&: ur2);
232 BOOST_TEST_EQ(ur1.get(), 10);
233 BOOST_TEST(ur1.allocated());
234 BOOST_TEST_EQ(ur2.get(), 0);
235 BOOST_TEST(!ur2.allocated());
236 }
237
238 n = 0;
239 deleted_res1 = -1;
240 deleted_res2 = -1;
241 {
242 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur1{ 10, checking_resource_deleter< int >(deleted_res1, n) };
243 BOOST_TEST_EQ(ur1.get(), 10);
244 BOOST_TEST_EQ(ur1.get_deleter().get_deleted(), &deleted_res1);
245 BOOST_TEST(ur1.allocated());
246 boost::scope::unique_resource< int, checking_resource_deleter< int > > ur2{ 20, checking_resource_deleter< int >(deleted_res2, n) };
247 BOOST_TEST_EQ(ur2.get(), 20);
248 BOOST_TEST_EQ(ur2.get_deleter().get_deleted(), &deleted_res2);
249 BOOST_TEST(ur2.allocated());
250 using namespace std;
251 swap(left&: ur1, right&: ur2);
252 BOOST_TEST_EQ(n, 0);
253 BOOST_TEST_EQ(ur1.get(), 20);
254 BOOST_TEST_EQ(ur1.get_deleter().get_deleted(), &deleted_res2);
255 BOOST_TEST(ur1.allocated());
256 BOOST_TEST_EQ(ur2.get(), 10);
257 BOOST_TEST_EQ(ur2.get_deleter().get_deleted(), &deleted_res1);
258 BOOST_TEST(ur2.allocated());
259 }
260 BOOST_TEST_EQ(n, 2);
261 BOOST_TEST_EQ(deleted_res1, 10);
262 BOOST_TEST_EQ(deleted_res2, 20);
263
264 struct local
265 {
266 static void raw_func_deleter(int)
267 {
268 ++g_n;
269 }
270
271 static void raw_func_deleter1(int res)
272 {
273 g_res1 = res;
274 }
275
276 static void raw_func_deleter2(int res)
277 {
278 g_res2 = res;
279 }
280 };
281
282 g_n = 0;
283 {
284 boost::scope::unique_resource< int, void (&)(int) > ur(10, local::raw_func_deleter);
285 BOOST_TEST_EQ(ur.get(), 10);
286 BOOST_TEST(ur.allocated());
287 BOOST_TEST(!noexcept(ur.reset()));
288 }
289 BOOST_TEST_EQ(g_n, 1);
290
291 g_n = 0;
292 {
293 boost::scope::unique_resource< int, void (&)(int) > ur1(10, local::raw_func_deleter);
294 BOOST_TEST_EQ(ur1.get(), 10);
295 BOOST_TEST(ur1.allocated());
296 boost::scope::unique_resource< int, void (&)(int) > ur2(std::move(ur1));
297 BOOST_TEST_EQ(ur2.get(), 10);
298 BOOST_TEST(ur2.allocated());
299 BOOST_TEST(!ur1.allocated());
300 }
301 BOOST_TEST_EQ(g_n, 1);
302
303 g_res1 = 0;
304 g_res2 = 0;
305 {
306 boost::scope::unique_resource< int, void (&)(int) > ur1(10, local::raw_func_deleter1);
307 BOOST_TEST_EQ(ur1.get(), 10);
308 BOOST_TEST(ur1.allocated());
309 boost::scope::unique_resource< int, void (&)(int) > ur2(20, local::raw_func_deleter2);
310 BOOST_TEST_EQ(ur2.get(), 20);
311 BOOST_TEST(ur2.allocated());
312 ur2 = std::move(ur1);
313 BOOST_TEST_EQ(ur2.get(), 10);
314 BOOST_TEST(ur2.allocated());
315 BOOST_TEST(!ur1.allocated());
316 }
317 BOOST_TEST_EQ(g_res1, 10);
318 BOOST_TEST_EQ(g_res2, 20);
319
320 g_res1 = 0;
321 g_res2 = 0;
322 {
323 boost::scope::unique_resource< int, void (&)(int) > ur1(10, local::raw_func_deleter1);
324 BOOST_TEST_EQ(ur1.get(), 10);
325 BOOST_TEST(ur1.allocated());
326 boost::scope::unique_resource< int, void (&)(int) > ur2(20, local::raw_func_deleter2);
327 BOOST_TEST_EQ(ur2.get(), 20);
328 BOOST_TEST(ur2.allocated());
329 using namespace std;
330 swap(left&: ur1, right&: ur2);
331 BOOST_TEST_EQ(ur1.get(), 20);
332 BOOST_TEST(ur1.allocated());
333 BOOST_TEST_EQ(ur2.get(), 10);
334 BOOST_TEST(ur2.allocated());
335 }
336 BOOST_TEST_EQ(g_res1, 10);
337 BOOST_TEST_EQ(g_res2, 20);
338}
339
340
341struct struct_resource
342{
343 int value;
344
345 struct_resource(int v = 0) noexcept :
346 value(v)
347 {
348 }
349
350 friend bool operator== (struct_resource const& left, struct_resource const& right) noexcept
351 {
352 return left.value == right.value;
353 }
354
355 friend bool operator!= (struct_resource const& left, struct_resource const& right) noexcept
356 {
357 return !(left == right);
358 }
359
360 friend std::ostream& operator<< (std::ostream& strm, struct_resource const& res)
361 {
362 strm << "{ " << res.value << " }";
363 return strm;
364 }
365};
366
367void check_struct()
368{
369 {
370 boost::scope::unique_resource< struct_resource, empty_resource_deleter< struct_resource > > ur;
371 BOOST_TEST_EQ(ur.get(), struct_resource{});
372 BOOST_TEST(!ur.allocated());
373 }
374
375 int n = 0;
376 struct_resource deleted_res1{ -1 };
377 {
378 boost::scope::unique_resource< struct_resource, checking_resource_deleter< struct_resource > > ur{ struct_resource{ 10 }, checking_resource_deleter< struct_resource >(deleted_res1, n) };
379 BOOST_TEST_EQ(ur.get(), struct_resource{ 10 });
380 BOOST_TEST(ur.allocated());
381 }
382 BOOST_TEST_EQ(n, 1);
383 BOOST_TEST_EQ(deleted_res1, struct_resource{ 10 });
384
385 n = 0;
386 deleted_res1 = struct_resource{ -1 };
387 {
388 boost::scope::unique_resource< struct_resource, checking_resource_deleter< struct_resource > > ur{ struct_resource{ 10 }, checking_resource_deleter< struct_resource >(deleted_res1, n) };
389 BOOST_TEST_EQ(ur.get(), struct_resource{ 10 });
390 BOOST_TEST(ur.allocated());
391 ur.reset(res: 20);
392 BOOST_TEST_EQ(n, 1);
393 BOOST_TEST_EQ(deleted_res1, struct_resource{ 10 });
394 deleted_res1 = struct_resource{ -1 };
395 BOOST_TEST_EQ(ur.get(), struct_resource{ 20 });
396 BOOST_TEST(ur.allocated());
397 }
398 BOOST_TEST_EQ(n, 2);
399 BOOST_TEST_EQ(deleted_res1, struct_resource{ 20 });
400
401 n = 0;
402 deleted_res1 = struct_resource{ -1 };
403 {
404 boost::scope::unique_resource< struct_resource, checking_resource_deleter< struct_resource > > ur1{ struct_resource{ 10 }, checking_resource_deleter< struct_resource >(deleted_res1, n) };
405 BOOST_TEST_EQ(ur1.get(), struct_resource{ 10 });
406 BOOST_TEST(ur1.allocated());
407 boost::scope::unique_resource< struct_resource, checking_resource_deleter< struct_resource > > ur2{ std::move(ur1) };
408 BOOST_TEST_EQ(ur2.get(), struct_resource{ 10 });
409 BOOST_TEST(ur2.allocated());
410 BOOST_TEST(!ur1.allocated());
411 }
412 BOOST_TEST_EQ(n, 1);
413 BOOST_TEST_EQ(deleted_res1, struct_resource{ 10 });
414
415 n = 0;
416 deleted_res1 = struct_resource{ -1 };
417 struct_resource deleted_res2{ -1 };
418 {
419 boost::scope::unique_resource< struct_resource, checking_resource_deleter< struct_resource > > ur1{ struct_resource{ 10 }, checking_resource_deleter< struct_resource >(deleted_res1, n) };
420 BOOST_TEST_EQ(ur1.get(), struct_resource{ 10 });
421 BOOST_TEST(ur1.allocated());
422 boost::scope::unique_resource< struct_resource, checking_resource_deleter< struct_resource > > ur2{ struct_resource{ 20 }, checking_resource_deleter< struct_resource >(deleted_res2, n) };
423 BOOST_TEST_EQ(ur2.get(), struct_resource{ 20 });
424 BOOST_TEST(ur2.allocated());
425 ur2 = std::move(ur1);
426 BOOST_TEST_EQ(n, 1);
427 BOOST_TEST_EQ(deleted_res1, struct_resource{ -1 });
428 BOOST_TEST_EQ(deleted_res2, struct_resource{ 20 });
429 deleted_res2 = struct_resource{ -1 };
430 BOOST_TEST_EQ(ur2.get(), struct_resource{ 10 });
431 BOOST_TEST(ur2.allocated());
432 BOOST_TEST(!ur1.allocated());
433 }
434 BOOST_TEST_EQ(n, 2);
435 BOOST_TEST_EQ(deleted_res1, struct_resource{ 10 });
436 BOOST_TEST_EQ(deleted_res2, struct_resource{ -1 });
437
438 n = 0;
439 deleted_res1 = struct_resource{ -1 };
440 deleted_res2 = struct_resource{ -1 };
441 {
442 boost::scope::unique_resource< struct_resource, checking_resource_deleter< struct_resource > > ur1{ struct_resource{ 10 }, checking_resource_deleter< struct_resource >(deleted_res1, n) };
443 BOOST_TEST_EQ(ur1.get(), struct_resource{ 10 });
444 BOOST_TEST(ur1.allocated());
445 boost::scope::unique_resource< struct_resource, checking_resource_deleter< struct_resource > > ur2{ struct_resource{ 20 }, checking_resource_deleter< struct_resource >(deleted_res2, n) };
446 BOOST_TEST_EQ(ur2.get(), struct_resource{ 20 });
447 BOOST_TEST(ur2.allocated());
448 using namespace std;
449 swap(left&: ur1, right&: ur2);
450 BOOST_TEST_EQ(n, 0);
451 BOOST_TEST_EQ(ur1.get(), struct_resource{ 20 });
452 BOOST_TEST_EQ(ur1.get_deleter().get_deleted(), &deleted_res2);
453 BOOST_TEST(ur1.allocated());
454 BOOST_TEST_EQ(ur2.get(), struct_resource{ 10 });
455 BOOST_TEST_EQ(ur2.get_deleter().get_deleted(), &deleted_res1);
456 BOOST_TEST(ur2.allocated());
457 }
458 BOOST_TEST_EQ(n, 2);
459 BOOST_TEST_EQ(deleted_res1, struct_resource{ 10 });
460 BOOST_TEST_EQ(deleted_res2, struct_resource{ 20 });
461}
462
463
464void check_ptr()
465{
466 {
467 boost::scope::unique_resource< struct_resource*, empty_resource_deleter< struct_resource* > > ur;
468 BOOST_TEST_EQ(ur.get(), static_cast< struct_resource* >(nullptr));
469 BOOST_TEST(!ur.allocated());
470 }
471
472 int n = 0;
473 struct_resource res1{ 10 };
474 struct_resource* deleted_res1 = nullptr;
475 {
476 boost::scope::unique_resource< struct_resource*, checking_resource_deleter< struct_resource* > > ur{ &res1, checking_resource_deleter< struct_resource* >(deleted_res1, n) };
477 BOOST_TEST_EQ(ur.get(), &res1);
478 BOOST_TEST_EQ(ur.get()->value, 10);
479 BOOST_TEST_EQ(ur->value, 10);
480 BOOST_TEST_EQ((*ur).value, 10);
481 BOOST_TEST(ur.allocated());
482 }
483 BOOST_TEST_EQ(n, 1);
484 BOOST_TEST_EQ(deleted_res1, &res1);
485}
486
487
488void check_ref()
489{
490 int n = 0;
491 struct_resource res1{ 10 };
492 struct_resource deleted_res1{ -1 };
493 {
494 boost::scope::unique_resource< struct_resource&, checking_resource_deleter< struct_resource > > ur{ res1, checking_resource_deleter< struct_resource >(deleted_res1, n) };
495 BOOST_TEST_EQ(ur.get(), res1);
496 BOOST_TEST_EQ(&ur.get(), &res1);
497 BOOST_TEST(ur.allocated());
498 }
499 BOOST_TEST_EQ(n, 1);
500 BOOST_TEST_EQ(deleted_res1, res1);
501
502 n = 0;
503 deleted_res1 = struct_resource{ -1 };
504 struct_resource res2{ 20 };
505 {
506 boost::scope::unique_resource< struct_resource&, checking_resource_deleter< struct_resource > > ur{ res1, checking_resource_deleter< struct_resource >(deleted_res1, n) };
507 BOOST_TEST_EQ(&ur.get(), &res1);
508 BOOST_TEST(ur.allocated());
509 ur.reset(res&: res2);
510 BOOST_TEST_EQ(n, 1);
511 BOOST_TEST_EQ(deleted_res1, res1);
512 deleted_res1 = struct_resource{ -1 };
513 BOOST_TEST_EQ(&ur.get(), &res2);
514 BOOST_TEST(ur.allocated());
515 }
516 BOOST_TEST_EQ(n, 2);
517 BOOST_TEST_EQ(deleted_res1, res2);
518
519 n = 0;
520 deleted_res1 = struct_resource{ -1 };
521 {
522 boost::scope::unique_resource< struct_resource&, checking_resource_deleter< struct_resource > > ur1{ res1, checking_resource_deleter< struct_resource >(deleted_res1, n) };
523 BOOST_TEST_EQ(&ur1.get(), &res1);
524 BOOST_TEST(ur1.allocated());
525 boost::scope::unique_resource< struct_resource&, checking_resource_deleter< struct_resource > > ur2{ std::move(ur1) };
526 BOOST_TEST_EQ(&ur2.get(), &res1);
527 BOOST_TEST(ur2.allocated());
528 BOOST_TEST(!ur1.allocated());
529 }
530 BOOST_TEST_EQ(n, 1);
531 BOOST_TEST_EQ(deleted_res1, res1);
532
533 n = 0;
534 deleted_res1 = struct_resource{ -1 };
535 struct_resource deleted_res2{ -1 };
536 {
537 boost::scope::unique_resource< struct_resource&, checking_resource_deleter< struct_resource > > ur1{ res1, checking_resource_deleter< struct_resource >(deleted_res1, n) };
538 BOOST_TEST_EQ(&ur1.get(), &res1);
539 BOOST_TEST(ur1.allocated());
540 boost::scope::unique_resource< struct_resource&, checking_resource_deleter< struct_resource > > ur2{ res2, checking_resource_deleter< struct_resource >(deleted_res2, n) };
541 BOOST_TEST_EQ(&ur2.get(), &res2);
542 BOOST_TEST(ur2.allocated());
543 ur2 = std::move(ur1);
544 BOOST_TEST_EQ(n, 1);
545 BOOST_TEST_EQ(deleted_res1, struct_resource{ -1 });
546 BOOST_TEST_EQ(deleted_res2, struct_resource{ 20 });
547 deleted_res2 = struct_resource{ -1 };
548 BOOST_TEST_EQ(&ur2.get(), &res1);
549 BOOST_TEST(ur2.allocated());
550 BOOST_TEST(!ur1.allocated());
551 }
552 BOOST_TEST_EQ(n, 2);
553 BOOST_TEST_EQ(deleted_res1, struct_resource{ 10 });
554 BOOST_TEST_EQ(deleted_res2, struct_resource{ -1 });
555
556 n = 0;
557 deleted_res1 = struct_resource{ -1 };
558 deleted_res2 = struct_resource{ -1 };
559 {
560 boost::scope::unique_resource< struct_resource&, checking_resource_deleter< struct_resource > > ur1{ res1, checking_resource_deleter< struct_resource >(deleted_res1, n) };
561 BOOST_TEST_EQ(&ur1.get(), &res1);
562 BOOST_TEST(ur1.allocated());
563 struct_resource expected_res2{ 20 };
564 boost::scope::unique_resource< struct_resource&, checking_resource_deleter< struct_resource > > ur2{ res2, checking_resource_deleter< struct_resource >(deleted_res2, n) };
565 BOOST_TEST_EQ(&ur2.get(), &res2);
566 BOOST_TEST(ur2.allocated());
567 using namespace std;
568 swap(left&: ur1, right&: ur2);
569 BOOST_TEST_EQ(n, 0);
570 BOOST_TEST_EQ(&ur1.get(), &res2);
571 BOOST_TEST_EQ(ur1.get_deleter().get_deleted(), &deleted_res2);
572 BOOST_TEST(ur1.allocated());
573 BOOST_TEST_EQ(&ur2.get(), &res1);
574 BOOST_TEST_EQ(ur2.get_deleter().get_deleted(), &deleted_res1);
575 BOOST_TEST(ur2.allocated());
576 }
577 BOOST_TEST_EQ(n, 2);
578 BOOST_TEST_EQ(deleted_res1, struct_resource{ 10 });
579 BOOST_TEST_EQ(deleted_res2, struct_resource{ 20 });
580}
581
582
583class throw_on_move_resource
584{
585private:
586 int m_value;
587
588public:
589 explicit throw_on_move_resource(int v = 0) noexcept :
590 m_value(v)
591 {
592 }
593
594 throw_on_move_resource(throw_on_move_resource const&) = default;
595 throw_on_move_resource& operator= (throw_on_move_resource const&) = default;
596
597 throw_on_move_resource(throw_on_move_resource&&)
598 {
599 throw std::runtime_error("throw_on_move_resource move ctor");
600 }
601 throw_on_move_resource& operator= (throw_on_move_resource&&)
602 {
603 throw std::runtime_error("throw_on_move_resource move assignment");
604 }
605
606 int get() const noexcept
607 {
608 return m_value;
609 }
610
611 bool operator== (throw_on_move_resource const& that) const noexcept
612 {
613 return m_value == that.m_value;
614 }
615
616 bool operator!= (throw_on_move_resource const& that) const noexcept
617 {
618 return !operator==(that);
619 }
620
621 friend std::ostream& operator<< (std::ostream& strm, throw_on_move_resource const& res)
622 {
623 strm << "{ " << res.m_value << " }";
624 return strm;
625 }
626};
627
628class throw_on_copy_resource
629{
630private:
631 int m_value;
632 mutable bool m_throw;
633
634public:
635 explicit throw_on_copy_resource(int v = 0, bool do_throw = true) noexcept :
636 m_value(v),
637 m_throw(do_throw)
638 {
639 }
640
641 throw_on_copy_resource(throw_on_copy_resource const& that) :
642 m_value(that.m_value),
643 m_throw(that.m_throw)
644 {
645 if (m_throw)
646 throw std::runtime_error("throw_on_copy_resource copy ctor");
647 }
648 throw_on_copy_resource& operator= (throw_on_copy_resource const& that)
649 {
650 m_value = that.m_value;
651 m_throw = that.m_throw;
652 if (m_throw)
653 throw std::runtime_error("throw_on_copy_resource copy assignment");
654 return *this;
655 }
656
657 throw_on_copy_resource(throw_on_copy_resource&&) = delete;
658 throw_on_copy_resource& operator= (throw_on_copy_resource&&) = delete;
659
660 int get() const noexcept
661 {
662 return m_value;
663 }
664
665 void set_throw(bool do_throw) const noexcept
666 {
667 m_throw = do_throw;
668 }
669
670 bool operator== (throw_on_copy_resource const& that) const noexcept
671 {
672 return m_value == that.m_value;
673 }
674
675 bool operator!= (throw_on_copy_resource const& that) const noexcept
676 {
677 return !operator==(that);
678 }
679
680 friend std::ostream& operator<< (std::ostream& strm, throw_on_copy_resource const& res)
681 {
682 strm << "{ " << res.m_value << " }";
683 return strm;
684 }
685};
686
687void check_throw_resource()
688{
689 int n = 0;
690 try
691 {
692 boost::scope::unique_resource< throw_on_move_resource, checking_resource_deleter< throw_on_move_resource > > ur{ throw_on_move_resource{ 10 }, checking_resource_deleter< throw_on_move_resource >(n) };
693 BOOST_TEST_EQ(ur.get().get(), 10);
694 BOOST_TEST(ur.allocated());
695 }
696 catch (...)
697 {
698 BOOST_ERROR("An exception is not expected to be thrown by throw_on_move_resource (copy ctor should be used)");
699 }
700 BOOST_TEST_EQ(n, 1);
701
702 n = 0;
703 try
704 {
705 boost::scope::unique_resource< throw_on_copy_resource, checking_resource_deleter< throw_on_copy_resource > > ur{ throw_on_copy_resource{ 10 }, checking_resource_deleter< throw_on_copy_resource >(n) };
706 BOOST_ERROR("An exception is expected to be thrown by throw_on_copy_resource");
707 }
708 catch (...)
709 {
710 }
711 BOOST_TEST_EQ(n, 1);
712
713 n = 0;
714 try
715 {
716 boost::scope::unique_resource< throw_on_copy_resource, checking_resource_deleter< throw_on_copy_resource > > ur1{ throw_on_copy_resource{ 10, false }, checking_resource_deleter< throw_on_copy_resource >(n) };
717 ur1.get().set_throw(true);
718 try
719 {
720 boost::scope::unique_resource< throw_on_copy_resource, checking_resource_deleter< throw_on_copy_resource > > ur2 = std::move(ur1);
721 BOOST_ERROR("An exception is expected to be thrown by throw_on_copy_resource");
722 }
723 catch (...)
724 {
725 BOOST_TEST_EQ(n, 0);
726 throw;
727 }
728 }
729 catch (...)
730 {
731 }
732 BOOST_TEST_EQ(n, 1);
733
734 n = 0;
735 try
736 {
737 boost::scope::unique_resource< throw_on_copy_resource, checking_resource_deleter< throw_on_copy_resource > > ur1{ throw_on_copy_resource{ 10, false }, checking_resource_deleter< throw_on_copy_resource >(n) };
738 ur1.get().set_throw(true);
739 try
740 {
741 boost::scope::unique_resource< throw_on_copy_resource, checking_resource_deleter< throw_on_copy_resource > > ur2{ throw_on_copy_resource{ 20, false }, checking_resource_deleter< throw_on_copy_resource >(n) };
742 ur2 = std::move(ur1);
743 BOOST_ERROR("An exception is expected to be thrown by throw_on_copy_resource");
744 }
745 catch (...)
746 {
747 BOOST_TEST_EQ(n, 1);
748 throw;
749 }
750 }
751 catch (...)
752 {
753 }
754 BOOST_TEST_EQ(n, 2);
755}
756
757class moveable_resource
758{
759private:
760 int m_value;
761
762public:
763 explicit moveable_resource(int value = 0) noexcept :
764 m_value(value)
765 {
766 }
767
768 moveable_resource(moveable_resource&& that) noexcept :
769 m_value(that.m_value)
770 {
771 that.m_value = -1;
772 }
773
774 moveable_resource& operator= (moveable_resource&& that) noexcept
775 {
776 m_value = that.m_value;
777 that.m_value = -1;
778 return *this;
779 }
780
781 moveable_resource(moveable_resource const&) = delete;
782 moveable_resource& operator= (moveable_resource const&) = delete;
783
784 int get() const noexcept
785 {
786 return m_value;
787 }
788
789 bool operator== (moveable_resource const& that) const noexcept
790 {
791 return m_value == that.m_value;
792 }
793
794 bool operator!= (moveable_resource const& that) const noexcept
795 {
796 return !operator==(that);
797 }
798
799 friend std::ostream& operator<< (std::ostream& strm, moveable_resource const& res)
800 {
801 strm << "{ " << res.m_value << " }";
802 return strm;
803 }
804
805 friend void copy_resource(moveable_resource const& from, moveable_resource& to)
806 {
807 to.m_value = from.m_value;
808 }
809};
810
811class copyable_resource
812{
813private:
814 int m_value;
815
816public:
817 explicit copyable_resource(int value = 0) noexcept :
818 m_value(value)
819 {
820 }
821
822 copyable_resource(copyable_resource const& that) noexcept :
823 m_value(that.m_value)
824 {
825 }
826
827 copyable_resource& operator= (copyable_resource const& that) noexcept
828 {
829 m_value = that.m_value;
830 return *this;
831 }
832
833 int get() const noexcept
834 {
835 return m_value;
836 }
837
838 bool operator== (copyable_resource const& that) const noexcept
839 {
840 return m_value == that.m_value;
841 }
842
843 bool operator!= (copyable_resource const& that) const noexcept
844 {
845 return !operator==(that);
846 }
847
848 friend std::ostream& operator<< (std::ostream& strm, copyable_resource const& res)
849 {
850 strm << "{ " << res.m_value << " }";
851 return strm;
852 }
853};
854
855template< typename Resource >
856class throwing_resource_deleter :
857 public checking_resource_deleter< Resource >
858{
859private:
860 using base_type = checking_resource_deleter< Resource >;
861
862private:
863 mutable bool m_throw;
864
865public:
866 explicit throwing_resource_deleter(int& n, bool do_throw = false) noexcept :
867 base_type(n),
868 m_throw(do_throw)
869 {
870 }
871
872 explicit throwing_resource_deleter(Resource& deleted, int& n, bool do_throw = false) noexcept :
873 base_type(deleted, n),
874 m_throw(do_throw)
875 {
876 }
877
878 throwing_resource_deleter(throwing_resource_deleter const& that) :
879 base_type(static_cast< base_type const& >(that)),
880 m_throw(that.m_throw)
881 {
882 if (m_throw)
883 throw std::runtime_error("throwing_resource_deleter copy ctor");
884 }
885
886 throwing_resource_deleter& operator=(throwing_resource_deleter const& that)
887 {
888 *static_cast< base_type* >(this) = static_cast< base_type const& >(that);
889 m_throw = that.m_throw;
890 if (m_throw)
891 throw std::runtime_error("throwing_resource_deleter copy assignment");
892 return *this;
893 }
894
895 void set_throw(bool do_throw) const noexcept
896 {
897 m_throw = do_throw;
898 }
899};
900
901template< typename Resource >
902using default_resource_traits = void;
903
904template< typename Resource >
905struct wrapped_int_resource_traits
906{
907 static Resource make_default() noexcept
908 {
909 return Resource(-1);
910 }
911
912 static bool is_allocated(Resource const& res) noexcept
913 {
914 return res.get() >= 0;
915 }
916};
917
918template< template< typename > class Traits >
919void check_throw_deleter()
920{
921 int n = 0;
922 {
923 try
924 {
925 using unique_resource_t = boost::scope::unique_resource< copyable_resource, throwing_resource_deleter< copyable_resource >, Traits< copyable_resource > >;
926 unique_resource_t ur1{ boost::scope::default_resource, throwing_resource_deleter< copyable_resource >(n) };
927 ur1.get_deleter().set_throw(true);
928 try
929 {
930 unique_resource_t ur2 = std::move(ur1);
931 BOOST_ERROR("An exception is expected to be thrown by throwing_resource_deleter");
932 }
933 catch (...)
934 {
935 BOOST_TEST_EQ(n, 0);
936 throw;
937 }
938 }
939 catch (...)
940 {
941 }
942 BOOST_TEST_EQ(n, 0);
943 }
944
945 n = 0;
946 {
947 copyable_resource deleted_res1;
948 try
949 {
950 using unique_resource_t = boost::scope::unique_resource< copyable_resource, throwing_resource_deleter< copyable_resource >, Traits< copyable_resource > >;
951 unique_resource_t ur1{ copyable_resource{ 10 }, throwing_resource_deleter< copyable_resource >(deleted_res1, n) };
952 ur1.get_deleter().set_throw(true);
953 try
954 {
955 unique_resource_t ur2 = std::move(ur1);
956 BOOST_ERROR("An exception is expected to be thrown by throwing_resource_deleter");
957 }
958 catch (...)
959 {
960 BOOST_TEST_EQ(n, 0);
961 throw;
962 }
963 }
964 catch (...)
965 {
966 }
967 BOOST_TEST_EQ(n, 1);
968 BOOST_TEST_EQ(deleted_res1, copyable_resource{ 10 });
969 }
970
971 n = 0;
972 {
973 copyable_resource deleted_res1, deleted_res2;
974 try
975 {
976 using unique_resource_t = boost::scope::unique_resource< copyable_resource, throwing_resource_deleter< copyable_resource >, Traits< copyable_resource > >;
977 unique_resource_t ur1{ copyable_resource{ 10 }, throwing_resource_deleter< copyable_resource >(deleted_res1, n) };
978 ur1.get_deleter().set_throw(true);
979 try
980 {
981 unique_resource_t ur2{ copyable_resource{ 20 }, throwing_resource_deleter< copyable_resource >(deleted_res2, n) };
982 ur2 = std::move(ur1);
983 BOOST_ERROR("An exception is expected to be thrown by throwing_resource_deleter");
984 }
985 catch (...)
986 {
987 BOOST_TEST_EQ(n, 1);
988 BOOST_TEST_EQ(deleted_res2, copyable_resource{ 20 });
989 throw;
990 }
991 }
992 catch (...)
993 {
994 }
995 BOOST_TEST_EQ(n, 2);
996 BOOST_TEST_EQ(deleted_res1, copyable_resource{ 10 });
997 }
998
999 n = 0;
1000 {
1001 try
1002 {
1003 using unique_resource_t = boost::scope::unique_resource< moveable_resource, throwing_resource_deleter< moveable_resource >, Traits< moveable_resource > >;
1004 unique_resource_t ur1{ boost::scope::default_resource, throwing_resource_deleter< moveable_resource >(n) };
1005 ur1.get_deleter().set_throw(true);
1006 try
1007 {
1008 unique_resource_t ur2 = std::move(ur1);
1009 BOOST_ERROR("An exception is expected to be thrown by throwing_resource_deleter");
1010 }
1011 catch (...)
1012 {
1013 BOOST_TEST_EQ(n, 0);
1014 throw;
1015 }
1016 }
1017 catch (...)
1018 {
1019 }
1020 BOOST_TEST_EQ(n, 0);
1021 }
1022
1023 n = 0;
1024 {
1025 moveable_resource deleted_res1;
1026 try
1027 {
1028 using unique_resource_t = boost::scope::unique_resource< moveable_resource, throwing_resource_deleter< moveable_resource >, Traits< moveable_resource > >;
1029 unique_resource_t ur1{ moveable_resource{ 10 }, throwing_resource_deleter< moveable_resource >(deleted_res1, n) };
1030 ur1.get_deleter().set_throw(true);
1031 try
1032 {
1033 unique_resource_t ur2 = std::move(ur1);
1034 BOOST_ERROR("An exception is expected to be thrown by throwing_resource_deleter");
1035 }
1036 catch (...)
1037 {
1038 // The resource was moved from ur1, but the deleter could not have been moved. Then the resource was moved back to ur1.
1039 BOOST_TEST_EQ(n, 0);
1040 BOOST_TEST(ur1.allocated());
1041 BOOST_TEST_EQ(ur1.get(), moveable_resource{ 10 });
1042 throw;
1043 }
1044 }
1045 catch (...)
1046 {
1047 }
1048 BOOST_TEST_EQ(n, 1);
1049 BOOST_TEST_EQ(deleted_res1, moveable_resource{ 10 });
1050 }
1051
1052 n = 0;
1053 {
1054 moveable_resource deleted_res1, deleted_res2;
1055 try
1056 {
1057 using unique_resource_t = boost::scope::unique_resource< moveable_resource, throwing_resource_deleter< moveable_resource >, Traits< moveable_resource > >;
1058 unique_resource_t ur1{ moveable_resource{ 10 }, throwing_resource_deleter< moveable_resource >(deleted_res1, n) };
1059 ur1.get_deleter().set_throw(true);
1060 try
1061 {
1062 unique_resource_t ur2{ moveable_resource{ 20 }, throwing_resource_deleter< moveable_resource >(deleted_res2, n) };
1063 ur2 = std::move(ur1);
1064 BOOST_ERROR("An exception is expected to be thrown by throwing_resource_deleter");
1065 }
1066 catch (...)
1067 {
1068 // First, ur2 was reset - the deleter was called on the resource 20. Then the deleter could not have been moved from ur1,
1069 // leaving ur1 intact.
1070 BOOST_TEST_EQ(n, 1);
1071 BOOST_TEST_EQ(deleted_res2, moveable_resource{ 20 });
1072 throw;
1073 }
1074 }
1075 catch (...)
1076 {
1077 }
1078 BOOST_TEST_EQ(n, 2);
1079 BOOST_TEST_EQ(deleted_res1, moveable_resource{ 10 });
1080 BOOST_TEST_EQ(deleted_res2, moveable_resource{ 20 });
1081 }
1082}
1083
1084// Specially-crafted resource type that is:
1085// * nothrow move-constructible
1086// * NOT-nothrow move-assignable
1087// * has data layout which favors placing the "allocated" flag in unique_resource in its tail padding
1088class move_constructible_resource
1089{
1090public:
1091 // A special tag to construct "default" resource value
1092 struct default_tag { };
1093
1094private:
1095 int m_n1;
1096 signed char m_n2;
1097
1098public:
1099 constexpr move_constructible_resource() noexcept : m_n1(0), m_n2(0) { }
1100
1101 // For compatibility with move_constructible_resource_traits::make_default()
1102 explicit constexpr move_constructible_resource(default_tag) noexcept : move_constructible_resource() { }
1103
1104 explicit move_constructible_resource(int n1, signed char n2 = 0) noexcept : m_n1(n1), m_n2(n2) { }
1105
1106 move_constructible_resource(move_constructible_resource&& that) noexcept : m_n1(that.m_n1), m_n2(that.m_n2)
1107 {
1108 that.m_n1 = 0;
1109 that.m_n2 = 0;
1110 }
1111
1112 move_constructible_resource(move_constructible_resource const& that) : m_n1(that.m_n1), m_n2(that.m_n2)
1113 {
1114 }
1115
1116 move_constructible_resource& operator= (move_constructible_resource&& that) // not noexcept
1117 {
1118 m_n1 = that.m_n1;
1119 m_n2 = that.m_n2;
1120 that.m_n1 = 0;
1121 that.m_n2 = 0;
1122 return *this;
1123 }
1124
1125 move_constructible_resource& operator= (move_constructible_resource const& that)
1126 {
1127 m_n1 = that.m_n1;
1128 m_n2 = that.m_n2;
1129 return *this;
1130 }
1131
1132 // For compatibility with move_constructible_resource_traits::make_default()
1133 move_constructible_resource& operator= (default_tag) noexcept
1134 {
1135 m_n1 = 0;
1136 m_n2 = 0;
1137 return *this;
1138 }
1139
1140 bool operator== (move_constructible_resource const& that) const noexcept
1141 {
1142 return m_n1 == that.m_n1 && m_n2 == that.m_n2;
1143 }
1144
1145 bool operator!= (move_constructible_resource const& that) const noexcept
1146 {
1147 return !operator==(that);
1148 }
1149
1150 friend std::ostream& operator<< (std::ostream& strm, move_constructible_resource const& res)
1151 {
1152 strm << "{ " << res.m_n1 << ", " << static_cast< int >(res.m_n2) << " }";
1153 return strm;
1154 }
1155
1156 friend void copy_resource(move_constructible_resource const& from, move_constructible_resource& to)
1157 {
1158 to.m_n1 = from.m_n1;
1159 to.m_n2 = from.m_n2;
1160 }
1161};
1162
1163//! Resource traits for \c move_constructible_resource
1164struct move_constructible_resource_traits
1165{
1166 static move_constructible_resource::default_tag make_default() noexcept { return move_constructible_resource::default_tag{}; }
1167 static bool is_allocated(move_constructible_resource const& res) noexcept { return res != move_constructible_resource{}; }
1168};
1169
1170void check_throw_deleter_move_constructible_resource()
1171{
1172 int n = 0;
1173 {
1174 move_constructible_resource deleted_res1;
1175 try
1176 {
1177 using unique_resource_t = boost::scope::unique_resource< move_constructible_resource, throwing_resource_deleter< move_constructible_resource >, move_constructible_resource_traits >;
1178 unique_resource_t ur1{ move_constructible_resource(10, 5), throwing_resource_deleter< move_constructible_resource >(deleted_res1, n) };
1179 ur1.get_deleter().set_throw(true);
1180 try
1181 {
1182 unique_resource_t ur2 = std::move(ur1);
1183 BOOST_ERROR("An exception is expected to be thrown by throwing_resource_deleter");
1184 }
1185 catch (...)
1186 {
1187 // The resource was moved from ur1, but the deleter could not have been moved. Then the resource was moved back to ur1.
1188 BOOST_TEST_EQ(n, 0);
1189 BOOST_TEST(ur1.allocated());
1190 BOOST_TEST_EQ(ur1.get(), move_constructible_resource(10, 5));
1191 throw;
1192 }
1193 }
1194 catch (...)
1195 {
1196 }
1197 BOOST_TEST_EQ(n, 1);
1198 BOOST_TEST_EQ(deleted_res1, move_constructible_resource(10, 5));
1199 }
1200
1201 n = 0;
1202 {
1203 move_constructible_resource deleted_res1;
1204 try
1205 {
1206 // No resource traits to force using the "allocated" flag
1207 using unique_resource_t = boost::scope::unique_resource< move_constructible_resource, throwing_resource_deleter< move_constructible_resource > >;
1208 unique_resource_t ur1{ move_constructible_resource(10, 0), throwing_resource_deleter< move_constructible_resource >(deleted_res1, n) };
1209 ur1.get_deleter().set_throw(true);
1210 try
1211 {
1212 unique_resource_t ur2 = std::move(ur1);
1213 BOOST_ERROR("An exception is expected to be thrown by throwing_resource_deleter");
1214 }
1215 catch (...)
1216 {
1217 // The resource was moved from ur1, but the deleter could not have been moved. Then the resource was moved back to ur1.
1218 BOOST_TEST_EQ(n, 0);
1219 BOOST_TEST(ur1.allocated());
1220 BOOST_TEST_EQ(ur1.get(), move_constructible_resource(10, 0));
1221 throw;
1222 }
1223 }
1224 catch (...)
1225 {
1226 }
1227 BOOST_TEST_EQ(n, 1);
1228 BOOST_TEST_EQ(deleted_res1, move_constructible_resource(10, 0));
1229 }
1230}
1231
1232
1233void check_deduction()
1234{
1235 struct local
1236 {
1237 static void raw_func_deleter(int)
1238 {
1239 ++g_n;
1240 }
1241
1242#if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES)
1243 static void raw_func_deleter_noexcept(int) noexcept
1244 {
1245 ++g_n;
1246 }
1247#endif
1248 };
1249
1250#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
1251 {
1252 using expected_unique_resource_t = boost::scope::unique_resource< int, empty_resource_deleter< int > >;
1253 boost::scope::unique_resource ur{ 0, empty_resource_deleter< int >() };
1254 BOOST_TEST_TRAIT_SAME(decltype(ur), expected_unique_resource_t);
1255 }
1256 {
1257 using expected_unique_resource_t = boost::scope::unique_resource< struct_resource, empty_resource_deleter< struct_resource > >;
1258 boost::scope::unique_resource ur{ struct_resource(), empty_resource_deleter< struct_resource >() };
1259 BOOST_TEST_TRAIT_SAME(decltype(ur), expected_unique_resource_t);
1260 }
1261 {
1262 using expected_unique_resource_t = boost::scope::unique_resource< int, void(*)(int) >;
1263 boost::scope::unique_resource ur{ 0, local::raw_func_deleter };
1264 BOOST_TEST_TRAIT_SAME(decltype(ur), expected_unique_resource_t);
1265 }
1266#if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES)
1267 {
1268 using expected_unique_resource_t = boost::scope::unique_resource< int, void(*)(int) noexcept >;
1269 boost::scope::unique_resource ur{ 0, local::raw_func_deleter_noexcept };
1270 BOOST_TEST_TRAIT_SAME(decltype(ur), expected_unique_resource_t);
1271 }
1272#endif
1273 {
1274 using expected_unique_resource_t = boost::scope::unique_resource< int, empty_resource_deleter< int > >;
1275 boost::scope::unique_resource ur1{ 0, empty_resource_deleter< int >() };
1276 BOOST_TEST_TRAIT_SAME(decltype(ur1), expected_unique_resource_t);
1277 boost::scope::unique_resource ur2 = std::move(ur1);
1278 BOOST_TEST_TRAIT_SAME(decltype(ur2), expected_unique_resource_t);
1279 }
1280#endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
1281
1282 int n = 0, deleted_res = -1;
1283 {
1284 using expected_unique_resource_t = boost::scope::unique_resource< int, checking_resource_deleter< int > >;
1285 auto ur = boost::scope::make_unique_resource_checked(res: 10, invalid: 0, del: checking_resource_deleter< int >(deleted_res, n));
1286 BOOST_TEST_TRAIT_SAME(decltype(ur), expected_unique_resource_t);
1287 BOOST_TEST_EQ(ur.get(), 10);
1288 BOOST_TEST(ur.allocated());
1289 }
1290 BOOST_TEST_EQ(n, 1);
1291 BOOST_TEST_EQ(deleted_res, 10);
1292
1293 n = 0;
1294 deleted_res = -1;
1295 {
1296 using expected_unique_resource_t = boost::scope::unique_resource< int, checking_resource_deleter< int > >;
1297 auto ur = boost::scope::make_unique_resource_checked(res: 0, invalid: 0, del: checking_resource_deleter< int >(deleted_res, n));
1298 BOOST_TEST_TRAIT_SAME(decltype(ur), expected_unique_resource_t);
1299 BOOST_TEST_EQ(ur.get(), 0);
1300 BOOST_TEST(!ur.allocated());
1301 }
1302 BOOST_TEST_EQ(n, 0);
1303 BOOST_TEST_EQ(deleted_res, -1);
1304
1305 {
1306 using expected_unique_resource_t = boost::scope::unique_resource< int, void(*)(int) >;
1307 auto ur = boost::scope::make_unique_resource_checked(res: 0, invalid: 0, del&: local::raw_func_deleter);
1308 BOOST_TEST_TRAIT_SAME(decltype(ur), expected_unique_resource_t);
1309 }
1310#if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES)
1311 {
1312 using expected_unique_resource_t = boost::scope::unique_resource< int, void(*)(int) noexcept >;
1313 auto ur = boost::scope::make_unique_resource_checked(res: 0, invalid: 0, del&: local::raw_func_deleter_noexcept);
1314 BOOST_TEST_TRAIT_SAME(decltype(ur), expected_unique_resource_t);
1315 }
1316#endif
1317
1318 n = 0;
1319 try
1320 {
1321 // Not required to throw, but either way the deleter should not be called
1322 auto ur = boost::scope::make_unique_resource_checked(res: throw_on_copy_resource{ 0 }, invalid: throw_on_copy_resource{ 0 }, del: checking_resource_deleter< throw_on_copy_resource >(n));
1323 }
1324 catch (...)
1325 {
1326 }
1327 BOOST_TEST_EQ(n, 0);
1328
1329 n = 0;
1330 try
1331 {
1332 auto ur = boost::scope::make_unique_resource_checked(res: 0, invalid: 0, del: throwing_resource_deleter< int >(n, true));
1333 BOOST_ERROR("An exception is expected to be thrown by throwing_resource_deleter");
1334 }
1335 catch (...)
1336 {
1337 }
1338 BOOST_TEST_EQ(n, 0);
1339}
1340
1341struct int_resource_traits
1342{
1343 static int make_default() noexcept
1344 {
1345 return -1;
1346 }
1347
1348 static bool is_allocated(int res) noexcept
1349 {
1350 return res >= 0;
1351 }
1352};
1353
1354void check_resource_traits()
1355{
1356 {
1357 boost::scope::unique_resource< int, empty_resource_deleter< int >, int_resource_traits > ur;
1358 BOOST_TEST_EQ(ur.get(), int_resource_traits::make_default());
1359 BOOST_TEST(!ur.allocated());
1360 }
1361
1362 int n = 0, deleted_res1 = -1;
1363 {
1364 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur{ -10, checking_resource_deleter< int >(deleted_res1, n) };
1365 BOOST_TEST_EQ(ur.get(), -10);
1366 BOOST_TEST(!ur.allocated());
1367 BOOST_TEST(!ur);
1368 }
1369 BOOST_TEST_EQ(n, 0);
1370 BOOST_TEST_EQ(deleted_res1, -1);
1371
1372 n = 0;
1373 deleted_res1 = -1;
1374 {
1375 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur{ 0, checking_resource_deleter< int >(deleted_res1, n) };
1376 BOOST_TEST_EQ(ur.get(), 0);
1377 BOOST_TEST(ur.allocated());
1378 BOOST_TEST(!!ur);
1379 }
1380 BOOST_TEST_EQ(n, 1);
1381 BOOST_TEST_EQ(deleted_res1, 0);
1382
1383 n = 0;
1384 deleted_res1 = -1;
1385 {
1386 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur{ 10, checking_resource_deleter< int >(deleted_res1, n) };
1387 BOOST_TEST_EQ(ur.get(), 10);
1388 BOOST_TEST(ur.allocated());
1389 ur.release();
1390 BOOST_TEST_EQ(ur.get(), int_resource_traits::make_default());
1391 BOOST_TEST(!ur.allocated());
1392 }
1393 BOOST_TEST_EQ(n, 0);
1394 BOOST_TEST_EQ(deleted_res1, -1);
1395
1396 n = 0;
1397 deleted_res1 = -1;
1398 {
1399 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur{ 10, checking_resource_deleter< int >(deleted_res1, n) };
1400 BOOST_TEST_EQ(ur.get(), 10);
1401 BOOST_TEST(ur.allocated());
1402 ur.reset();
1403 BOOST_TEST(!ur.allocated());
1404 BOOST_TEST_EQ(ur.get(), int_resource_traits::make_default());
1405 BOOST_TEST_EQ(n, 1);
1406 BOOST_TEST_EQ(deleted_res1, 10);
1407 }
1408 BOOST_TEST_EQ(n, 1);
1409
1410 n = 0;
1411 deleted_res1 = -1;
1412 {
1413 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur{ 10, checking_resource_deleter< int >(deleted_res1, n) };
1414 BOOST_TEST_EQ(ur.get(), 10);
1415 BOOST_TEST(ur.allocated());
1416 ur.reset(res: 20);
1417 BOOST_TEST_EQ(n, 1);
1418 BOOST_TEST_EQ(deleted_res1, 10);
1419 deleted_res1 = -1;
1420 BOOST_TEST_EQ(ur.get(), 20);
1421 BOOST_TEST(ur.allocated());
1422 }
1423 BOOST_TEST_EQ(n, 2);
1424 BOOST_TEST_EQ(deleted_res1, 20);
1425
1426 n = 0;
1427 deleted_res1 = -1;
1428 {
1429 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur1{ 10, checking_resource_deleter< int >(deleted_res1, n) };
1430 BOOST_TEST_EQ(ur1.get(), 10);
1431 BOOST_TEST(ur1.allocated());
1432 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur2{ std::move(ur1) };
1433 BOOST_TEST_EQ(ur2.get(), 10);
1434 BOOST_TEST(ur2.allocated());
1435 BOOST_TEST_EQ(ur1.get(), int_resource_traits::make_default());
1436 BOOST_TEST(!ur1.allocated());
1437 }
1438 BOOST_TEST_EQ(n, 1);
1439 BOOST_TEST_EQ(deleted_res1, 10);
1440
1441 n = 0;
1442 deleted_res1 = -1;
1443 int deleted_res2 = -1;
1444 {
1445 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur1{ 10, checking_resource_deleter< int >(deleted_res1, n) };
1446 BOOST_TEST_EQ(ur1.get(), 10);
1447 BOOST_TEST(ur1.allocated());
1448 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur2{ 20, checking_resource_deleter< int >(deleted_res2, n) };
1449 BOOST_TEST_EQ(ur2.get(), 20);
1450 BOOST_TEST(ur2.allocated());
1451 ur2 = std::move(ur1);
1452 BOOST_TEST_EQ(ur2.get(), 10);
1453 BOOST_TEST(ur2.allocated());
1454 BOOST_TEST_EQ(ur1.get(), int_resource_traits::make_default());
1455 BOOST_TEST(!ur1.allocated());
1456 BOOST_TEST_EQ(n, 1);
1457 BOOST_TEST_EQ(deleted_res1, -1);
1458 BOOST_TEST_EQ(deleted_res2, 20);
1459 deleted_res2 = -1;
1460 }
1461 BOOST_TEST_EQ(n, 2);
1462 BOOST_TEST_EQ(deleted_res1, 10);
1463 BOOST_TEST_EQ(deleted_res2, -1);
1464
1465 {
1466 boost::scope::unique_resource< int, empty_resource_deleter< int >, int_resource_traits > ur1;
1467 BOOST_TEST_EQ(ur1.get(), int_resource_traits::make_default());
1468 BOOST_TEST(!ur1.allocated());
1469 boost::scope::unique_resource< int, empty_resource_deleter< int >, int_resource_traits > ur2{ 10, empty_resource_deleter< int >() };
1470 BOOST_TEST_EQ(ur2.get(), 10);
1471 BOOST_TEST(ur2.allocated());
1472 using namespace std;
1473 swap(left&: ur1, right&: ur2);
1474 BOOST_TEST_EQ(ur1.get(), 10);
1475 BOOST_TEST(ur1.allocated());
1476 BOOST_TEST_EQ(ur2.get(), int_resource_traits::make_default());
1477 BOOST_TEST(!ur2.allocated());
1478 }
1479
1480 n = 0;
1481 deleted_res1 = -1;
1482 deleted_res2 = -1;
1483 {
1484 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur1{ 10, checking_resource_deleter< int >(deleted_res1, n) };
1485 BOOST_TEST_EQ(ur1.get(), 10);
1486 BOOST_TEST_EQ(ur1.get_deleter().get_deleted(), &deleted_res1);
1487 BOOST_TEST(ur1.allocated());
1488 boost::scope::unique_resource< int, checking_resource_deleter< int >, int_resource_traits > ur2{ 20, checking_resource_deleter< int >(deleted_res2, n) };
1489 BOOST_TEST_EQ(ur2.get(), 20);
1490 BOOST_TEST_EQ(ur2.get_deleter().get_deleted(), &deleted_res2);
1491 BOOST_TEST(ur2.allocated());
1492 using namespace std;
1493 swap(left&: ur1, right&: ur2);
1494 BOOST_TEST_EQ(n, 0);
1495 BOOST_TEST_EQ(ur1.get(), 20);
1496 BOOST_TEST_EQ(ur1.get_deleter().get_deleted(), &deleted_res2);
1497 BOOST_TEST(ur1.allocated());
1498 BOOST_TEST_EQ(ur2.get(), 10);
1499 BOOST_TEST_EQ(ur2.get_deleter().get_deleted(), &deleted_res1);
1500 BOOST_TEST(ur2.allocated());
1501 }
1502 BOOST_TEST_EQ(n, 2);
1503 BOOST_TEST_EQ(deleted_res1, 10);
1504 BOOST_TEST_EQ(deleted_res2, 20);
1505}
1506
1507#if !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS)
1508
1509struct global_deleter_int
1510{
1511 void operator() (int) noexcept
1512 {
1513 ++g_n;
1514 }
1515};
1516
1517struct global_deleter_ptr
1518{
1519 void operator() (int*) noexcept
1520 {
1521 ++g_n;
1522 }
1523};
1524
1525void check_simple_resource_traits()
1526{
1527 g_n = 0;
1528 {
1529 boost::scope::unique_resource< int, global_deleter_int, boost::scope::unallocated_resource< -1 > > ur;
1530 BOOST_TEST_EQ(ur.get(), -1);
1531 BOOST_TEST(!ur.allocated());
1532 BOOST_TEST(!ur);
1533 }
1534 BOOST_TEST_EQ(g_n, 0);
1535
1536 g_n = 0;
1537 {
1538 boost::scope::unique_resource< int, global_deleter_int, boost::scope::unallocated_resource< -1 > > ur{ -1 };
1539 BOOST_TEST_EQ(ur.get(), -1);
1540 BOOST_TEST(!ur.allocated());
1541 BOOST_TEST(!ur);
1542 }
1543 BOOST_TEST_EQ(g_n, 0);
1544
1545 g_n = 0;
1546 {
1547 boost::scope::unique_resource< int, global_deleter_int, boost::scope::unallocated_resource< -1 > > ur{ 10 };
1548 BOOST_TEST_EQ(ur.get(), 10);
1549 BOOST_TEST(ur.allocated());
1550 BOOST_TEST(!!ur);
1551 }
1552 BOOST_TEST_EQ(g_n, 1);
1553
1554 g_n = 0;
1555 {
1556 boost::scope::unique_resource< int, global_deleter_int, boost::scope::unallocated_resource< -1, -2, -3 > > ur;
1557 BOOST_TEST_EQ(ur.get(), -1);
1558 BOOST_TEST(!ur.allocated());
1559 BOOST_TEST(!ur);
1560
1561 ur.reset(res: -2);
1562 BOOST_TEST_EQ(g_n, 0);
1563 BOOST_TEST_EQ(ur.get(), -2);
1564 BOOST_TEST(!ur.allocated());
1565 BOOST_TEST(!ur);
1566
1567 ur.reset(res: -3);
1568 BOOST_TEST_EQ(g_n, 0);
1569 BOOST_TEST_EQ(ur.get(), -3);
1570 BOOST_TEST(!ur.allocated());
1571 BOOST_TEST(!ur);
1572
1573 ur.reset(res: 10);
1574 BOOST_TEST_EQ(g_n, 0);
1575 BOOST_TEST_EQ(ur.get(), 10);
1576 BOOST_TEST(ur.allocated());
1577 BOOST_TEST(!!ur);
1578 }
1579 BOOST_TEST_EQ(g_n, 1);
1580
1581 g_n = 0;
1582 {
1583 boost::scope::unique_resource< int*, global_deleter_ptr, boost::scope::unallocated_resource< nullptr > > ur;
1584 BOOST_TEST_EQ(ur.get(), static_cast< int* >(nullptr));
1585 BOOST_TEST(!ur.allocated());
1586 BOOST_TEST(!ur);
1587 }
1588 BOOST_TEST_EQ(g_n, 0);
1589
1590 g_n = 0;
1591 {
1592 boost::scope::unique_resource< int*, global_deleter_ptr, boost::scope::unallocated_resource< nullptr > > ur{ &g_n };
1593 BOOST_TEST_EQ(ur.get(), &g_n);
1594 BOOST_TEST(ur.allocated());
1595 BOOST_TEST(!!ur);
1596 }
1597 BOOST_TEST_EQ(g_n, 1);
1598}
1599
1600#endif // !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS)
1601
1602int main()
1603{
1604 check_int();
1605 check_struct();
1606 check_ptr();
1607 check_ref();
1608 check_throw_resource();
1609 check_throw_deleter< default_resource_traits >();
1610 check_throw_deleter< wrapped_int_resource_traits >();
1611 check_throw_deleter_move_constructible_resource();
1612 check_deduction();
1613 check_resource_traits();
1614#if !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS)
1615 check_simple_resource_traits();
1616#endif
1617 return boost::report_errors();
1618}
1619

source code of boost/libs/scope/test/run/unique_resource.cpp