On 10/3/2017 at 9:39 AM, Finalspace said:void *AllocateAlignedMemory(const size_t size, const size_t alignment) { assert(size > 0); assert((alignment > 0) && !(alignment & (alignment - 1))); // Allocate empty memory to hold a size of a pointer + the actual size + alignment padding size_t newSize = sizeof(void *) + size + (alignment << 1); void *basePtr = AllocateMemory(newSize); // The resulting address starts after the stored base pointer void *alignedPtr = (void *)((uintptr_t)basePtr + sizeof(void *)); // Move the resulting address to a aligned one when address is not aligned to the given alignment uintptr_t mask = alignment - 1; if ((alignment > 1) && (((uintptr_t)alignedPtr & mask) != 0)) { *(uintptr_t *)alignedPtr += ((uintptr_t)alignment - ((uintptr_t)alignedPtr & mask)); } // Write the base pointer before the alignment pointer *(void **)((void *)((uintptr_t)alignedPtr - sizeof(void *))) = basePtr; return(alignedPtr); }
I recently noticed some code very similar to your allocator in the book Game Engine Architecture (2nd Edition). The author adds the alignment to the requested size, since worst case you are misaligned by alignment - 1 bytes. Since alignment bytes are added instead of alignment - 1 bytes, there is always a spare byte which is used for storing the adjustment, needed for recovering the original pointer when freeing. This approach only works for alignments of 128 bytes or lower (since the next power of 2, 256, cannot be stored in one byte).
Your approach handles all alignments by explicitly making room for a complete pointer instead of an offset. Though this makes me wonder if you cannot replace alignment << 1 by alignment - 1?