type_pool
1.2
|
00001 /* 00002 (C) Copyright Thierry Seegers 2012. Distributed under the following license: 00003 00004 Boost Software License - Version 1.0 - August 17th, 2003 00005 00006 Permission is hereby granted, free of charge, to any person or organization 00007 obtaining a copy of the software and accompanying documentation covered by 00008 this license (the "Software") to use, reproduce, display, distribute, 00009 execute, and transmit the Software, and to prepare derivative works of the 00010 Software, and to permit third-parties to whom the Software is furnished to 00011 do so, all subject to the following: 00012 00013 The copyright notices in the Software and this entire statement, including 00014 the above license grant, this restriction and the following disclaimer, 00015 must be included in all copies of the Software, in whole or in part, and 00016 all derivative works of the Software, unless such copies or derivative 00017 works are solely in the form of machine-executable object code generated by 00018 a source language processor. 00019 00020 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00021 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00022 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 00023 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 00024 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 00025 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00026 DEALINGS IN THE SOFTWARE. 00027 */ 00028 00029 #if !defined(TYPEPOOL_H) 00030 #define TYPEPOOL_H 00031 00032 #include <algorithm> 00033 #include <atomic> 00034 #include <functional> 00035 #include <future> 00036 #include <list> 00037 #include <memory> 00038 #include <mutex> 00039 #include <utility> 00040 00042 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 00043 00044 00052 template<size_t S, class Allocator = std::allocator<unsigned char[S]>> 00053 class chunk_pool 00054 { 00055 Allocator allocator; 00056 size_t cap; 00057 std::atomic<bool> empty; 00058 std::mutex m; 00059 std::future<void> preallocation; 00060 00061 typedef std::list<typename Allocator::pointer> store_t; 00062 store_t store; 00063 00064 // Disabled copy construction. 00065 chunk_pool(const chunk_pool&); 00066 chunk_pool(chunk_pool&&); 00067 00068 // Disabled assignment. 00069 chunk_pool& operator=(const chunk_pool&); 00070 chunk_pool& operator=(chunk_pool&&); 00071 00072 protected: 00074 static size_t max_size() 00075 { 00076 store_t s; 00077 return s.max_size(); 00078 } 00079 00080 public: 00082 typedef Allocator allocator_type; 00083 00085 typedef typename allocator_type::pointer pointer; 00086 00094 chunk_pool(size_t preallocate = 0, size_t cap = max_size()) : cap(std::min(cap, max_size())) 00095 { 00096 preallocate = std::min(preallocate, cap); 00097 00098 empty = (preallocate == 0); 00099 00100 preallocation = std::async([preallocate, this]() mutable -> void 00101 { 00102 try 00103 { 00104 while(preallocate--) 00105 { 00106 store.push_back(this->allocator.allocate(1)); 00107 } 00108 } 00109 catch(...) {} 00110 }); 00111 } 00112 00116 virtual ~chunk_pool() 00117 { 00118 preallocation.wait(); 00119 std::for_each(store.begin(), store.end(), std::bind(&allocator_type::deallocate, allocator, std::placeholders::_1, S)); 00120 } 00121 00126 pointer allocate() 00127 { 00128 if(empty) 00129 { 00130 return allocator.allocate(1); 00131 } 00132 else 00133 { 00134 m.lock(); 00135 00136 preallocation.wait(); 00137 empty = store.empty(); 00138 00139 if(!empty) 00140 { 00141 pointer p = store.back(); 00142 store.pop_back(); 00143 empty = store.empty(); 00144 00145 m.unlock(); 00146 00147 return p; 00148 } 00149 else 00150 { 00151 m.unlock(); 00152 00153 return allocator.allocate(1); 00154 } 00155 } 00156 } 00157 00163 void release(typename Allocator::pointer p) 00164 { 00165 m.lock(); 00166 00167 if(store.size() < cap) 00168 { 00169 store.push_back(p); 00170 empty = false; 00171 } 00172 else 00173 { 00174 allocator.deallocate(p, S); 00175 } 00176 00177 m.unlock(); 00178 } 00179 }; 00180 00200 template<typename T, class Allocator = typename chunk_pool<sizeof(T)>::allocator_type> 00201 class type_pool : public chunk_pool<sizeof(T), Allocator> 00202 { 00203 void release(T* p) 00204 { 00205 p->~T(); 00206 00207 chunk_pool<sizeof(T), Allocator>::release(reinterpret_cast<typename chunk_pool<sizeof(T), Allocator>::pointer>(p)); 00208 } 00209 00210 public: 00212 typedef typename std::unique_ptr<T, std::function<void (T*)>> unique_ptr; 00213 00218 type_pool(size_t preallocate = 0, size_t cap = chunk_pool<sizeof(T), Allocator>::max_size()) : chunk_pool<sizeof(T), Allocator>(preallocate, cap) 00219 {} 00220 00225 template<typename U> 00226 typename std::enable_if<std::is_same<T, U>::value, T*>::type get_ptr(U&& t) 00227 { 00228 return new(chunk_pool<sizeof(T), Allocator>::allocate()) T(std::move(t)); 00229 } 00230 00231 #if (defined(__GNUG__) && (GCC_VERSION >= 40400)) 00232 00233 00234 00235 00236 00237 00238 template<typename U, typename... Args> 00239 typename std::enable_if<std::is_same<T, U>::value, T*>::type get_ptr(Args&&... args) 00240 { 00241 return new(chunk_pool<sizeof(T), Allocator>::allocate()) T(std::forward<Args>(args)...); 00242 } 00243 #endif 00244 00248 template<typename U> 00249 typename std::enable_if<std::is_same<T, U>::value, std::shared_ptr<T>>::type get_shared(U&& t) 00250 { 00251 return std::shared_ptr<T>(get_ptr(std::move(t)), std::bind1st(std::mem_fun(&type_pool<T, Allocator>::release), this)); 00252 } 00253 00254 #if (defined(__GNUG__) && (GCC_VERSION >= 40400)) 00255 00256 00257 00258 00259 00260 template<typename U, typename... Args> 00261 typename std::enable_if<std::is_same<T, U>::value, std::shared_ptr<T>>::type get_shared(Args&&... args) 00262 { 00263 return std::shared_ptr<T>(get_ptr<T>(std::forward<Args>(args)...), std::bind1st(std::mem_fun(&type_pool<T, Allocator>::release), this)); 00264 } 00265 #endif 00266 00271 template<typename U> 00272 typename std::enable_if<std::is_same<T, U>::value, typename type_pool<T, Allocator>::unique_ptr>::type get_unique(U&& t) 00273 { 00274 return typename type_pool<T, Allocator>::unique_ptr(get_ptr(std::move(t)), std::bind1st(std::mem_fun(&type_pool<T, Allocator>::release), this)); 00275 } 00276 00277 #if (defined(__GNUG__) && (GCC_VERSION >= 40400)) 00278 00279 00280 00281 00282 00283 00284 template<typename U, typename... Args> 00285 typename std::enable_if<std::is_same<T, U>::value, typename type_pool<T, Allocator>::unique_ptr>::type get_unique(Args&&... args) 00286 { 00287 return typename type_pool<T, Allocator>::unique_ptr(get_ptr<T>(std::forward<Args>(args)...), std::bind1st(std::mem_fun(&type_pool<T, Allocator>::release), this)); 00288 } 00289 #endif 00290 }; 00291 00292 #endif 00293