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