Commit dfc54dbc authored by BRAMAS Berenger's avatar BRAMAS Berenger

Update alligned memory allocator

parent 55234c38
......@@ -6,6 +6,7 @@
#define INAMEMORY_HPP
#include <cstdint>
#include <cassert>
/**
* Proposes methods to allocate aligned memory.
......@@ -14,10 +15,14 @@
* Note: the alignement must be a power of 2
*/
class InaMemory {
const std::size_t HeaderSize = sizeof(unsigned char*) + sizeof(std::size_t);
struct Header{
unsigned char* originPtr;
std::size_t nbElements;
};
const static std::size_t HeaderSize = sizeof(Header);
template < std::size_t Alignement >
static void* Allocate(const std::size_t inSize, const std::size_t inHeader) {
static void* Allocate(const std::size_t inSize, const std::size_t inNbelements) {
// Return null for empty allocation
if (inSize == 0) {
return nullptr;
......@@ -27,27 +32,20 @@ class InaMemory {
static_assert(Alignement != 0 && ((Alignement - 1) & Alignement) == 0, "Alignement must be a power of 2");
// We will need to store the adress of the real blocks
const std::size_t Offset = (Alignement < HeaderSize ? HeaderSize / Alignement : 1) * Alignement;
const std::size_t Offset = (Alignement < HeaderSize ? (HeaderSize / Alignement) + 1 : 1) * Alignement;
unsigned char* allocatedMemoryPtr = new unsigned char[inSize + Offset - 1];
unsigned char* alignedMemoryPtr = reinterpret_cast< unsigned char* >((reinterpret_cast< std::size_t >(allocatedMemoryPtr) + Offset - 1) & ~(Alignement - 1));
unsigned char* headerPtr = (alignedMemoryPtr - HeaderSize);
unsigned char* allocatedMemoryPtr = new unsigned char[inSize + Offset];
unsigned char* alignedMemoryPtr = reinterpret_cast< unsigned char* >((reinterpret_cast< std::size_t >(allocatedMemoryPtr) + Offset) & ~(Alignement - 1));
assert((reinterpret_cast< std::size_t >(alignedMemoryPtr) & (Alignement-1)) == 0);
Header* headerPtr = reinterpret_cast<Header*>(alignedMemoryPtr - HeaderSize);
// Save real address then header value then alignement
*reinterpret_cast< unsigned char** >(headerPtr) = allocatedMemory;
*reinterpret_cast< std::size_t* >(headerPtr + sizeof(unsigned char*)) = inHeader;
headerPtr->originPtr = allocatedMemoryPtr;
headerPtr->nbElements = inNbelements;
// Return aligned address
return reinterpret_cast< void* >(alignedMemoryAddress);
}
static void Release(const void* ptrToFree) {
// If equal to null do nothing
if (ptrToFree) {
// Retrieve real address
const unsigned char* const* storeRealAddress = reinterpret_cast< const unsigned char* const* >(reinterpret_cast< const unsigned char* >(ptrToFree) - HeaderSize);
delete[] reinterpret_cast< const unsigned char* >(*storeRealAddress);
}
return reinterpret_cast< void* >(alignedMemoryPtr);
}
public:
......@@ -59,24 +57,25 @@ public:
const std::size_t sizeInBytes = (inNbElementsInArray * sizeof(ObjectType));
ObjectType* alignedArray = reinterpret_cast< ObjectType* >(Allocate(sizeInBytes, inNbElementsInArray));
ObjectType* alignedArray = reinterpret_cast< ObjectType* >(Allocate<Alignement>(sizeInBytes, inNbElementsInArray));
for (std::size_t idx = 0; idx < inNbElementsInArray; ++idx) {
new (&alignedArray[idx]) ObjectType();
}
return array;
return alignedArray;
}
template < class ObjectType >
inline void _delete(const ObjectType* ptrToFree) {
static void _delete(const ObjectType* ptrToFree) {
if (ptrToFree) {
const std::size_t numberOfElements = (*reinterpret_cast< const std::size_t* >(reinterpret_cast< const unsigned char* >(ptrToFree) + sizeof(unsigned char*) - HeaderSize));
const Header* headerPtr = reinterpret_cast<const Header*>(reinterpret_cast< const unsigned char* >(ptrToFree) - HeaderSize);
const std::size_t numberOfElements = headerPtr->nbElements;
for (std::size_t idx = 0; idx < numberOfElements; ++idx) {
ptrToFree[idx].~ObjectType();
}
Release(ptrToFree);
delete[] headerPtr->originPtr;
}
}
};
......
///////////////////////////////////////////////////////////////////////////
// Inastemp - Berenger Bramas MPCDF - 2016
// Under MIT Licence, please you must read the LICENCE file.
///////////////////////////////////////////////////////////////////////////
#include "InastempGlobal.h"
#include "Common/InaMemory.hpp"
#include "UTester.hpp"
#include <cmath>
#include <cstring>
#include <vector>
class TestMemo : public UTester< TestMemo > {
using Parent = UTester< TestMemo >;
template <long int alignement>
void TestBasic() {
{
}
for(long int size = 1 ; size < 10 ; ++size){
{
char* vecChar = InaMemory::_new<alignement, char>(size);
UASSERTETRUE(vecChar != nullptr);
UASSERTETRUE((reinterpret_cast<unsigned long>(vecChar) & (alignement-1)) == 0);
InaMemory::_delete(vecChar);
}
{
double* vecDouble = InaMemory::_new<alignement, double>(size);
UASSERTETRUE(vecDouble != nullptr);
UASSERTETRUE((reinterpret_cast<unsigned long>(vecDouble) & (alignement-1)) == 0);
InaMemory::_delete(vecDouble);
}
{
std::vector<double>* vecDouble = InaMemory::_new<alignement, std::vector<double> >(size);
UASSERTETRUE(vecDouble != nullptr);
UASSERTETRUE((reinterpret_cast<unsigned long>(vecDouble) & (alignement-1)) == 0);
InaMemory::_delete(vecDouble);
}
}
}
void SetTests() {
Parent::AddTest(&TestMemo::TestBasic<1>, "Basic memo test 1");
Parent::AddTest(&TestMemo::TestBasic<2>, "Basic memo test 2");
Parent::AddTest(&TestMemo::TestBasic<4>, "Basic memo test 4");
Parent::AddTest(&TestMemo::TestBasic<8>, "Basic memo test 8");
Parent::AddTest(&TestMemo::TestBasic<16>, "Basic memo test 16");
Parent::AddTest(&TestMemo::TestBasic<32>, "Basic memo test 32");
}
};
int main() {
return TestMemo().Run();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment