00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #ifndef __ONIKIRI_POOL_H
00038 #define __ONIKIRI_POOL_H
00039
00040 #include <stack>
00041 #include <vector>
00042
00043
00044
00045 namespace Onikiri
00046 {
00047 static const int POOL_ALLOCATOR_CHUNK_SIZE_BASE = 64;
00048
00049 template <typename T>
00050 class pool_body
00051 {
00052 public:
00053 typedef T value_type;
00054 typedef value_type* pointer;
00055 typedef value_type& reference;
00056 typedef const value_type* const_pointer;
00057 typedef const value_type& const_reference;
00058 typedef size_t size_type;
00059 typedef ptrdiff_t difference_type;
00060
00061 protected:
00062
00063 template <typename U>
00064 class pool_stack
00065 {
00066 std::vector<U> stack_body;
00067 size_t stack_top;
00068 public:
00069
00070 pool_stack() :
00071 stack_body(POOL_ALLOCATOR_CHUNK_SIZE_BASE),
00072 stack_top(0)
00073 {
00074 };
00075
00076 void push(const U& v)
00077 {
00078 if(stack_body.size() <= stack_top){
00079 stack_body.resize(stack_body.size()*2);
00080 }
00081 stack_body[stack_top] = v;
00082 stack_top++;
00083 }
00084
00085 void pop()
00086 {
00087 stack_top--;
00088 }
00089
00090 U& top()
00091 {
00092 assert(stack_top != 0);
00093 return stack_body[stack_top - 1];
00094 }
00095
00096 size_t size()
00097 {
00098 return stack_top;
00099 }
00100 };
00101
00102
00103 typedef pool_stack<T*> stack_type;
00104 std::vector< stack_type* > ptr_stack_array;
00105 std::vector<T*> ptr_list;
00106
00107 #ifdef ONIKIRI_POOL_ALLOCATOR_INVESTIGATE
00108 size_t total_memory;
00109 size_t total_count;
00110 std::vector<size_t> total_memory_array;
00111 std::vector<size_t> total_count_array;
00112 #endif
00113 void allocate_chank( size_type count, stack_type* stack )
00114 {
00115 size_t chunk_size = POOL_ALLOCATOR_CHUNK_SIZE_BASE / count;
00116 if(chunk_size < 4)
00117 chunk_size = 4;
00118
00119
00120 pointer chunk = (pointer)( ::operator new(chunk_size * count * sizeof(T)) );
00121 ptr_list.push_back(chunk);
00122
00123 for( size_t i = 0; i < chunk_size; i++){
00124 stack->push( chunk );
00125 chunk += count;
00126 }
00127
00128 #ifdef ONIKIRI_POOL_ALLOCATOR_INVESTIGATE
00129 total_memory += chunk_size * count * sizeof(T);
00130 total_count += chunk_size * count;
00131 if( total_memory_array.size() <= count ){
00132 total_memory_array.resize( count + 1 );
00133 total_count_array.resize( count + 1 );
00134 }
00135 total_memory_array[count] += chunk_size * count * sizeof(T);
00136 total_count_array[count] += chunk_size * count;
00137 #endif
00138 }
00139
00140 public:
00141
00142 pool_body()
00143 {
00144 };
00145
00146 ~pool_body()
00147 {
00148 for(size_t i = 0; i < ptr_list.size(); i++){
00149 ::operator delete( (void*)ptr_list[i] );
00150 }
00151 for(size_t i = 0; i < ptr_stack_array.size(); i++){
00152 if(ptr_stack_array[i]){
00153 delete ptr_stack_array[i];
00154 }
00155 }
00156 #ifdef ONIKIRI_POOL_ALLOCATOR_INVESTIGATE
00157 printf( "pool_allocator< %s > : \n\ttype size : %d bytes\n\ttotal : %d bytes, %d elements\n", typeid(T).name(), (int)sizeof(T), (int)total_memory, (int)total_count );
00158 for( size_t i = 0; i < total_memory_array.size(); i++ ){
00159 if( total_memory_array[i] > 0)
00160 printf("\t%d : %d bytes, %d elements\n", (int)i, (int)total_memory_array[i], (int)total_count_array[i] );
00161 }
00162 #endif
00163 };
00164
00165 INLINE pointer allocate(
00166 size_type count,
00167 const void* hint = 0)
00168 {
00169 if(count == 0)
00170 return 0;
00171
00172 if(ptr_stack_array.size() <= count){
00173 ptr_stack_array.resize(count+1, 0);
00174 }
00175
00176 stack_type* stack = ptr_stack_array[count];
00177 if(stack == 0){
00178
00179 stack = new stack_type();
00180 ptr_stack_array[count] = stack;
00181 }
00182
00183
00184 if(stack->size() == 0){
00185 allocate_chank( count, stack );
00186 }
00187
00188 pointer ptr = stack->top();
00189 stack->pop();
00190 return ptr;
00191 }
00192
00193 INLINE void deallocate(pointer ptr, size_type count)
00194 {
00195 stack_type* stack = ptr_stack_array[count];
00196 stack->push(ptr);
00197 }
00198 };
00199
00200 template <typename T>
00201 class pool_allocator
00202 {
00203 typedef pool_body<T> pool_type;
00204 INLINE pool_type& pool()
00205 {
00206 static pool_type p;
00207 return p;
00208 }
00209
00210 public:
00211
00212 typedef T value_type;
00213 typedef value_type* pointer;
00214 typedef value_type& reference;
00215 typedef const value_type* const_pointer;
00216 typedef const value_type& const_reference;
00217 typedef size_t size_type;
00218 typedef ptrdiff_t difference_type;
00219
00220 template <class U>
00221 struct rebind
00222 {
00223 typedef pool_allocator<U> other;
00224 };
00225
00226 pool_allocator()
00227 {
00228 }
00229
00230 pool_allocator(const pool_allocator&)
00231 {
00232 }
00233
00234 template <class U>
00235 pool_allocator(const pool_allocator<U>&)
00236 {
00237 }
00238
00239 ~pool_allocator()
00240 {
00241 }
00242
00243 INLINE pointer allocate(
00244 size_type count,
00245 const void* hint = 0)
00246 {
00247 return pool().allocate(count);
00248
00249 }
00250
00251 INLINE void construct(pointer ptr, const T& value)
00252 {
00253 new (ptr) T(value);
00254 }
00255
00256 INLINE void deallocate(pointer ptr, size_type count)
00257 {
00258 return pool().deallocate(ptr, count);
00259 }
00260
00261 INLINE void destroy(pointer ptr)
00262 {
00263 ptr->~T();
00264 }
00265
00266 pointer address(reference value) const
00267 {
00268 return &value;
00269 }
00270
00271 const_pointer address(const_reference value) const
00272 {
00273 return &value;
00274 }
00275
00276 size_type max_size() const
00277 {
00278 return std::numeric_limits<size_t>::max() / sizeof(T);
00279 }
00280 };
00281
00282
00283 template <class T1, class T2>
00284 bool operator==(const pool_allocator<T1>&, const pool_allocator<T2>&)
00285 {
00286 return true;
00287 }
00288
00289 template <class T1, class T2>
00290 bool operator!=(const pool_allocator<T1>&, const pool_allocator<T2>&)
00291 {
00292 return false;
00293 }
00294
00295 };
00296
00297 #endif
00298