mirror of
https://github.com/boostorg/container.git
synced 2026-08-04 01:04:15 +02:00
Added overaligned support for monotonic_buffer_resource
This commit is contained in:
@@ -2832,6 +2832,12 @@ collect them containers and build [*Boost.Container], a library targeted to a wi
|
||||
|
||||
[section:release_notes Release Notes]
|
||||
|
||||
[section:release_notes_boost_1_93_00 Boost 1.93 Release]
|
||||
|
||||
* Added overaligned support for [classref boost::container::pmr::monotonic_buffer_resource monotonic_buffer_resource].
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:release_notes_boost_1_92_00 Boost 1.92 Release]
|
||||
|
||||
* Added new [classref boost::container::hub hub] container designed by Joaqu\u00EDn M. L\u00F3pez Mu\u00F1oz.
|
||||
|
||||
@@ -145,13 +145,20 @@ void* monotonic_buffer_resource::do_allocate(std::size_t bytes, std::size_t alig
|
||||
//m_current_buffer_size in allocate_from_current().
|
||||
std::size_t aligner = 0u;
|
||||
if(!m_current_buffer || this->remaining_storage(alignment, aligner) < bytes || m_current_buffer_size < aligner){
|
||||
//Update next_buffer_size to at least bytes
|
||||
//The block obtained from the upstream resource is only guaranteed to be
|
||||
//max_align-aligned, so for an over-aligned request reserve enough extra
|
||||
//space to be able to realign the returned block inside the new buffer.
|
||||
const std::size_t extra_for_alignment = (alignment > memory_resource::max_align) ? (alignment - 1u) : 0u;
|
||||
//Update next_buffer_size to at least bytes plus the realignment slack
|
||||
this->increase_next_buffer_at_least_to(bytes + extra_for_alignment);
|
||||
//Now allocate and update internal data
|
||||
m_current_buffer = (char*)m_memory_blocks.allocate(m_next_buffer_size);
|
||||
m_current_buffer_size = m_next_buffer_size;
|
||||
this->increase_next_buffer();
|
||||
//Recompute the alignment padding for the freshly obtained buffer (which is
|
||||
//only max_align-aligned). This is zero unless the request is over-aligned,
|
||||
//in which case the reserved slack above guarantees "aligner + bytes" fits.
|
||||
this->remaining_storage(alignment, aligner);
|
||||
}
|
||||
//Enough internal storage, extract from it. For a zero-sized block this returns
|
||||
//the current aligned position without consuming bytes, so repeated zero-sized
|
||||
|
||||
@@ -508,6 +508,99 @@ void test_do_allocate_zero()
|
||||
BOOST_TEST(mrl.m_info.size() == 0u);
|
||||
}
|
||||
|
||||
void test_do_allocate_overaligned()
|
||||
{
|
||||
//Over-aligned requests (alignment > memory_resource::max_align) must be
|
||||
//honored. The buffers obtained from upstream are only max_align-aligned
|
||||
//(memory_resource_logger uses std::malloc), so the resource has to reserve
|
||||
//extra space and realign the returned block inside the freshly obtained
|
||||
//buffer. These tests verify the returned pointer honors the requested
|
||||
//alignment in every code path.
|
||||
const std::size_t max_align = memory_resource::max_align;
|
||||
memory_resource_logger mrl;
|
||||
|
||||
//(1) Over-aligned allocation from a fresh resource must trigger an upstream
|
||||
// buffer and return a correctly over-aligned, fully usable block.
|
||||
{
|
||||
const std::size_t over = max_align*4u;
|
||||
const std::size_t bytes = over*3u + 1u;
|
||||
monotonic_buffer_resource m(&mrl);
|
||||
void *const p = m.allocate(bytes, over);
|
||||
BOOST_TEST(p != 0);
|
||||
BOOST_TEST((std::size_t(p) % over) == 0u);
|
||||
//A single upstream buffer was requested for it
|
||||
BOOST_TEST(mrl.m_info.size() == 1u);
|
||||
//The whole block must be usable: writing every byte would trip ASAN or
|
||||
//corrupt the heap if the buffer were too small after realignment.
|
||||
char *const cp = (char*)p;
|
||||
for(std::size_t i = 0; i != bytes; ++i){
|
||||
cp[i] = (char)0xABu;
|
||||
}
|
||||
}
|
||||
BOOST_TEST(mrl.m_mismatches == 0u);
|
||||
BOOST_TEST(mrl.m_info.size() == 0u);
|
||||
|
||||
//(2) A sequence of increasing over-alignments must each be honored.
|
||||
{
|
||||
monotonic_buffer_resource m(&mrl);
|
||||
for(std::size_t a = max_align*2u; a <= max_align*32u; a *= 2u){
|
||||
void *const p = m.allocate(a/2u, a);
|
||||
BOOST_TEST(p != 0);
|
||||
BOOST_TEST((std::size_t(p) % a) == 0u);
|
||||
}
|
||||
}
|
||||
BOOST_TEST(mrl.m_mismatches == 0u);
|
||||
BOOST_TEST(mrl.m_info.size() == 0u);
|
||||
|
||||
//(3) Over-aligned allocation served from a user-supplied buffer (realigned in
|
||||
// place, no upstream) and then from a fresh buffer after exhaustion.
|
||||
{
|
||||
//256-byte, 64-aligned external buffer
|
||||
boost::move_detail::aligned_storage<256u, 64u>::type storage;
|
||||
const std::size_t over = 64u;
|
||||
monotonic_buffer_resource m(&storage, sizeof(storage), &mrl);
|
||||
char *const base = (char*)&storage;
|
||||
//Misalign the current position by 1 byte
|
||||
void *const one = m.allocate(1u, 1u);
|
||||
BOOST_TEST(one == base);
|
||||
//Over-aligned request must be realigned within the same buffer (no upstream)
|
||||
void *const p = m.allocate(over, over);
|
||||
BOOST_TEST((std::size_t(p) % over) == 0u);
|
||||
BOOST_TEST(p == base + over);
|
||||
BOOST_TEST(mrl.m_info.size() == 0u);
|
||||
//Exhaust the remaining storage
|
||||
void *const ex = m.allocate(m.remaining_storage(1u), 1u);
|
||||
(void)ex;
|
||||
BOOST_TEST(m.remaining_storage(1u) == 0u);
|
||||
//Over-aligned request now must go upstream and still be correctly aligned
|
||||
void *const q = m.allocate(over, over);
|
||||
BOOST_TEST(q != 0);
|
||||
BOOST_TEST((std::size_t(q) % over) == 0u);
|
||||
BOOST_TEST(mrl.m_info.size() == 1u);
|
||||
}
|
||||
BOOST_TEST(mrl.m_mismatches == 0u);
|
||||
BOOST_TEST(mrl.m_info.size() == 0u);
|
||||
|
||||
//(4) A zero-sized over-aligned request is also honored (returns an aligned
|
||||
// address) following the same rules as any other zero-sized allocation.
|
||||
{
|
||||
boost::move_detail::aligned_storage<128u, 64u>::type storage;
|
||||
const std::size_t over = 64u;
|
||||
monotonic_buffer_resource m(&storage, sizeof(storage), &mrl);
|
||||
char *const base = (char*)&storage;
|
||||
//Misalign, then a zero-sized over-aligned request returns the next aligned
|
||||
//position inside the buffer without consuming real storage nor upstream.
|
||||
void *const one = m.allocate(1u, 1u);
|
||||
BOOST_TEST(one == base);
|
||||
void *const z = m.allocate(0u, over);
|
||||
BOOST_TEST(z == base + over);
|
||||
BOOST_TEST((std::size_t(z) % over) == 0u);
|
||||
BOOST_TEST(mrl.m_info.size() == 0u);
|
||||
}
|
||||
BOOST_TEST(mrl.m_mismatches == 0u);
|
||||
BOOST_TEST(mrl.m_info.size() == 0u);
|
||||
}
|
||||
|
||||
void test_do_deallocate()
|
||||
{
|
||||
memory_resource_logger mrl;
|
||||
@@ -626,6 +719,7 @@ int main()
|
||||
test_upstream_resource();
|
||||
test_do_allocate();
|
||||
test_do_allocate_zero();
|
||||
test_do_allocate_overaligned();
|
||||
test_do_deallocate();
|
||||
test_do_is_equal();
|
||||
test_release();
|
||||
|
||||
Reference in New Issue
Block a user