SHARE
TWEET

Untitled

a guest Jun 19th, 2017 45 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //StaticBuffer.h
  2.  
  3. //This file provides a class which allocates memory from a preallocated heap, in as quick a manner as possible.
  4. //Essentially, it provides a second stack for the program, one which never gets deallocated.
  5. //Usage: StaticMemoryAllocator::allocate(size_t bytes) returns a safely aligned void*
  6.  
  7. #ifndef PlaneGC_StaticBuffer_h
  8. #define PlaneGC_StaticBuffer_h
  9.  
  10. #include "Allocators.h"
  11.  
  12. namespace PlaneGC {
  13.  
  14. class StaticBuffer {
  15. public:
  16.     static const size_t blocksize= 0x10000; //How many bytes it will allocate at a time. It is also the max bytes it can allocate per request
  17.  
  18.     template<typename T> class stl_wrapper {
  19.     public:
  20.         typedef T value_type;
  21.         typedef size_t size_type;
  22.         typedef ptrdiff_t difference_type;
  23.         typedef T* pointer;
  24.         typedef const T* const_pointer;
  25.         typedef T& reference;
  26.         typedef const T& const_reference;
  27.  
  28.         stl_wrapper() { };
  29.         stl_wrapper(const stl_wrapper&) { };
  30.         template <class U> stl_wrapper(const stl_wrapper<U>&) { };
  31.  
  32.         size_t max_size() const { return max((size_t)1, blocksize / sizeof(T)); };
  33.  
  34.         template<class U> struct rebind { typedef stl_wrapper<U> other; };
  35.         pointer address(reference r) { return &r; }
  36.         const_pointer address(const_reference r) { return &r; }
  37.  
  38.         pointer allocate(size_type n, const void* hint= 0) { return (T*)StaticBuffer::allocate(n*sizeof(T)); };
  39.         void deallocate(pointer p, size_type n) { StaticBuffer::deallocate(p, n*sizeof(T)); };
  40.  
  41.         void construct(pointer p, const T& val) { new(p) T(val); };
  42.         void destroy(pointer p) { p->~T(); };
  43.     };
  44.  
  45. private:
  46.     class Block {
  47.     private:
  48.         Block(Block* previous_, uint bytes) {
  49.             previous= 0;
  50.             next= 0;
  51.             InsertAfter(previous_);
  52.             remaining= bytes;
  53.             head= (byte*)this + GetPaddedTotal(sizeof(*this));
  54.         };
  55.         ~Block() { RemoveLinks(); };
  56.     public:
  57.         static Block* CreateBlock(size_t minimum= StaticBuffer::blocksize) {
  58.             size_t size= max(minimum, StaticBuffer::blocksize);
  59.             return new(new byte[GetPaddedTotal(sizeof(Block)) + size]) Block(StaticBuffer::head(), size);
  60.         };
  61.         static void DestroyBlock(Block* block) {
  62.             if(!block) return;
  63.             block->~Block();
  64.             delete[] (byte*) block;
  65.         };;
  66.     private:
  67.         void InsertAfter(Block* previous_) {
  68.             if(previous_ == this) return;
  69.             RemoveLinks();
  70.             if(previous= previous_) {
  71.                 if(next= previous->next) next->previous= this;
  72.                 previous->next= this;
  73.             }
  74.         };
  75.         void RemoveLinks() {
  76.             if(StaticBuffer::head() == this) StaticBuffer::head()= next ? next : previous;
  77.             if(StaticBuffer::root() == this) StaticBuffer::root()= previous ? previous : next;
  78.             if(previous) previous->next= next;
  79.             if(next) next->previous= previous;
  80.         };
  81.         void SortIntoList() {
  82.             if(!previous) return;
  83.             //Moving this block to a position in the linked list where it will be sorted by bytesremaining
  84.             Block* current= previous;
  85.             while((current->remaining > remaining) && (current->previous)) {
  86.                 current= current->previous;
  87.             }
  88.             InsertAfter(current);
  89.         };
  90.  
  91.     public:
  92.         void* allocate(size_t bytes) {
  93.             assert(this == StaticBuffer::head());
  94.             if(remaining >= bytes) {
  95.                 void* result= head;
  96.                 head += bytes;
  97.                 remaining -= bytes;
  98.                 return result;
  99.             }else{
  100.                 Block* current= previous;
  101.                 while(current->previous && (current->remaining >= bytes)) {
  102.                     current= current->previous;
  103.                 }
  104.                 if(current->next && (current->next->remaining >= bytes)) {
  105.                     //found the block with the least free space which can take this request
  106.                     current= current->next;
  107.                     current->InsertAfter(this);
  108.                 }else{
  109.                     //no existing block had enough bytes
  110.                     current= CreateBlock(bytes);
  111.                 }
  112.                 StaticBuffer::head()= current;
  113.                 SortIntoList();
  114.                 return next->allocate(bytes);
  115.             }
  116.         };
  117.  
  118.     private:
  119.         Block* previous;
  120.         Block* next;
  121.         byte* head;
  122.         size_t remaining;
  123.     };
  124.  
  125. public:
  126.     StaticBuffer() {
  127.         inc();
  128.     };
  129.  
  130.     ~StaticBuffer() {
  131.         dec();
  132.     };
  133.  
  134.     static void inc() { ++reference_count(); };
  135.     static void dec() {
  136.         if(!(--reference_count())) {
  137.             lock();
  138.             while(root()) Block::DestroyBlock(root());
  139.             unlock();
  140.         }
  141.     };
  142.  
  143.     static void* allocate(size_t bytes) {
  144.         lock();
  145.         void* v= head()->allocate(bytes);
  146.         if(v) {
  147.             ++allocated_count();
  148.             allocated_bytes() += bytes;
  149.         }
  150.         unlock();
  151.  
  152.         return v;
  153.     };
  154.  
  155.     static void deallocate(void* memory, size_t bytes) {
  156.         deallocated_count() += bytes;
  157.     };
  158.  
  159.     static size_t& reference_count() { static size_t v= 0; return v; };
  160.     static size_t& allocated_count() { static size_t v= 0; return v; };
  161.     static size_t& deallocated_count() { static size_t v= 0; return v; };
  162.     static size_t& allocated_bytes() { static size_t v= 0; return v; };
  163.  
  164. private:
  165.     static Block*& root() { static Block* v= Block::CreateBlock(); return v; };
  166.     static Block*& head() { static Block* v= root(); return v; };
  167.    
  168.     #ifdef PlaneThread_h
  169.     static PlaneThread::SpinLock& GetLock() { static PlaneThread::SpinLock v; return v; };
  170.     static void lock() { GetLock().lock(); };
  171.     static void unlock() { GetLock().release(); };
  172.     #else
  173.     static void lock() { };
  174.     static void unlock() { };
  175.     #endif
  176.  
  177.     friend class Block;
  178. };
  179.  
  180. const StaticBuffer StaticBuffer_handle;
  181.  
  182. }; //end namespace
  183.  
  184. #endif //#ifndef PlaneGC_StaticBuffer_h
RAW Paste Data
Want to get better at C++?
Learn to code C++ in 2017
Pastebin PRO Summer Special!
Get 40% OFF on Pastebin PRO accounts!
Top