]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // | |
3 | // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost | |
4 | // Software License, Version 1.0. (See accompanying file | |
5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // See http://www.boost.org/libs/interprocess for documentation. | |
8 | // | |
9 | ////////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP | |
12 | #define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP | |
13 | ||
14 | #ifndef BOOST_CONFIG_HPP | |
15 | # include <boost/config.hpp> | |
16 | #endif | |
17 | # | |
18 | #if defined(BOOST_HAS_PRAGMA_ONCE) | |
19 | # pragma once | |
20 | #endif | |
21 | ||
22 | #include <boost/interprocess/detail/config_begin.hpp> | |
23 | #include <boost/interprocess/detail/workaround.hpp> | |
24 | ||
25 | #include <boost/intrusive/pointer_traits.hpp> | |
26 | ||
27 | #include <boost/interprocess/interprocess_fwd.hpp> | |
28 | #include <boost/assert.hpp> | |
29 | #include <boost/utility/addressof.hpp> | |
30 | #include <boost/interprocess/allocators/detail/node_pool.hpp> | |
31 | #include <boost/interprocess/containers/version_type.hpp> | |
32 | #include <boost/container/detail/multiallocation_chain.hpp> | |
33 | #include <boost/interprocess/exceptions.hpp> | |
34 | #include <boost/interprocess/detail/utilities.hpp> | |
35 | #include <boost/interprocess/detail/workaround.hpp> | |
36 | #include <boost/move/adl_move_swap.hpp> | |
37 | #include <cstddef> | |
38 | ||
39 | //!\file | |
40 | //!Describes private_node_allocator_base pooled shared memory STL compatible allocator | |
41 | ||
42 | namespace boost { | |
43 | namespace interprocess { | |
44 | ||
45 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
46 | ||
47 | namespace ipcdetail { | |
48 | ||
49 | template < unsigned int Version | |
50 | , class T | |
51 | , class SegmentManager | |
52 | , std::size_t NodesPerBlock | |
53 | > | |
54 | class private_node_allocator_base | |
55 | : public node_pool_allocation_impl | |
56 | < private_node_allocator_base < Version, T, SegmentManager, NodesPerBlock> | |
57 | , Version | |
58 | , T | |
59 | , SegmentManager | |
60 | > | |
61 | { | |
62 | public: | |
63 | //Segment manager | |
64 | typedef SegmentManager segment_manager; | |
65 | typedef typename SegmentManager::void_pointer void_pointer; | |
66 | ||
67 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
68 | private: | |
69 | typedef private_node_allocator_base | |
70 | < Version, T, SegmentManager, NodesPerBlock> self_t; | |
71 | typedef ipcdetail::private_node_pool | |
72 | <SegmentManager | |
73 | , sizeof_value<T>::value | |
74 | , NodesPerBlock | |
75 | > node_pool_t; | |
76 | ||
77 | BOOST_STATIC_ASSERT((Version <=2)); | |
78 | ||
79 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
80 | ||
81 | public: | |
82 | ||
83 | typedef typename boost::intrusive:: | |
84 | pointer_traits<void_pointer>::template | |
85 | rebind_pointer<T>::type pointer; | |
86 | typedef typename boost::intrusive:: | |
87 | pointer_traits<void_pointer>::template | |
88 | rebind_pointer<const T>::type const_pointer; | |
89 | typedef T value_type; | |
90 | typedef typename ipcdetail::add_reference | |
91 | <value_type>::type reference; | |
92 | typedef typename ipcdetail::add_reference | |
93 | <const value_type>::type const_reference; | |
94 | typedef typename segment_manager::size_type size_type; | |
95 | typedef typename segment_manager::difference_type difference_type; | |
96 | typedef boost::interprocess::version_type | |
97 | <private_node_allocator_base, Version> version; | |
98 | typedef boost::container::container_detail::transform_multiallocation_chain | |
99 | <typename SegmentManager::multiallocation_chain, T>multiallocation_chain; | |
100 | ||
101 | //!Obtains node_allocator from other node_allocator | |
102 | template<class T2> | |
103 | struct rebind | |
104 | { | |
105 | typedef private_node_allocator_base | |
106 | <Version, T2, SegmentManager, NodesPerBlock> other; | |
107 | }; | |
108 | ||
109 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
110 | template <int dummy> | |
111 | struct node_pool | |
112 | { | |
113 | typedef ipcdetail::private_node_pool | |
114 | <SegmentManager | |
115 | , sizeof_value<T>::value | |
116 | , NodesPerBlock | |
117 | > type; | |
118 | ||
119 | static type *get(void *p) | |
120 | { return static_cast<type*>(p); } | |
121 | }; | |
122 | ||
123 | private: | |
124 | //!Not assignable from related private_node_allocator_base | |
125 | template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2> | |
126 | private_node_allocator_base& operator= | |
127 | (const private_node_allocator_base<Version2, T2, MemoryAlgorithm2, N2>&); | |
128 | ||
129 | //!Not assignable from other private_node_allocator_base | |
130 | private_node_allocator_base& operator=(const private_node_allocator_base&); | |
131 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
132 | ||
133 | public: | |
134 | //!Constructor from a segment manager | |
135 | private_node_allocator_base(segment_manager *segment_mngr) | |
136 | : m_node_pool(segment_mngr) | |
137 | {} | |
138 | ||
139 | //!Copy constructor from other private_node_allocator_base. Never throws | |
140 | private_node_allocator_base(const private_node_allocator_base &other) | |
141 | : m_node_pool(other.get_segment_manager()) | |
142 | {} | |
143 | ||
144 | //!Copy constructor from related private_node_allocator_base. Never throws. | |
145 | template<class T2> | |
146 | private_node_allocator_base | |
147 | (const private_node_allocator_base | |
148 | <Version, T2, SegmentManager, NodesPerBlock> &other) | |
149 | : m_node_pool(other.get_segment_manager()) | |
150 | {} | |
151 | ||
152 | //!Destructor, frees all used memory. Never throws | |
153 | ~private_node_allocator_base() | |
154 | {} | |
155 | ||
156 | //!Returns the segment manager. Never throws | |
157 | segment_manager* get_segment_manager()const | |
158 | { return m_node_pool.get_segment_manager(); } | |
159 | ||
160 | //!Returns the internal node pool. Never throws | |
161 | node_pool_t* get_node_pool() const | |
162 | { return const_cast<node_pool_t*>(&m_node_pool); } | |
163 | ||
164 | //!Swaps allocators. Does not throw. If each allocator is placed in a | |
165 | //!different shared memory segments, the result is undefined. | |
166 | friend void swap(self_t &alloc1,self_t &alloc2) | |
167 | { boost::adl_move_swap(alloc1.m_node_pool, alloc2.m_node_pool); } | |
168 | ||
169 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
170 | private: | |
171 | node_pool_t m_node_pool; | |
172 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
173 | }; | |
174 | ||
175 | //!Equality test for same type of private_node_allocator_base | |
176 | template<unsigned int V, class T, class S, std::size_t NPC> inline | |
177 | bool operator==(const private_node_allocator_base<V, T, S, NPC> &alloc1, | |
178 | const private_node_allocator_base<V, T, S, NPC> &alloc2) | |
179 | { return &alloc1 == &alloc2; } | |
180 | ||
181 | //!Inequality test for same type of private_node_allocator_base | |
182 | template<unsigned int V, class T, class S, std::size_t NPC> inline | |
183 | bool operator!=(const private_node_allocator_base<V, T, S, NPC> &alloc1, | |
184 | const private_node_allocator_base<V, T, S, NPC> &alloc2) | |
185 | { return &alloc1 != &alloc2; } | |
186 | ||
187 | template < class T | |
188 | , class SegmentManager | |
189 | , std::size_t NodesPerBlock = 64 | |
190 | > | |
191 | class private_node_allocator_v1 | |
192 | : public private_node_allocator_base | |
193 | < 1 | |
194 | , T | |
195 | , SegmentManager | |
196 | , NodesPerBlock | |
197 | > | |
198 | { | |
199 | public: | |
200 | typedef ipcdetail::private_node_allocator_base | |
201 | < 1, T, SegmentManager, NodesPerBlock> base_t; | |
202 | ||
203 | template<class T2> | |
204 | struct rebind | |
205 | { | |
206 | typedef private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> other; | |
207 | }; | |
208 | ||
209 | private_node_allocator_v1(SegmentManager *segment_mngr) | |
210 | : base_t(segment_mngr) | |
211 | {} | |
212 | ||
213 | template<class T2> | |
214 | private_node_allocator_v1 | |
215 | (const private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other) | |
216 | : base_t(other) | |
217 | {} | |
218 | }; | |
219 | ||
220 | } //namespace ipcdetail { | |
221 | ||
222 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
223 | ||
224 | //!An STL node allocator that uses a segment manager as memory | |
225 | //!source. The internal pointer type will of the same type (raw, smart) as | |
226 | //!"typename SegmentManager::void_pointer" type. This allows | |
227 | //!placing the allocator in shared memory, memory mapped-files, etc... | |
228 | //!This allocator has its own node pool. NodesPerBlock is the number of nodes allocated | |
229 | //!at once when the allocator needs runs out of nodes | |
230 | template < class T | |
231 | , class SegmentManager | |
232 | , std::size_t NodesPerBlock | |
233 | > | |
234 | class private_node_allocator | |
235 | #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) | |
236 | : public ipcdetail::private_node_allocator_base | |
237 | < 2 | |
238 | , T | |
239 | , SegmentManager | |
240 | , NodesPerBlock | |
241 | > | |
242 | #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
243 | { | |
244 | ||
245 | #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
246 | typedef ipcdetail::private_node_allocator_base | |
247 | < 2, T, SegmentManager, NodesPerBlock> base_t; | |
248 | public: | |
249 | typedef boost::interprocess::version_type<private_node_allocator, 2> version; | |
250 | ||
251 | template<class T2> | |
252 | struct rebind | |
253 | { | |
254 | typedef private_node_allocator | |
255 | <T2, SegmentManager, NodesPerBlock> other; | |
256 | }; | |
257 | ||
258 | private_node_allocator(SegmentManager *segment_mngr) | |
259 | : base_t(segment_mngr) | |
260 | {} | |
261 | ||
262 | template<class T2> | |
263 | private_node_allocator | |
264 | (const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other) | |
265 | : base_t(other) | |
266 | {} | |
267 | ||
268 | #else | |
269 | public: | |
270 | typedef implementation_defined::segment_manager segment_manager; | |
271 | typedef segment_manager::void_pointer void_pointer; | |
272 | typedef implementation_defined::pointer pointer; | |
273 | typedef implementation_defined::const_pointer const_pointer; | |
274 | typedef T value_type; | |
275 | typedef typename ipcdetail::add_reference | |
276 | <value_type>::type reference; | |
277 | typedef typename ipcdetail::add_reference | |
278 | <const value_type>::type const_reference; | |
279 | typedef typename segment_manager::size_type size_type; | |
280 | typedef typename segment_manage::difference_type difference_type; | |
281 | ||
282 | //!Obtains private_node_allocator from | |
283 | //!private_node_allocator | |
284 | template<class T2> | |
285 | struct rebind | |
286 | { | |
287 | typedef private_node_allocator | |
288 | <T2, SegmentManager, NodesPerBlock> other; | |
289 | }; | |
290 | ||
291 | private: | |
292 | //!Not assignable from | |
293 | //!related private_node_allocator | |
294 | template<class T2, class SegmentManager2, std::size_t N2> | |
295 | private_node_allocator& operator= | |
296 | (const private_node_allocator<T2, SegmentManager2, N2>&); | |
297 | ||
298 | //!Not assignable from | |
299 | //!other private_node_allocator | |
300 | private_node_allocator& operator=(const private_node_allocator&); | |
301 | ||
302 | public: | |
303 | //!Constructor from a segment manager. If not present, constructs a node | |
304 | //!pool. Increments the reference count of the associated node pool. | |
305 | //!Can throw boost::interprocess::bad_alloc | |
306 | private_node_allocator(segment_manager *segment_mngr); | |
307 | ||
308 | //!Copy constructor from other private_node_allocator. Increments the reference | |
309 | //!count of the associated node pool. Never throws | |
310 | private_node_allocator(const private_node_allocator &other); | |
311 | ||
312 | //!Copy constructor from related private_node_allocator. If not present, constructs | |
313 | //!a node pool. Increments the reference count of the associated node pool. | |
314 | //!Can throw boost::interprocess::bad_alloc | |
315 | template<class T2> | |
316 | private_node_allocator | |
317 | (const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other); | |
318 | ||
319 | //!Destructor, removes node_pool_t from memory | |
320 | //!if its reference count reaches to zero. Never throws | |
321 | ~private_node_allocator(); | |
322 | ||
323 | //!Returns a pointer to the node pool. | |
324 | //!Never throws | |
325 | node_pool_t* get_node_pool() const; | |
326 | ||
327 | //!Returns the segment manager. | |
328 | //!Never throws | |
329 | segment_manager* get_segment_manager()const; | |
330 | ||
331 | //!Returns the number of elements that could be allocated. | |
332 | //!Never throws | |
333 | size_type max_size() const; | |
334 | ||
335 | //!Allocate memory for an array of count elements. | |
336 | //!Throws boost::interprocess::bad_alloc if there is no enough memory | |
337 | pointer allocate(size_type count, cvoid_pointer hint = 0); | |
338 | ||
339 | //!Deallocate allocated memory. | |
340 | //!Never throws | |
341 | void deallocate(const pointer &ptr, size_type count); | |
342 | ||
343 | //!Deallocates all free blocks | |
344 | //!of the pool | |
345 | void deallocate_free_blocks(); | |
346 | ||
347 | //!Swaps allocators. Does not throw. If each allocator is placed in a | |
348 | //!different memory segment, the result is undefined. | |
349 | friend void swap(self_t &alloc1, self_t &alloc2); | |
350 | ||
351 | //!Returns address of mutable object. | |
352 | //!Never throws | |
353 | pointer address(reference value) const; | |
354 | ||
355 | //!Returns address of non mutable object. | |
356 | //!Never throws | |
357 | const_pointer address(const_reference value) const; | |
358 | ||
359 | //!Copy construct an object. | |
360 | //!Throws if T's copy constructor throws | |
361 | void construct(const pointer &ptr, const_reference v); | |
362 | ||
363 | //!Destroys object. Throws if object's | |
364 | //!destructor throws | |
365 | void destroy(const pointer &ptr); | |
366 | ||
367 | //!Returns maximum the number of objects the previously allocated memory | |
368 | //!pointed by p can hold. This size only works for memory allocated with | |
369 | //!allocate, allocation_command and allocate_many. | |
370 | size_type size(const pointer &p) const; | |
371 | ||
372 | pointer allocation_command(boost::interprocess::allocation_type command, | |
373 | size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse); | |
374 | ||
375 | //!Allocates many elements of size elem_size in a contiguous block | |
376 | //!of memory. The minimum number to be allocated is min_elements, | |
377 | //!the preferred and maximum number is | |
378 | //!preferred_elements. The number of actually allocated elements is | |
379 | //!will be assigned to received_size. The elements must be deallocated | |
380 | //!with deallocate(...) | |
381 | void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain); | |
382 | ||
383 | //!Allocates n_elements elements, each one of size elem_sizes[i]in a | |
384 | //!contiguous block | |
385 | //!of memory. The elements must be deallocated | |
386 | void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain); | |
387 | ||
388 | //!Allocates many elements of size elem_size in a contiguous block | |
389 | //!of memory. The minimum number to be allocated is min_elements, | |
390 | //!the preferred and maximum number is | |
391 | //!preferred_elements. The number of actually allocated elements is | |
392 | //!will be assigned to received_size. The elements must be deallocated | |
393 | //!with deallocate(...) | |
394 | void deallocate_many(multiallocation_chain &chain); | |
395 | ||
396 | //!Allocates just one object. Memory allocated with this function | |
397 | //!must be deallocated only with deallocate_one(). | |
398 | //!Throws boost::interprocess::bad_alloc if there is no enough memory | |
399 | pointer allocate_one(); | |
400 | ||
401 | //!Allocates many elements of size == 1 in a contiguous block | |
402 | //!of memory. The minimum number to be allocated is min_elements, | |
403 | //!the preferred and maximum number is | |
404 | //!preferred_elements. The number of actually allocated elements is | |
405 | //!will be assigned to received_size. Memory allocated with this function | |
406 | //!must be deallocated only with deallocate_one(). | |
407 | void allocate_individual(size_type num_elements, multiallocation_chain &chain); | |
408 | ||
409 | //!Deallocates memory previously allocated with allocate_one(). | |
410 | //!You should never use deallocate_one to deallocate memory allocated | |
411 | //!with other functions different from allocate_one(). Never throws | |
412 | void deallocate_one(const pointer &p); | |
413 | ||
414 | //!Allocates many elements of size == 1 in a contiguous block | |
415 | //!of memory. The minimum number to be allocated is min_elements, | |
416 | //!the preferred and maximum number is | |
417 | //!preferred_elements. The number of actually allocated elements is | |
418 | //!will be assigned to received_size. Memory allocated with this function | |
419 | //!must be deallocated only with deallocate_one(). | |
420 | void deallocate_individual(multiallocation_chain &chain); | |
421 | #endif | |
422 | }; | |
423 | ||
424 | #ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED | |
425 | ||
426 | //!Equality test for same type | |
427 | //!of private_node_allocator | |
428 | template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline | |
429 | bool operator==(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1, | |
430 | const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2); | |
431 | ||
432 | //!Inequality test for same type | |
433 | //!of private_node_allocator | |
434 | template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline | |
435 | bool operator!=(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1, | |
436 | const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2); | |
437 | ||
438 | #endif | |
439 | ||
440 | } //namespace interprocess { | |
441 | } //namespace boost { | |
442 | ||
443 | #include <boost/interprocess/detail/config_end.hpp> | |
444 | ||
445 | #endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP | |
446 |