]> git.sesse.net Git - casparcg/blob - dependencies64/tbb/include/tbb/memory_pool.h
980a8bfb69497897dbcee34b4f1a8d7daa2b80b3
[casparcg] / dependencies64 / tbb / include / tbb / memory_pool.h
1 /*
2     Copyright 2005-2011 Intel Corporation.  All Rights Reserved.
3
4     This file is part of Threading Building Blocks.
5
6     Threading Building Blocks is free software; you can redistribute it
7     and/or modify it under the terms of the GNU General Public License
8     version 2 as published by the Free Software Foundation.
9
10     Threading Building Blocks is distributed in the hope that it will be
11     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with Threading Building Blocks; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     As a special exception, you may use this file as part of a free software
20     library without restriction.  Specifically, if other files instantiate
21     templates or use macros or inline functions from this file, or you compile
22     this file and link it with other files to produce an executable, this
23     file does not by itself cause the resulting executable to be covered by
24     the GNU General Public License.  This exception does not however
25     invalidate any other reasons why the executable file might be covered by
26     the GNU General Public License.
27 */
28
29 #ifndef __TBB_memory_pool_H
30 #define __TBB_memory_pool_H
31
32 #if !TBB_PREVIEW_MEMORY_POOL
33 #error Set TBB_PREVIEW_MEMORY_POOL to include memory_pool.h
34 #endif
35 /** @file */
36
37 #include "scalable_allocator.h"
38 #include "tbb_stddef.h"
39 #include "tbb_machine.h" // TODO: Itanium requires linkage with TBB library
40 #include <new> // std::bad_alloc
41
42 #if __TBB_EXTRA_DEBUG
43 #define __TBBMALLOC_ASSERT ASSERT
44 #else
45 #define __TBBMALLOC_ASSERT(a,b) ((void)0)
46 #endif
47
48 namespace tbb {
49 namespace interface6 {
50 //! @cond INTERNAL
51 namespace internal {
52
53 //! Base of thread-safe pool allocator for variable-size requests
54 class pool_base : tbb::internal::no_copy {
55     // Pool interface is separate from standard allocator classes because it has
56     // to maintain internal state, no copy or assignment. Move and swap are possible.
57 public:
58     //! Reset pool to reuse its memory (free all objects at once)
59     void recycle() { rml::pool_reset(my_pool); }
60
61     //! The "malloc" analogue to allocate block of memory of size bytes
62     void *malloc(size_t size) { return rml::pool_malloc(my_pool, size); }
63
64     //! The "free" analogue to discard a previously allocated piece of memory.
65     void free(void* ptr) { rml::pool_free(my_pool, ptr); }
66
67     //! The "realloc" analogue complementing pool_malloc.
68     // Enables some low-level optimization possibilities
69     void *realloc(void* ptr, size_t size) {
70         return rml::pool_realloc(my_pool, ptr, size);
71     }
72
73 protected:
74     //! destroy pool - must be called in a child class
75     void destroy() { rml::pool_destroy(my_pool); }
76
77     rml::MemoryPool *my_pool;
78 };
79
80 } // namespace internal
81 //! @endcond
82
83 #if _MSC_VER && !defined(__INTEL_COMPILER)
84     // Workaround for erroneous "unreferenced parameter" warning in method destroy.
85     #pragma warning (push)
86     #pragma warning (disable: 4100)
87 #endif
88
89 //! Meets "allocator" requirements of ISO C++ Standard, Section 20.1.5
90 /** @ingroup memory_allocation */
91 template<typename T, typename P = internal::pool_base>
92 class memory_pool_allocator {
93 protected:
94     typedef P pool_type;
95     pool_type *my_pool;
96     template<typename U, typename R>
97     friend class memory_pool_allocator;
98     template<typename V, typename U, typename R>
99     friend bool operator==( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
100     template<typename V, typename U, typename R>
101     friend bool operator!=( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
102 public:
103     typedef typename tbb::internal::allocator_type<T>::value_type value_type;
104     typedef value_type* pointer;
105     typedef const value_type* const_pointer;
106     typedef value_type& reference;
107     typedef const value_type& const_reference;
108     typedef size_t size_type;
109     typedef ptrdiff_t difference_type;
110     template<typename U> struct rebind {
111         typedef memory_pool_allocator<U, P> other;
112     };
113
114     memory_pool_allocator(pool_type &pool) throw() : my_pool(&pool) {}
115     memory_pool_allocator(const memory_pool_allocator& src) throw() : my_pool(src.my_pool) {}
116     template<typename U>
117     memory_pool_allocator(const memory_pool_allocator<U,P>& src) throw() : my_pool(src.my_pool) {}
118
119     pointer address(reference x) const { return &x; }
120     const_pointer address(const_reference x) const { return &x; }
121     
122     //! Allocate space for n objects.
123     pointer allocate( size_type n, const void* /*hint*/ = 0) {
124         return static_cast<pointer>( my_pool->malloc( n*sizeof(value_type) ) );
125     }
126     //! Free previously allocated block of memory.
127     void deallocate( pointer p, size_type ) {
128         my_pool->free(p);
129     }
130     //! Largest value for which method allocate might succeed.
131     size_type max_size() const throw() {
132         size_type max = static_cast<size_type>(-1) / sizeof (value_type);
133         return (max > 0 ? max : 1);
134     }
135     //! Copy-construct value at location pointed to by p.
136     void construct( pointer p, const value_type& value ) { ::new((void*)(p)) value_type(value); }
137
138     //! Destroy value at location pointed to by p.
139     void destroy( pointer p ) { p->~value_type(); }
140
141 };
142
143 #if _MSC_VER && !defined(__INTEL_COMPILER)
144     #pragma warning (pop)
145 #endif // warning 4100 is back
146
147 //! Analogous to std::allocator<void>, as defined in ISO C++ Standard, Section 20.4.1
148 /** @ingroup memory_allocation */
149 template<typename P> 
150 class memory_pool_allocator<void, P> {
151 public:
152     typedef P pool_type;
153     typedef void* pointer;
154     typedef const void* const_pointer;
155     typedef void value_type;
156     template<typename U> struct rebind {
157         typedef memory_pool_allocator<U, P> other;
158     };
159
160     memory_pool_allocator( pool_type &pool) throw() : my_pool(&pool) {}
161     memory_pool_allocator( const memory_pool_allocator& src) throw() : my_pool(src.my_pool) {}
162     template<typename U>
163     memory_pool_allocator(const memory_pool_allocator<U,P>& src) throw() : my_pool(src.my_pool) {}
164
165 protected:
166     pool_type *my_pool;
167     template<typename U, typename R>
168     friend class memory_pool_allocator;
169     template<typename V, typename U, typename R>
170     friend bool operator==( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
171     template<typename V, typename U, typename R>
172     friend bool operator!=( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
173 };
174
175 template<typename T, typename U, typename P>
176 inline bool operator==( const memory_pool_allocator<T,P>& a, const memory_pool_allocator<U,P>& b) {return a.my_pool==b.my_pool;}
177
178 template<typename T, typename U, typename P>
179 inline bool operator!=( const memory_pool_allocator<T,P>& a, const memory_pool_allocator<U,P>& b) {return a.my_pool!=b.my_pool;}
180
181
182 //! Thread-safe growable pool allocator for variable-size requests
183 template <typename Alloc>
184 class memory_pool : public internal::pool_base {
185     Alloc my_alloc; // TODO: base-class optimization
186     static void *allocate_request(intptr_t pool_id, size_t & bytes);
187     static int deallocate_request(intptr_t pool_id, void*, size_t raw_bytes);
188
189 public:
190     //! construct pool with underlying allocator
191     memory_pool(const Alloc &src = Alloc());
192
193     //! destroy pool
194     ~memory_pool() { destroy(); } // call the callbacks first and destroy my_alloc latter
195
196 };
197
198 class fixed_pool : public internal::pool_base {
199     void *my_buffer;
200     size_t my_size;
201     inline static void *allocate_request(intptr_t pool_id, size_t & bytes);
202
203 public:
204     //! construct pool with underlying allocator
205     inline fixed_pool(void *buf, size_t size);
206     //! destroy pool
207     ~fixed_pool() { destroy(); }
208 };
209
210 //////////////// Implementation ///////////////
211
212 template <typename Alloc>
213 memory_pool<Alloc>::memory_pool(const Alloc &src) : my_alloc(src) {
214     rml::MemPoolPolicy args = {
215         allocate_request, deallocate_request, sizeof(typename Alloc::value_type)
216     };
217     my_pool = rml::pool_create(intptr_t(this), &args);
218     __TBBMALLOC_ASSERT(my_pool, "Pool is not created");
219     if( !my_pool ) __TBB_THROW(std::bad_alloc());
220 }
221 template <typename Alloc>
222 void *memory_pool<Alloc>::allocate_request(intptr_t pool_id, size_t & bytes) {
223     memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_id);
224     const size_t unit_size = sizeof(typename Alloc::value_type);
225     __TBBMALLOC_ASSERT( 0 == bytes%unit_size, NULL);
226     void *ptr;
227     __TBB_TRY { ptr = self.my_alloc.allocate( bytes/unit_size ); }
228     __TBB_CATCH(...) { return 0; }
229     return ptr;
230 }
231 template <typename Alloc>
232 int memory_pool<Alloc>::deallocate_request(intptr_t pool_id, void* raw_ptr, size_t raw_bytes) {
233     memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_id);
234     const size_t unit_size = sizeof(typename Alloc::value_type);
235     __TBBMALLOC_ASSERT( 0 == raw_bytes%unit_size, NULL);
236     self.my_alloc.deallocate( static_cast<typename Alloc::value_type*>(raw_ptr), raw_bytes/unit_size );
237     return 0;
238 }
239 inline fixed_pool::fixed_pool(void *buf, size_t size) : my_buffer(buf), my_size(size) {
240     rml::MemPoolPolicy args = { allocate_request, 0, size };
241     my_pool = rml::pool_create(intptr_t(this), &args);
242     __TBBMALLOC_ASSERT(my_pool, "Pool is not created");
243     if( !my_pool ) __TBB_THROW(std::bad_alloc());
244 }
245 inline void *fixed_pool::allocate_request(intptr_t pool_id, size_t & bytes) {
246     fixed_pool &self = *reinterpret_cast<fixed_pool*>(pool_id);
247     if( bytes > self.my_size || !__TBB_CompareAndSwapW(&self.my_size, 0, (bytes=self.my_size)) )
248         return 0; // all the memory was given already
249     return self.my_buffer;
250 }
251
252 } //namespace interface6
253 using interface6::memory_pool_allocator;
254 using interface6::memory_pool;
255 using interface6::fixed_pool;
256 } //namespace tbb
257
258 #undef __TBBMALLOC_ASSERT
259 #endif// __TBB_memory_pool_H