Created
December 30, 2019 22:40
-
-
Save mshabunin/cb1e5d57c543d19ba8cba630e31fef58 to your computer and use it in GitHub Desktop.
Memory pool with two modes: safe and fast
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstddef> | |
#include <iostream> | |
#include <list> | |
// #define SAFE | |
using namespace std; | |
class Pool | |
{ | |
// interface | |
class IBlock | |
{ | |
public: | |
virtual ~IBlock() {} | |
virtual void * commit(void *) = 0; | |
virtual size_t getSize() const = 0; | |
}; | |
// implementation | |
template <typename T> | |
class SafeBlock : public IBlock | |
{ | |
public: | |
SafeBlock(T *&ptr_, size_t sz_) : ptr(ptr_) | |
{ | |
cout << "One allocate " << sizeof(ptr) * sz_ << endl; | |
ptr = new T[sz_]; | |
} | |
~SafeBlock() | |
{ | |
delete[] ptr; | |
ptr = 0; | |
} | |
void * commit(void *) override { return 0; } | |
size_t getSize() const override { return 0; } | |
private: | |
T *&ptr; | |
}; | |
// implementation | |
template <typename T> | |
class FastBlock : public IBlock | |
{ | |
public: | |
FastBlock(T *&ptr_, size_t sz_) : ptr(ptr_), sz(sz_) {} | |
~FastBlock() {} | |
void *commit(void * buf) override | |
{ | |
const size_t d = (unsigned long long)buf % sizeof(T); | |
if (d != 0) | |
{ | |
cout << "Align pointer: " << buf << " -> "; | |
buf = (void*)((unsigned long long)buf + (sizeof(T) - d)); | |
cout << buf << endl; | |
} | |
cout << "Use pointer: " << buf << endl; | |
ptr = (T*)buf; | |
buf = (void*)((T*)buf + sz); | |
return buf; | |
} | |
size_t getSize() const override { return sizeof(T) * sz; } | |
private: | |
T *&ptr; | |
size_t sz; | |
}; | |
public: | |
Pool(bool safe_ = true) : safe(safe_), buf(0) {} | |
~Pool() | |
{ | |
for(IBlock * b : blocks) | |
{ | |
delete b; | |
} | |
if (buf) | |
{ | |
cout << "Cleanup buf" << endl; | |
delete[] buf; | |
} | |
} | |
template <typename T> | |
void allocate(T*&ptr, size_t num) | |
{ | |
if (!safe) | |
blocks.push_front(new FastBlock<T>(ptr, num)); | |
else | |
blocks.push_front(new SafeBlock<T>(ptr, num)); | |
} | |
void commit() | |
{ | |
if (!safe) | |
{ | |
size_t totalSize = 0; // bytes | |
for(IBlock * b : blocks) | |
{ | |
totalSize += b->getSize() + 64; // alignment | |
} | |
cout << "Single allocate: " << totalSize << " bytes" << endl; | |
buf = new char[totalSize]; | |
char *ptr = buf; | |
for(IBlock * b : blocks) | |
{ | |
ptr = (char*)b->commit((void*)ptr); | |
} | |
} | |
} | |
private: | |
bool safe; | |
list<IBlock*> blocks; | |
char * buf; | |
}; | |
void test(bool s) | |
{ | |
char * u = 0; | |
int * a = 0; | |
double * b = 0; | |
cout << a << ", " << b << ", " << (void*)u << endl; | |
{ | |
Pool p(s); | |
cout << "Allocate" << endl; | |
p.allocate<int>(a, 10); | |
p.allocate(u, 3); | |
p.allocate<double>(b, 20); | |
cout << a << ", " << b << ", " << (void*)u << endl; | |
cout << "Commit" << endl; | |
p.commit(); | |
cout << a << ", " << b << ", " << (void*)u << endl; | |
} | |
cout << "Cleanup" << endl; | |
cout << a << ", " << b << ", " << (void*)u << endl; | |
} | |
int main() | |
{ | |
cout << "==========" << endl; | |
test(true); | |
cout << "==========" << endl; | |
test(false); | |
cout << "==========" << endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment