mem_pool.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) Sergey P. Derevyago, 2008-2009.
00003  *
00004  * Permission to copy, use, modify, sell and distribute this software is granted
00005  * provided this copyright notice appears in all copies.
00006  * This software is provided "as is" without express or implied warranty, and
00007  * with no claim as to its suitability for any purpose.
00008  *
00009  */
00010 
00016 #include <ders/mem_pool.hpp>
00017 #include <vector>
00018 #include <stdio.h>
00019 #include <ders/hash_vec.hpp>
00020 
00021 namespace {
00022 
00023 using namespace std;
00024 using namespace ders;
00025 
00026 struct mp_impl {
00027        static const size_t MOS1=256;
00028        static const size_t MOS2=8*1024;
00029        static const size_t SZVP=sizeof(void*);
00030        static const size_t SZVP8=SZVP*8;
00031        static const size_t HEADS1_SIZE=(MOS1-1)/SZVP+1;
00032        static const size_t HEADS2_SIZE=(MOS2-MOS1-1)/SZVP8+1;
00033 
00034        size_t max_chunk_size;
00035        size_t min_objs_in_chunk;
00036        vector<void*> chunks;
00037        void* heads1[HEADS1_SIZE];
00038        void* heads2[HEADS2_SIZE];
00039 #ifndef NDEBUG
00040        hash_vec<void*, size_t> allocated;
00041 #endif
00042 
00043        mp_impl(size_t mcs, size_t moic);
00044        ~mp_impl();
00045 
00046        void* new_chunk(size_t size);
00047        void format_new_chunk(void*& head, size_t size, size_t grid);
00048 };
00049 
00050 mp_impl::mp_impl(size_t mcs, size_t moic)
00051 #ifndef NDEBUG
00052   : allocated(1001)
00053 #endif
00054 {
00055  assert(moic>=1);
00056 
00057  max_chunk_size=mcs;
00058  min_objs_in_chunk=moic;
00059  chunks.reserve(64);
00060  for (int i=0, end=HEADS1_SIZE; i<end; i++) heads1[i]=0;
00061  for (int i=0, end=HEADS2_SIZE; i<end; i++) heads2[i]=0;
00062 }
00063 
00064 mp_impl::~mp_impl()
00065 {
00066  for (int i=0, end=chunks.size(); i<end; i++)
00067      operator delete(chunks[i]);
00068 }
00069 
00070 void* mp_impl::new_chunk(size_t size)
00071 {
00072  chunks.reserve(chunks.size()+1);  // the following push_back mustn't throw
00073  chunks.push_back(operator new(size));
00074 
00075  return chunks.back();
00076 }
00077 
00078 void mp_impl::format_new_chunk(void*& head, size_t size, size_t grid)
00079 {
00080  size_t size2=(size+grid-1)/grid*grid;
00081 
00082  size_t n=max_chunk_size/size2;
00083  if (n<min_objs_in_chunk) n=min_objs_in_chunk;
00084 
00085  typedef unsigned char uchar;
00086  uchar *first=static_cast<uchar*>(new_chunk(size2*n)),
00087        *last=first+size2*(n-1);
00088 
00089  for (uchar *ptr=first; ptr!=last; ptr+=size2)
00090      *reinterpret_cast<void**>(ptr)=ptr+size2;
00091 
00092  *reinterpret_cast<void**>(last)=head;
00093  head=first;
00094 }
00095 
00096 }  // unnamed
00097 
00098 #define IMPL static_cast<mp_impl*>(impl)
00099 
00100 namespace ders {  // ::ders
00101 
00102 mem_pool::mem_pool(size_t max_chunk_size, size_t min_objs_in_chunk) :
00103   impl(new mp_impl(max_chunk_size, min_objs_in_chunk))
00104 {
00105 }
00106 
00107 mem_pool::~mem_pool()
00108 {
00109 #ifndef NDEBUG
00110  for (int i=0; i<IMPL->allocated.size(); i++) {
00111      fprintf(stderr, "(%p,%d)", IMPL->allocated.key(i), (int)IMPL->allocated.
00112        val(i));
00113  }
00114 
00115  assert(IMPL->allocated.size()==0);
00116 #endif
00117  delete IMPL;
00118 }
00119 
00120 void* mem_pool::allocate(size_t size)
00121 {
00122  assert(size>0);
00123  void* ret;
00124 
00125  if (size<=mp_impl::MOS1) {
00126     void*& head=IMPL->heads1[(size-1)/mp_impl::SZVP];
00127     if (!head) IMPL->format_new_chunk(head, size, mp_impl::SZVP);
00128 
00129     ret=head;
00130     head=*reinterpret_cast<void**>(head);
00131  }
00132  else if (size<=mp_impl::MOS2) {
00133     void*& head=IMPL->heads2[(size-mp_impl::MOS1-1)/mp_impl::SZVP8];
00134     if (!head) IMPL->format_new_chunk(head, size, mp_impl::SZVP8);
00135 
00136     ret=head;
00137     head=*reinterpret_cast<void**>(head);
00138  }
00139  else ret=operator new(size);
00140 
00141 #ifndef NDEBUG
00142  int pos=IMPL->allocated.insert(ret, size);
00143  assert(pos!=-1);
00144 #endif
00145  return ret;
00146 }
00147 
00148 void mem_pool::deallocate(void* ptr, size_t size)
00149 {
00150 #ifndef NDEBUG
00151  int pos=IMPL->allocated.find(ptr);
00152  assert(pos!=-1);
00153  assert(IMPL->allocated.val(pos)==size);
00154  IMPL->allocated.erase(pos);
00155 #endif
00156 
00157  if (size<=mp_impl::MOS1) {
00158     void*& head=IMPL->heads1[(size-1)/mp_impl::SZVP];
00159 
00160     *reinterpret_cast<void**>(ptr)=head;
00161     head=ptr;
00162  }
00163  else if (size<=mp_impl::MOS2) {
00164     void*& head=IMPL->heads2[(size-mp_impl::MOS1-1)/mp_impl::SZVP8];
00165 
00166     *reinterpret_cast<void**>(ptr)=head;
00167     head=ptr;
00168  }
00169  else operator delete(ptr);
00170 }
00171 
00172 }  // namespace ::ders
00173 

Generated on Tue Dec 8 11:35:32 2009 for derslib by  doxygen 1.5.5