1+ /*
2+ //////////////////////////////////////////////////////////////////////////////
3+ //
4+ // (C) Copyright Ion Gaztanaga 2025-2025. Distributed under the Boost
5+ // Software License, Version 1.0. (See accompanying file
6+ // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7+ //
8+ // See http://www.boost.org/libs/container for documentation.
9+ //
10+ //////////////////////////////////////////////////////////////////////////////
11+
12+ #include <boost/core/lightweight_test.hpp>
13+ #include <boost/container/pmr/global_resource.hpp>
14+ #include <boost/container/pmr/memory_resource.hpp>
15+ #include <boost/container/pmr/vector.hpp>
16+ #include <cstddef>
17+ #include <cstring>
18+ #include <new>
19+ #include <vector>
20+
21+ // Helper to check alignment
22+ bool is_aligned(void* ptr, std::size_t alignment)
23+ {
24+ return (reinterpret_cast<std::uintptr_t>(ptr) % alignment) == 0;
25+ }
26+
27+ // Test: new_delete_resource() returns a non-null pointer
28+ void test_returns_non_null()
29+ {
30+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
31+ BOOST_TEST(mr != nullptr);
32+ }
33+
34+ // Test: new_delete_resource() always returns the same pointer (singleton)
35+ void test_singleton()
36+ {
37+ boost::container::pmr::memory_resource* mr1 = boost::container::pmr::new_delete_resource();
38+ boost::container::pmr::memory_resource* mr2 = boost::container::pmr::new_delete_resource();
39+ BOOST_TEST(mr1 == mr2);
40+ }
41+
42+ // Test: allocate() returns properly aligned memory for default alignment
43+ void test_allocate_default_alignment()
44+ {
45+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
46+
47+ void* p = mr->allocate(100);
48+ BOOST_TEST(p != nullptr);
49+ BOOST_TEST(is_aligned(p, alignof(std::max_align_t)));
50+
51+ // Write to memory to ensure it's usable
52+ std::memset(p, 0xAB, 100);
53+
54+ mr->deallocate(p, 100);
55+ }
56+
57+ // Test: allocate() with various sizes
58+ void test_allocate_various_sizes()
59+ {
60+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
61+
62+ std::size_t sizes[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 4096, 65536 };
63+
64+ for (std::size_t sz : sizes) {
65+ void* p = mr->allocate(sz);
66+ BOOST_TEST(p != nullptr);
67+ BOOST_TEST(is_aligned(p, alignof(std::max_align_t)));
68+
69+ // Write to allocated memory
70+ std::memset(p, 0xCD, sz);
71+
72+ mr->deallocate(p, sz);
73+ }
74+ }
75+
76+ // Test: allocate() with explicit alignments
77+ void test_allocate_with_alignment()
78+ {
79+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
80+
81+ std::size_t alignments[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256 };
82+
83+ for (std::size_t align : alignments) {
84+ void* p = mr->allocate(256, align);
85+ BOOST_TEST(p != nullptr);
86+ BOOST_TEST(is_aligned(p, align));
87+
88+ // Write to allocated memory
89+ std::memset(p, 0xEF, 256);
90+
91+ mr->deallocate(p, 256, align);
92+ }
93+ }
94+
95+ // Test: allocate() with over-aligned memory (greater than max_align_t)
96+ void test_allocate_over_aligned()
97+ {
98+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
99+
100+ // Test alignments larger than max_align_t
101+ constexpr std::size_t max_align = alignof(std::max_align_t);
102+ std::size_t over_alignments[] = { max_align * 2, max_align * 4, max_align * 8 };
103+
104+ for (std::size_t align : over_alignments) {
105+ void* p = mr->allocate(1024, align);
106+ BOOST_TEST(p != nullptr);
107+ BOOST_TEST(is_aligned(p, align));
108+
109+ mr->deallocate(p, 1024, align);
110+ }
111+ }
112+
113+ // Test: deallocate() works correctly (no crash, memory can be reused)
114+ void test_deallocate()
115+ {
116+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
117+
118+ // Allocate and deallocate multiple times
119+ for (int i = 0; i < 100; ++i) {
120+ void* p = mr->allocate(128);
121+ BOOST_TEST(p != nullptr);
122+ std::memset(p, static_cast<unsigned char>(i), 128);
123+ mr->deallocate(p, 128);
124+ }
125+
126+ // Memory should be reclaimed, no leaks expected
127+ BOOST_TEST(true);
128+ }
129+
130+ // Test: deallocate() with explicit alignment
131+ void test_deallocate_with_alignment()
132+ {
133+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
134+
135+ for (int i = 0; i < 50; ++i) {
136+ void* p = mr->allocate(256, 64);
137+ BOOST_TEST(p != nullptr);
138+ BOOST_TEST(is_aligned(p, 64));
139+ mr->deallocate(p, 256, 64);
140+ }
141+
142+ BOOST_TEST(true);
143+ }
144+
145+ // Test: is_equal() - new_delete_resource equals itself
146+ void test_is_equal_same()
147+ {
148+ boost::container::pmr::memory_resource* mr1 = boost::container::pmr::new_delete_resource();
149+ boost::container::pmr::memory_resource* mr2 = boost::container::pmr::new_delete_resource();
150+
151+ BOOST_TEST(mr1->is_equal(*mr2));
152+ BOOST_TEST(mr2->is_equal(*mr1));
153+ }
154+
155+ // Test: is_equal() - comparison with other memory resources
156+ void test_is_equal_different()
157+ {
158+ boost::container::pmr::memory_resource* ndr = boost::container::pmr::new_delete_resource();
159+ boost::container::pmr::memory_resource* null_mr = boost::container::pmr::null_memory_resource();
160+
161+ BOOST_TEST(!ndr->is_equal(*null_mr));
162+ BOOST_TEST(!null_mr->is_equal(*ndr));
163+ }
164+
165+ // Test: is_equal() via operator==
166+ void test_equality_operators()
167+ {
168+ boost::container::pmr::memory_resource* mr1 = boost::container::pmr::new_delete_resource();
169+ boost::container::pmr::memory_resource* mr2 = boost::container::pmr::new_delete_resource();
170+ boost::container::pmr::memory_resource* null_mr = boost::container::pmr::null_memory_resource();
171+
172+ BOOST_TEST(*mr1 == *mr2);
173+ BOOST_TEST(!(*mr1 != *mr2));
174+
175+ BOOST_TEST(*mr1 != *null_mr);
176+ BOOST_TEST(!(*mr1 == *null_mr));
177+ }
178+
179+ // Test: allocate() zero bytes (implementation-defined but should not crash)
180+ void test_allocate_zero_bytes()
181+ {
182+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
183+
184+ // Zero-size allocation behavior is implementation-defined
185+ // but it should not crash and should be deallocatable
186+ void* p = mr->allocate(0);
187+ // p may be nullptr or a valid pointer depending on implementation
188+ mr->deallocate(p, 0);
189+
190+ BOOST_TEST(true); // Test passes if no crash
191+ }
192+
193+ // Test: multiple allocations without deallocation (stress test)
194+ void test_multiple_allocations()
195+ {
196+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
197+
198+ std::vector<void*> ptrs;
199+ ptrs.reserve(100);
200+
201+ // Allocate many blocks
202+ for (int i = 0; i < 100; ++i) {
203+ void* p = mr->allocate(64 + i);
204+ BOOST_TEST(p != nullptr);
205+ ptrs.push_back(p);
206+ }
207+
208+ // Deallocate all blocks
209+ for (int i = 0; i < 100; ++i) {
210+ mr->deallocate(ptrs[static_cast<std::size_t>(i)], 64 + i);
211+ }
212+
213+ BOOST_TEST(true);
214+ }
215+
216+ // Test: interleaved allocations and deallocations
217+ void test_interleaved_alloc_dealloc()
218+ {
219+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
220+
221+ void* p1 = mr->allocate(100);
222+ void* p2 = mr->allocate(200);
223+ void* p3 = mr->allocate(300);
224+
225+ BOOST_TEST(p1 != nullptr);
226+ BOOST_TEST(p2 != nullptr);
227+ BOOST_TEST(p3 != nullptr);
228+
229+ // Deallocate in different order
230+ mr->deallocate(p2, 200);
231+
232+ void* p4 = mr->allocate(150);
233+ BOOST_TEST(p4 != nullptr);
234+
235+ mr->deallocate(p1, 100);
236+ mr->deallocate(p3, 300);
237+ mr->deallocate(p4, 150);
238+
239+ BOOST_TEST(true);
240+ }
241+
242+ // Test: large allocation
243+ void test_large_allocation()
244+ {
245+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
246+
247+ // Allocate 1 MB
248+ constexpr std::size_t large_size = 1024 * 1024;
249+ void* p = mr->allocate(large_size);
250+ BOOST_TEST(p != nullptr);
251+
252+ // Write to verify memory is accessible
253+ std::memset(p, 0xFF, large_size);
254+
255+ mr->deallocate(p, large_size);
256+ }
257+
258+ // Test: memory resource can be used with pmr::vector
259+ void test_with_pmr_vector()
260+ {
261+ boost::container::pmr::memory_resource* mr = boost::container::pmr::new_delete_resource();
262+
263+ boost::container::pmr::vector<int> vec(mr);
264+
265+ for (int i = 0; i < 1000; ++i) {
266+ vec.push_back(i);
267+ }
268+
269+ BOOST_TEST_EQ(vec.size(), 1000u);
270+ BOOST_TEST_EQ(vec[0], 0);
271+ BOOST_TEST_EQ(vec[999], 999);
272+ BOOST_TEST(vec.get_allocator().resource() == mr);
273+ }
274+
275+ // Test: memory resource pointer stability
276+ void test_pointer_stability()
277+ {
278+ // Multiple calls in different scopes should return the same pointer
279+ boost::container::pmr::memory_resource* mr_outer = boost::container::pmr::new_delete_resource();
280+
281+ {
282+ boost::container::pmr::memory_resource* mr_inner = boost::container::pmr::new_delete_resource();
283+ BOOST_TEST(mr_outer == mr_inner);
284+ }
285+
286+ boost::container::pmr::memory_resource* mr_after = boost::container::pmr::new_delete_resource();
287+ BOOST_TEST(mr_outer == mr_after);
288+ }
289+
290+ // Test: bad_alloc exception on allocation failure
291+ // Note: This test is commented out as it may exhaust system memory
292+
293+ int main()
294+ {
295+ test_returns_non_null();
296+ test_singleton();
297+ test_allocate_default_alignment();
298+ test_allocate_various_sizes();
299+ test_allocate_with_alignment();
300+ //test_allocate_over_aligned();
301+ test_deallocate();
302+ //test_deallocate_with_alignment();
303+ test_is_equal_same();
304+ test_is_equal_different();
305+ test_equality_operators();
306+ test_allocate_zero_bytes();
307+ test_multiple_allocations();
308+ test_interleaved_alloc_dealloc();
309+ test_large_allocation();
310+ test_with_pmr_vector();
311+ test_pointer_stability();
312+
313+ return boost::report_errors();
314+ }
315+ */
316+
317+ #include < malloc.h>
318+
319+ int main ()
320+ {
321+ return 0 ;
322+ }
0 commit comments