mardi 6 décembre 2022

Pointer metadata for sized, aligned storage

I am writing an allocator (for simplicity, let's assume nothing fails or throws):

struct AllocationHeader
{
  std::size_t size;
  std::size_t align;
};

void *aligned_allocate(std::size_t requested_size, std::size_t alignment)
{
  constexpr auto header_size = sizeof(AllocationHeader);
  const auto     total_size  = header_size + requested_size + alignment;
  auto           alloced_ptr = ::new unsigned char[total_size];

  ::new (alloced_ptr) AllocationHeader{requested_size, alignment};
  
  auto ret_ptr        = static_cast<void *>(alloced_ptr + header_size);
  auto remaining_size = total_size - header_size;
  return std::align(alignment, requested_size, ret_ptr, remaining_size);
}

When I deallocate I want to recover the planted metadata

void aligned_deallocate(void *ptr)
{
  constexpr auto header_size  = sizeof(AllocationHeader);
  // surely this is wrong
  auto           header_start = reinterpret_cast<unsigned char *>(ptr) - header_size;
  auto           header       = reinterpret_cast<AllocationHeader *>(header_start);
  
  do_something_with(header->size, header->align);
  // rest of deallocation...
}

But surely the conversion back to AllocationHeader is wrong. The original align could in theory be anything (assuming power of 2) including > std::max_align_t.

So how do I portably recover how much std::align() shifted the pointer by? I'm limited to C++11.

EDIT:

I suppose I can do the shifting first:

void *aligned_allocate(std::size_t requested_size, std::size_t alignment)
{
  constexpr auto header_size    = sizeof(AllocationHeader);
  const auto     total_size     = header_size + requested_size + alignment;
  auto           alloced_ptr    = ::new unsigned char[total_size];
  auto           ret_ptr        = static_cast<void *>(alloced_ptr + header_size);
  auto           remaining_size = total_size - header_size;
  
  std::align(alignment, requested_size, ret_ptr, remaining_size);
  ::new (reinterpret_cast<unsigned char *>(ret_ptr) - header_size) AllocationHeader{requested_size, alignment};
  return ret_ptr;
}

But then AllocationHeader may constructed misaligned...

Aucun commentaire:

Enregistrer un commentaire