#include <iostream>
using namespace std;
constexpr int MEMORYPOOL_ALIGNMENT = 8; // length aligned
// memory block
template<typename _T>
struct MemoryBlock {
int nSize; // memory block size, in bytes
int nFree; // allocate a block of memory units Remaining
int nFirst; // first unit remaining number
MemoryBlock * pNext; // pointer to point to a next memory block
char aData [1]; // tag memory start position
//constructor
MemoryBlock (int nUnitSize, // storage unit size, sizeof T
int nUnitAmount): // size of the memory block to store the unit for computing
nSize(nUnitAmount * nUnitSize), nFree(nUnitAmount - 1), nFirst(1), pNext(nullptr) {
// first unit assigned when calling the constructor, it is a need to reduce the nFree
// next unit can be assigned a sequence number recorded in the first two bytes of the current unit
char * = ppDate aData;
cout << "the head ptr of memory ppDate = " << (int)*ppDate << endl;
for(int i = 1; i < nUnitAmount; ++i) {
// can be assigned a number of units currently stored in the storage unit
(*(uint16_t*)ppDate) = i;//short --- 16
cout << "the next available of memory is :" << (int)*ppDate << endl;
ppDate + = nUnitSize; // pointer to the next unit
}
cout << "===========================call MemoryBlock constructor\n";
}
// overload
void* operator new(size_t, int nUnitSize, int nUnitAmount) {
// length memoryBlock memory space plus the total length of the object storage space
return ::operator new(sizeof(MemoryBlock) + nUnitAmount * nUnitSize);
}
void operator delete(void *pBlock) {
::operator delete(pBlock);
cout << "================================call MemoryBlock destructor\n";
}
};
// memory pool
template<typename _T>
struct MemoryPool {
int nInitSize; // allocation size for the first time
int nGrowSize; // increment size
int nUnitSize; // storage unit size
MemoryBlock<_T> *pBlock;
MemoryPool(int _nGrowSize = 10, int _nInitSize = 3)
: nInitSize(_nInitSize), nGrowSize(_nGrowSize), pBlock(nullptr), nUnitSize(sizeof(_T)) {
cout << "==========================call MemoryPool constructor\n";
// memory block sizing
auto _size = sizeof(_T);
if(_size > 4) {
nUnitSize = (_size + MEMORYPOOL_ALIGNMENT - 1) & ~(MEMORYPOOL_ALIGNMENT - 1);
}
else if(_size < 2) {
nUnitSize = 2;
}
else
nUnitSize = 4;
}
~MemoryPool() {
MemoryBlock<_T> * pMyBlock = pBlock;
while(pMyBlock != nullptr) {
pMyBlock = pMyBlock->pNext;
delete pMyBlock;
}
cout << "================================call MemoryPool destructor\n";
}
void *allocate(size_t num) { //typename Allocator<_T>::const_pointer hint = 0
for(int i = 0; i < num; ++i) {
if(pBlock == nullptr) {
//create memoryBlock
pBlock = (MemoryBlock<_T>*) new (nUnitSize, nInitSize) MemoryBlock<_T>(nUnitSize, nInitSize);
return (void *)pBlock->aData;
}
// find the right memory block
MemoryBlock<_T> *pMyBlock = pBlock;
while(pMyBlock != nullptr && pMyBlock->nFree == 0) pMyBlock = pMyBlock->pNext;
if(pMyBlock != nullptr) {
cout << "to find the memory space, first =" << pMyBlock-> nFirst << endl;
char *pFree = pMyBlock->aData + pMyBlock->nFirst * nUnitSize;
pMyBlock->nFirst = *((uint16_t *)pFree);
pMyBlock->nFree--;
return (void *)pFree;
}
else {
// not found, indicating that the memory block has been exhausted
if(nGrowSize == 0) return NULL;
cout << "allocate new memoryBlock\n";
pMyBlock = (MemoryBlock<_T>*) new (nUnitSize, nGrowSize) MemoryBlock<_T> (nUnitSize, nGrowSize);
// failure to return
if(pMyBlock == nullptr) return NULL;
// successful in the linked list
pMyBlock->pNext = pBlock;
pBlock = pMyBlock;
return (void *)pMyBlock->aData;
}
}
}
void free(void *pFree) {
cout << "relese room\n";
// find memory
MemoryBlock<_T> * pMyBlock = pBlock;
MemoryBlock<_T> * preBlock = nullptr;
while (pMyBlock != nullptr && (pBlock->aData > pFree || pMyBlock->aData + pMyBlock->nSize)) {
preBlock = pMyBlock;
pMyBlock = pMyBlock->next;
}
//
if(pMyBlock != nullptr) {
// modify the array list
*((uint16_t*)pFree) = pMyBlock->nFirst;
pMyBlock->nFirst = (uint16_t)((uint32_t)pFree - (uint32_t)pMyBlock->aData) / nUnitSize;
pMyBlock->nFree++;
// need to free up memory to the OS
if(pMyBlock->nSize == pMyBlock->nFree * nUnitSize) {
// delete node
delete pMyBlock;
}
else {
// The block is inserted into the first team
preBlock = pMyBlock->pNext;
pMyBlock->pNext = nullptr;
pBlock = pMyBlock;
}
}
}
};
class User {
int s;
double s1;
double s3;
public:
User(int x) : s(x) {
cout << "*********************call User constructor\n";
}
int get() const { return s; };
~User() {
cout << "************************call User destructor\n";
}
};
int main () {
MemoryPool<User> pool;
User *dp1 = (User *)pool.allocate(1);
cout << "dp1 = " << dp1 << endl;
new (dp1) User (1111);
cout << "the value of object is " << dp1->get() << endl;
User *dp2 = (User *)pool.allocate(1);
cout << "dp2 = " << dp2 << endl;
new (dp2) User (2222);
cout << "the value of object is " << dp2->get() << endl;
User *dp3 = (User *)pool.allocate(1);
cout << "dp3 = " << dp3 << endl;
new (dp3) User (3333);
cout << "the value of object is " << dp3->get() << endl;
User *dp4 = (User *)pool.allocate(1);
cout << "dp4 = " << dp4 << endl;
new (dp4) User (4444);
cout << "the value of object is " << dp4->get() << endl;
User *dp5 = (User *)pool.allocate(1);
cout << "dp5 = " << dp5 << endl;
new (dp5) User (5555);
cout << "the value of object is " << dp5->get() << endl;
return 0;
}