Skip to content

Commit f29a4c8

Browse files
committed
Make new_delete_resource_imp and null_memory_resource_imp "final"
1 parent e4fcf4b commit f29a4c8

File tree

2 files changed

+324
-2
lines changed

2 files changed

+324
-2
lines changed

src/global_resource.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace boost {
2323
namespace container {
2424
namespace pmr {
2525

26-
class new_delete_resource_imp
26+
class new_delete_resource_imp BOOST_FINAL
2727
: public memory_resource
2828
{
2929
public:
@@ -41,7 +41,7 @@ class new_delete_resource_imp
4141
{ return &other == this; }
4242
};
4343

44-
struct null_memory_resource_imp
44+
struct null_memory_resource_imp BOOST_FINAL
4545
: public memory_resource
4646
{
4747
public:

test/new_delete_resource_test.cpp

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
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

Comments
 (0)