| 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__ |
|---|
| 21 | |
|---|
| 22 | #include <stdexcept> |
|---|
| 23 | #include <cstdlib> |
|---|
| 24 | #include <limits> |
|---|
| 25 | #include "mp/utility.h" |
|---|
| 26 | |
|---|
| 27 | #ifndef MP_POOL_DEFAULT_ALLOCATION_SIZE |
|---|
| 28 | #define MP_POOL_DEFAULT_ALLOCATION_SIZE 32*1024 |
|---|
| 29 | #endif |
|---|
| 30 | |
|---|
| 31 | #ifndef MP_POOL_DEFAULT_LOTS_IN_CHUNK |
|---|
| 32 | #define MP_POOL_DEFAULT_LOTS_IN_CHUNK 4 |
|---|
| 33 | #endif |
|---|
| 34 | |
|---|
| 35 | #ifndef MP_POOL_ALLOCATOR_DEFAULT_OBJECTS_IN_CHUNK |
|---|
| 36 | #define MP_POOL_ALLOCATOR_DEFAULT_OBJECTS_IN_CHUNK 1024 |
|---|
| 37 | #endif |
|---|
| 38 | |
|---|
| 39 | namespace mp { |
|---|
| 40 | |
|---|
| 41 | static const size_t POOL_DEFAULT_ALLOCATION_SIZE = MP_POOL_DEFAULT_ALLOCATION_SIZE; |
|---|
| 42 | static const size_t POOL_DEFAULT_LOTS_IN_CHUNK = MP_POOL_DEFAULT_LOTS_IN_CHUNK; |
|---|
| 43 | static const size_t POOL_ALLOCATOR_DEFAULT_OBJECTS_IN_CHUNK = MP_POOL_ALLOCATOR_DEFAULT_OBJECTS_IN_CHUNK; |
|---|
| 44 | |
|---|
| 45 | template < size_t EstimatedAllocationSize = POOL_DEFAULT_ALLOCATION_SIZE, |
|---|
| 46 | size_t OptimalLotsInChunk = POOL_DEFAULT_LOTS_IN_CHUNK > |
|---|
| 47 | class mempool { |
|---|
| 48 | public: |
|---|
| 49 | mempool(); |
|---|
| 50 | ~mempool(); |
|---|
| 51 | |
|---|
| 52 | public: |
|---|
| 53 | //! Allocate memory from the pool. |
|---|
| 54 | /* The allocated memory have to be freed using free() function. */ |
|---|
| 55 | inline void* malloc(size_t size); |
|---|
| 56 | |
|---|
| 57 | //! Free the allocated memory. |
|---|
| 58 | inline void free(void* x); |
|---|
| 59 | |
|---|
| 60 | //! Template version of malloc() |
|---|
| 61 | template <size_t size> |
|---|
| 62 | inline void* malloc(); |
|---|
| 63 | |
|---|
| 64 | public: |
|---|
| 65 | //! Destroy the constructed object. |
|---|
| 66 | template <typename T> |
|---|
| 67 | inline void destroy(T* x); |
|---|
| 68 | |
|---|
| 69 | //! Allocate memory from the pool and construct object. |
|---|
| 70 | template <typename T> |
|---|
| 71 | inline T* construct(); |
|---|
| 72 | MP_ARGS_BEGIN |
|---|
| 73 | template <typename T, MP_ARGS_TEMPLATE> |
|---|
| 74 | inline T* construct(MP_ARGS_PARAMS); |
|---|
| 75 | MP_ARGS_END |
|---|
| 76 | |
|---|
| 77 | private: |
|---|
| 78 | struct chunk_t { |
|---|
| 79 | chunk_t* next; |
|---|
| 80 | chunk_t* prev; |
|---|
| 81 | size_t free; |
|---|
| 82 | size_t lots; |
|---|
| 83 | size_t size; |
|---|
| 84 | }; |
|---|
| 85 | struct data_t { |
|---|
| 86 | chunk_t* chunk; |
|---|
| 87 | }; |
|---|
| 88 | |
|---|
| 89 | private: |
|---|
| 90 | chunk_t* m_free; |
|---|
| 91 | chunk_t* m_used; |
|---|
| 92 | |
|---|
| 93 | private: |
|---|
| 94 | void* expand_free(size_t req); |
|---|
| 95 | void splice_to_used(chunk_t* chunk); |
|---|
| 96 | void splice_to_free(chunk_t* chunk); |
|---|
| 97 | |
|---|
| 98 | private: |
|---|
| 99 | mempool(const mempool&); |
|---|
| 100 | }; |
|---|
| 101 | |
|---|
| 102 | |
|---|
| 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; |
|---|
| 139 | } |
|---|
| 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; |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | void deallocate(pointer p, size_type num) |
|---|
| 185 | { |
|---|
| 186 | if(p == 0) { return; } |
|---|
| 187 | pool::free(p); |
|---|
| 188 | } |
|---|
| 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 | }; |
|---|
| 196 | |
|---|
| 197 | |
|---|
| 198 | } // namespace mp |
|---|
| 199 | |
|---|
| 200 | template <class T1, class T2> |
|---|
| 201 | bool operator==(const mp::mempool_allocator<T1>&, const mp::mempool_allocator<T2>&) throw() { return true; } |
|---|
| 202 | |
|---|
| 203 | template <class T1, class T2> |
|---|
| 204 | bool operator!=(const mp::mempool_allocator<T1>&, const mp::mempool_allocator<T2>&) throw() { return false; } |
|---|
| 205 | |
|---|
| 206 | #include "mp/mempool_impl.h" |
|---|
| 207 | |
|---|
| 208 | #endif /* mp/mempool.h */ |
|---|
| 209 | |
|---|