| 1 | | #ifndef MP_POOL_H__ |
| 2 | | #define MP_POOL_H__ |
| | 1 | // |
| | 2 | // mp::mempool |
| | 3 | // |
| | 4 | // Copyright (C) 2008 FURUHASHI Sadayuki |
| | 5 | // |
| | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| | 7 | // you may not use this file except in compliance with the License. |
| | 8 | // You may obtain a copy of the License at |
| | 9 | // |
| | 10 | // http://www.apache.org/licenses/LICENSE-2.0 |
| | 11 | // |
| | 12 | // Unless required by applicable law or agreed to in writing, software |
| | 13 | // distributed under the License is distributed on an "AS IS" BASIS, |
| | 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | 15 | // See the License for the specific language governing permissions and |
| | 16 | // limitations under the License. |
| | 17 | // |
| | 18 | |
| | 19 | #ifndef MP_MEMPOOL_H__ |
| | 20 | #define MP_MEMPOOL_H__ |
| 70 | | template <size_t EstimatedAllocationSize, size_t OptimalLotsInChunk> |
| 71 | | mempool<EstimatedAllocationSize, OptimalLotsInChunk>::mempool() |
| 72 | | { |
| 73 | | m_free = (chunk_t*)std::malloc(sizeof(chunk_t)); |
| 74 | | if( m_free == NULL ) { throw std::bad_alloc(); } |
| 75 | | m_used = (chunk_t*)std::malloc(sizeof(chunk_t)); |
| 76 | | if( m_used == NULL ) { std::free(m_free); throw std::bad_alloc(); } |
| 77 | | m_free->next = m_free; |
| 78 | | m_free->prev = m_free; |
| 79 | | m_used->next = m_used; |
| 80 | | m_used->prev = m_used; |
| 81 | | } |
| 82 | | |
| 83 | | template <size_t EstimatedAllocationSize, size_t OptimalLotsInChunk> |
| 84 | | mempool<EstimatedAllocationSize, OptimalLotsInChunk>::~mempool() |
| 85 | | { |
| 86 | | chunk_t* f = m_free->next; |
| 87 | | while(f != m_free) { |
| 88 | | f = f->next; |
| 89 | | std::free(f->prev); |
| | 103 | template < typename ThreadTag = main_thread_tag, |
| | 104 | size_t EstimatedAllocationSize = POOL_DEFAULT_ALLOCATION_SIZE, |
| | 105 | size_t OptimalLotsInChunk = POOL_DEFAULT_LOTS_IN_CHUNK > |
| | 106 | class singleton_mempool { |
| | 107 | public: |
| | 108 | typedef mempool<EstimatedAllocationSize, OptimalLotsInChunk> pool_type; |
| | 109 | |
| | 110 | static void* malloc(size_t size) |
| | 111 | { return pool().malloc(size); } |
| | 112 | |
| | 113 | static void free(void* x) |
| | 114 | { pool().free(x); } |
| | 115 | |
| | 116 | template <size_t size> |
| | 117 | static void* malloc() |
| | 118 | { return pool().malloc<size>(); } |
| | 119 | |
| | 120 | public: |
| | 121 | template <typename T> |
| | 122 | static void destroy(T* x) |
| | 123 | { return pool().destroy<T>(x); } |
| | 124 | |
| | 125 | template <typename T> |
| | 126 | static T* construct() |
| | 127 | { return pool().construct<T>(); } |
| | 128 | MP_ARGS_BEGIN |
| | 129 | template <typename T, MP_ARGS_TEMPLATE> |
| | 130 | static T* construct(MP_ARGS_PARAMS) |
| | 131 | { return pool().construct<T, MP_ARGS_TYPES>(MP_ARGS_FUNC); } |
| | 132 | MP_ARGS_END |
| | 133 | |
| | 134 | private: |
| | 135 | static pool_type& pool() |
| | 136 | { |
| | 137 | static pool_type object; |
| | 138 | return object; |
| 91 | | std::free(f); |
| 92 | | |
| 93 | | f = m_used; |
| 94 | | while(f->next != m_used) { |
| 95 | | f = f->next; |
| 96 | | std::free(f->prev); |
| | 140 | }; |
| | 141 | |
| | 142 | |
| | 143 | template < typename T, |
| | 144 | typename ThreadTag = main_thread_tag, |
| | 145 | size_t OptimalObjectsInChunk = POOL_ALLOCATOR_DEFAULT_OBJECTS_IN_CHUNK > |
| | 146 | class mempool_allocator { |
| | 147 | private: |
| | 148 | typedef singleton_mempool<ThreadTag, sizeof(T), OptimalObjectsInChunk> pool; |
| | 149 | |
| | 150 | public: |
| | 151 | typedef size_t size_type; |
| | 152 | typedef ptrdiff_t difference_type; |
| | 153 | typedef T* pointer; |
| | 154 | typedef const T* const_pointer; |
| | 155 | typedef T& reference; |
| | 156 | typedef const T& const_reference; |
| | 157 | typedef T value_type; |
| | 158 | |
| | 159 | template <class U> |
| | 160 | struct rebind { typedef mempool_allocator<U> other; }; |
| | 161 | |
| | 162 | mempool_allocator() throw() {} |
| | 163 | mempool_allocator(const mempool_allocator&) throw() {} |
| | 164 | template <class U> mempool_allocator(const mempool_allocator<U>&) throw() {} |
| | 165 | |
| | 166 | ~mempool_allocator() throw() {} |
| | 167 | |
| | 168 | pointer address(reference r) |
| | 169 | { return &r; } |
| | 170 | |
| | 171 | const_pointer address(const_reference s) |
| | 172 | { return &s; } |
| | 173 | |
| | 174 | size_type max_size() throw() |
| | 175 | { return std::numeric_limits<size_t>::max() / sizeof(T); } |
| | 176 | |
| | 177 | pointer allocate(size_type num, const_pointer hint = 0) |
| | 178 | { |
| | 179 | const pointer p = static_cast<pointer>( pool::malloc(sizeof(T) * num) ); |
| | 180 | if (p == 0) { throw std::bad_alloc(); } |
| | 181 | return p; |
| 98 | | std::free(f); |
| 99 | | } |
| 100 | | |
| 101 | | template <size_t EstimatedAllocationSize, size_t OptimalLotsInChunk> |
| 102 | | template <size_t size> |
| 103 | | void* mempool<EstimatedAllocationSize, OptimalLotsInChunk>::malloc() |
| 104 | | { |
| 105 | | return this->malloc(size); |
| 106 | | } |
| 107 | | |
| 108 | | template <size_t EstimatedAllocationSize, size_t OptimalLotsInChunk> |
| 109 | | void* mempool<EstimatedAllocationSize, OptimalLotsInChunk>::malloc(size_t size) |
| 110 | | { |
| 111 | | size_t req = size + sizeof(data_t); |
| 112 | | for( chunk_t* f = m_free->next; f != m_free; f = f->next ) { |
| 113 | | if( f->free < req ) { continue; } |
| 114 | | data_t* data = reinterpret_cast<data_t*>( |
| 115 | | ((char*)f) + sizeof(chunk_t) + f->size - f->free |
| 116 | | ); |
| 117 | | f->lots++; |
| 118 | | f->free -= req; |
| 119 | | data->chunk = f; |
| 120 | | if( f->free < EstimatedAllocationSize + sizeof(chunk_t) ) { |
| 121 | | splice_to_used(f); |
| 122 | | } |
| 123 | | return ((char*)data) + sizeof(data_t); |
| | 183 | |
| | 184 | void deallocate(pointer p, size_type num) |
| | 185 | { |
| | 186 | if(p == 0) { return; } |
| | 187 | pool::free(p); |
| 125 | | return expand_free(req); |
| 126 | | } |
| 127 | | |
| 128 | | template <size_t EstimatedAllocationSize, size_t OptimalLotsInChunk> |
| 129 | | void mempool<EstimatedAllocationSize, OptimalLotsInChunk>::free(void* x) |
| 130 | | { |
| 131 | | data_t* data = reinterpret_cast<data_t*>( ((char*)x) - sizeof(data_t) ); |
| 132 | | chunk_t* chunk = data->chunk; |
| 133 | | chunk->lots--; |
| 134 | | if( chunk->lots == 0 ) { |
| 135 | | splice_to_free(chunk); |
| 136 | | } |
| 137 | | } |
| 138 | | |
| 139 | | template <size_t EstimatedAllocationSize, size_t OptimalLotsInChunk> |
| 140 | | void* mempool<EstimatedAllocationSize, OptimalLotsInChunk>::expand_free(size_t req) |
| 141 | | { |
| 142 | | const size_t default_chunk_size = (EstimatedAllocationSize + sizeof(chunk_t)) * OptimalLotsInChunk; |
| 143 | | size_t chunk_size = req > default_chunk_size ? req : default_chunk_size; |
| 144 | | chunk_t* n = (chunk_t*)std::malloc(sizeof(chunk_t) + chunk_size); |
| 145 | | if( n == NULL ) { throw std::bad_alloc(); } |
| 146 | | data_t* data = reinterpret_cast<data_t*>( ((char*)n) + sizeof(chunk_t) ); |
| 147 | | n->lots = 1; |
| 148 | | n->size = chunk_size; |
| 149 | | n->free = chunk_size - req; |
| 150 | | data->chunk = n; |
| 151 | | if( n->free < EstimatedAllocationSize + sizeof(chunk_t) ) { |
| 152 | | n->prev = m_used; |
| 153 | | n->next = m_used->next; |
| 154 | | m_used->next->prev = n; |
| 155 | | m_used->next = n; |
| 156 | | } else { |
| 157 | | n->prev = m_free; |
| 158 | | n->next = m_free->next; |
| 159 | | m_free->next->prev = n; |
| 160 | | m_free->next = n; |
| 161 | | } |
| 162 | | return ((char*)data) + sizeof(data_t); |
| 163 | | } |
| 164 | | |
| 165 | | template <size_t EstimatedAllocationSize, size_t OptimalLotsInChunk> |
| 166 | | void mempool<EstimatedAllocationSize, OptimalLotsInChunk>::splice_to_used(chunk_t* chunk) |
| 167 | | { |
| 168 | | chunk->prev->next = chunk->next; |
| 169 | | chunk->next->prev = chunk->prev; |
| 170 | | chunk->prev = m_used; |
| 171 | | chunk->next = m_used->next; |
| 172 | | m_used->next->prev = chunk; |
| 173 | | m_used->next = chunk; |
| 174 | | } |
| 175 | | |
| 176 | | template <size_t EstimatedAllocationSize, size_t OptimalLotsInChunk> |
| 177 | | void mempool<EstimatedAllocationSize, OptimalLotsInChunk>::splice_to_free(chunk_t* chunk) |
| 178 | | { |
| 179 | | chunk->prev->next = chunk->next; |
| 180 | | chunk->next->prev = chunk->prev; |
| 181 | | chunk->next = m_free->next; |
| 182 | | chunk->prev = m_free; |
| 183 | | m_free->next->prev = chunk; |
| 184 | | m_free->next = chunk; |
| 185 | | chunk->free = chunk->size; |
| 186 | | } |
| | 189 | |
| | 190 | void construct(pointer p, const T& r) |
| | 191 | { new ( reinterpret_cast<void*>(p) ) T(r); } |
| | 192 | |
| | 193 | void destroy(pointer p) |
| | 194 | { p->~T(); } |
| | 195 | }; |