c++memorymemory-alignment

Some memory alignment magic


I am now documenting a header for Variant Vector container. The file also includes some template classes, for example:

template <typename T>
struct TypeMemoryRequirement
{
  static constexpr size_t size_of = sizeof(T);
  static constexpr size_t aling_of = alignof(T);
  // extra space for align the pointer
  static constexpr size_t value = size_of + aling_of - 1;
  static constexpr size_t array_of(size_t count)
  {
    // only the first element gets aligned all follow up are tightly packed
    return 0 == count ? 0 : (value + ((count - 1) * size_of));
  }
  static void *align_pointer(void *ptr)
  {
    auto asInt = reinterpret_cast<uintptr_t>(ptr);
    asInt = (asInt + aling_of - 1) & ~(aling_of - 1);
    return reinterpret_cast<void *>(asInt);
  }
  static const void *align_pointer(const void *ptr)
  {
    auto asInt = reinterpret_cast<uintptr_t>(ptr);
    asInt = (asInt + aling_of - 1) & ~(aling_of - 1);
    return reinterpret_cast<const void *>(asInt);
  }
};

I have basic understanding of memory alignment, however I cannot understand what value static member is and why it is calculated as it is. I see that it is used in array_of method. I also cannot understand it.

I have scanned throught the rest of the header (2k lines of code) and failed to comprehend the usage of the code above. If someone could please help me get into this block of code, I would be very grateful


Solution

  • The idea is that you want to compute the total amount of memory that you will require. That's what the array_of static member function does. The reasoning is hinted at in the comment.

    Example

    Imagine you have a type of size and alignment 4 and you have 10 of it. Then, if you wanted to place these in an unaligned buffer (i.e. a buffer with alignment 1) then the first value might, in the worst case, waste up to 3 byte (that's 4-1). This is because the buffer might start at address 401, which means the first, second and third address (401, 402, 403) are not usable. Hence the total size required for the worst case is (4-1) + 4*10 or 7+4+...+4.

    General

    The oddly named value constant merely says how many bytes the first entry consumes and the remaining entries are computed by simple multiplication: value + (count-1)*size_of = size_of + aling_of - 1 + (count-1)*size_of = align_of-1 + count*size_of.