Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / interprocess / segment_manager.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_SEGMENT_MANAGER_HPP
12 #define BOOST_INTERPROCESS_SEGMENT_MANAGER_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/detail/no_exceptions_support.hpp>
22 #include <boost/interprocess/detail/type_traits.hpp>
23
24 #include <boost/interprocess/detail/transform_iterator.hpp>
25
26 #include <boost/interprocess/detail/mpl.hpp>
27 #include <boost/interprocess/detail/segment_manager_helper.hpp>
28 #include <boost/interprocess/detail/named_proxy.hpp>
29 #include <boost/interprocess/detail/utilities.hpp>
30 #include <boost/interprocess/offset_ptr.hpp>
31 #include <boost/interprocess/indexes/iset_index.hpp>
32 #include <boost/interprocess/exceptions.hpp>
33 #include <boost/interprocess/allocators/allocator.hpp>
34 #include <boost/interprocess/smart_ptr/deleter.hpp>
35 #include <boost/move/utility_core.hpp>
36 #include <boost/interprocess/sync/scoped_lock.hpp>
37 #include <cstddef>   //std::size_t
38 #include <string>    //char_traits
39 #include <new>       //std::nothrow
40 #include <utility>   //std::pair
41 #include <boost/assert.hpp>
42 #ifndef BOOST_NO_EXCEPTIONS
43 #include <exception>
44 #endif
45
46 //!\file
47 //!Describes the object placed in a memory segment that provides
48 //!named object allocation capabilities for single-segment and
49 //!multi-segment allocations.
50
51 namespace boost{
52 namespace interprocess{
53
54 //!This object is the public base class of segment manager.
55 //!This class only depends on the memory allocation algorithm
56 //!and implements all the allocation features not related
57 //!to named or unique objects.
58 //!
59 //!Storing a reference to segment_manager forces
60 //!the holder class to be dependent on index types and character types.
61 //!When such dependence is not desirable and only anonymous and raw
62 //!allocations are needed, segment_manager_base is the correct answer.
63 template<class MemoryAlgorithm>
64 class segment_manager_base
65    :  private MemoryAlgorithm
66 {
67    public:
68    typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
69    typedef typename MemoryAlgorithm::void_pointer  void_pointer;
70    typedef typename MemoryAlgorithm::mutex_family  mutex_family;
71    typedef MemoryAlgorithm memory_algorithm;
72
73    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
74
75    //Experimental. Don't use
76    typedef typename MemoryAlgorithm::multiallocation_chain    multiallocation_chain;
77    typedef typename MemoryAlgorithm::difference_type  difference_type;
78    typedef typename MemoryAlgorithm::size_type        size_type;
79
80    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
81
82    //!This constant indicates the payload size
83    //!associated with each allocation of the memory algorithm
84    static const size_type PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation;
85
86    //!Constructor of the segment_manager_base
87    //!
88    //!"size" is the size of the memory segment where
89    //!the basic segment manager is being constructed.
90    //!
91    //!"reserved_bytes" is the number of bytes
92    //!after the end of the memory algorithm object itself
93    //!that the memory algorithm will exclude from
94    //!dynamic allocation
95    //!
96    //!Can throw
97    segment_manager_base(size_type sz, size_type reserved_bytes)
98       :  MemoryAlgorithm(sz, reserved_bytes)
99    {
100       BOOST_ASSERT((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm)));
101    }
102
103    //!Returns the size of the memory
104    //!segment
105    size_type get_size() const
106    {  return MemoryAlgorithm::get_size();  }
107
108    //!Returns the number of free bytes of the memory
109    //!segment
110    size_type get_free_memory() const
111    {  return MemoryAlgorithm::get_free_memory();  }
112
113    //!Obtains the minimum size needed by
114    //!the segment manager
115    static size_type get_min_size (size_type size)
116    {  return MemoryAlgorithm::get_min_size(size);  }
117
118    //!Allocates nbytes bytes. This function is only used in
119    //!single-segment management. Never throws
120    void * allocate (size_type nbytes, std::nothrow_t)
121    {  return MemoryAlgorithm::allocate(nbytes);   }
122
123    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
124
125    //Experimental. Dont' use.
126    //!Allocates n_elements of elem_bytes bytes.
127    //!Throws bad_alloc on failure. chain.size() is not increased on failure.
128    void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
129    {
130       size_type prev_size = chain.size();
131       MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain);
132       if(!elem_bytes || chain.size() == prev_size){
133          throw bad_alloc();
134       }
135    }
136
137    //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
138    //!Throws bad_alloc on failure. chain.size() is not increased on failure.
139    void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
140    {
141       size_type prev_size = chain.size();
142       MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain);
143       if(!sizeof_element || chain.size() == prev_size){
144          throw bad_alloc();
145       }
146    }
147
148    //!Allocates n_elements of elem_bytes bytes.
149    //!Non-throwing version. chain.size() is not increased on failure.
150    void allocate_many(std::nothrow_t, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
151    {  MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); }
152
153    //!Allocates n_elements, each one of
154    //!element_lengths[i]*sizeof_element bytes.
155    //!Non-throwing version. chain.size() is not increased on failure.
156    void allocate_many(std::nothrow_t, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
157    {  MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); }
158
159    //!Deallocates all elements contained in chain.
160    //!Never throws.
161    void deallocate_many(multiallocation_chain &chain)
162    {  MemoryAlgorithm::deallocate_many(chain); }
163
164    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
165
166    //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
167    //!on failure
168    void * allocate(size_type nbytes)
169    {
170       void * ret = MemoryAlgorithm::allocate(nbytes);
171       if(!ret)
172          throw bad_alloc();
173       return ret;
174    }
175
176    //!Allocates nbytes bytes. This function is only used in
177    //!single-segment management. Never throws
178    void * allocate_aligned (size_type nbytes, size_type alignment, std::nothrow_t)
179    {  return MemoryAlgorithm::allocate_aligned(nbytes, alignment);   }
180
181    //!Allocates nbytes bytes. This function is only used in
182    //!single-segment management. Throws bad_alloc when fails
183    void * allocate_aligned(size_type nbytes, size_type alignment)
184    {
185       void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment);
186       if(!ret)
187          throw bad_alloc();
188       return ret;
189    }
190
191    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
192
193    template<class T>
194    std::pair<T *, bool>
195       allocation_command  (boost::interprocess::allocation_type command,   size_type limit_size,
196                            size_type preferred_size,size_type &received_size,
197                            T *reuse_ptr = 0)
198    {
199       std::pair<T *, bool> ret = MemoryAlgorithm::allocation_command
200          ( command | boost::interprocess::nothrow_allocation, limit_size, preferred_size, received_size
201          , reuse_ptr);
202       if(!(command & boost::interprocess::nothrow_allocation) && !ret.first)
203          throw bad_alloc();
204       return ret;
205    }
206
207    std::pair<void *, bool>
208       raw_allocation_command  (boost::interprocess::allocation_type command,   size_type limit_objects,
209                            size_type preferred_objects,size_type &received_objects,
210                            void *reuse_ptr = 0, size_type sizeof_object = 1)
211    {
212       std::pair<void *, bool> ret = MemoryAlgorithm::raw_allocation_command
213          ( command | boost::interprocess::nothrow_allocation, limit_objects, preferred_objects, received_objects
214          , reuse_ptr, sizeof_object);
215       if(!(command & boost::interprocess::nothrow_allocation) && !ret.first)
216          throw bad_alloc();
217       return ret;
218    }
219
220    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
221
222    //!Deallocates the bytes allocated with allocate/allocate_many()
223    //!pointed by addr
224    void   deallocate          (void *addr)
225    {  MemoryAlgorithm::deallocate(addr);   }
226
227    //!Increases managed memory in extra_size bytes more. This only works
228    //!with single-segment management.
229    void grow(size_type extra_size)
230    {  MemoryAlgorithm::grow(extra_size);   }
231
232    //!Decreases managed memory to the minimum. This only works
233    //!with single-segment management.
234    void shrink_to_fit()
235    {  MemoryAlgorithm::shrink_to_fit();   }
236
237    //!Returns the result of "all_memory_deallocated()" function
238    //!of the used memory algorithm
239    bool all_memory_deallocated()
240    {   return MemoryAlgorithm::all_memory_deallocated(); }
241
242    //!Returns the result of "check_sanity()" function
243    //!of the used memory algorithm
244    bool check_sanity()
245    {   return MemoryAlgorithm::check_sanity(); }
246
247    //!Writes to zero free memory (memory not yet allocated)
248    //!of the memory algorithm
249    void zero_free_memory()
250    {   MemoryAlgorithm::zero_free_memory(); }
251
252    //!Returns the size of the buffer previously allocated pointed by ptr
253    size_type size(const void *ptr) const
254    {   return MemoryAlgorithm::size(ptr); }
255
256    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
257    protected:
258    void * prot_anonymous_construct
259       (size_type num, bool dothrow, ipcdetail::in_place_interface &table)
260    {
261       typedef ipcdetail::block_header<size_type> block_header_t;
262       block_header_t block_info (  size_type(table.size*num)
263                                  , size_type(table.alignment)
264                                  , anonymous_type
265                                  , 1
266                                  , 0);
267
268       //Allocate memory
269       void *ptr_struct = this->allocate(block_info.total_size(), std::nothrow_t());
270
271       //Check if there is enough memory
272       if(!ptr_struct){
273          if(dothrow){
274             throw bad_alloc();
275          }
276          else{
277             return 0;
278          }
279       }
280
281       //Build scoped ptr to avoid leaks with constructor exception
282       ipcdetail::mem_algo_deallocator<MemoryAlgorithm> mem(ptr_struct, *this);
283
284       //Now construct the header
285       block_header_t * hdr = new(ptr_struct) block_header_t(block_info);
286       void *ptr = 0; //avoid gcc warning
287       ptr = hdr->value();
288
289       //Now call constructors
290       ipcdetail::array_construct(ptr, num, table);
291
292       //All constructors successful, we don't want erase memory
293       mem.release();
294       return ptr;
295    }
296
297    //!Calls the destructor and makes an anonymous deallocate
298    void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table)
299    {
300
301       //Get control data from associated with this object
302       typedef ipcdetail::block_header<size_type> block_header_t;
303       block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment);
304
305       //-------------------------------
306       //scoped_lock<rmutex> guard(m_header);
307       //-------------------------------
308
309       if(ctrl_data->alloc_type() != anonymous_type){
310          //This is not an anonymous object, the pointer is wrong!
311          BOOST_ASSERT(0);
312       }
313
314       //Call destructors and free memory
315       //Build scoped ptr to avoid leaks with destructor exception
316       std::size_t destroyed = 0;
317      table.destroy_n(const_cast<void*>(object), ctrl_data->m_value_bytes/table.size, destroyed);
318       this->deallocate(ctrl_data);
319    }
320    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
321 };
322
323 //!This object is placed in the beginning of memory segment and
324 //!implements the allocation (named or anonymous) of portions
325 //!of the segment. This object contains two indexes that
326 //!maintain an association between a name and a portion of the segment.
327 //!
328 //!The first index contains the mappings for normal named objects using the
329 //!char type specified in the template parameter.
330 //!
331 //!The second index contains the association for unique instances. The key will
332 //!be the const char * returned from type_info.name() function for the unique
333 //!type to be constructed.
334 //!
335 //!segment_manager<CharType, MemoryAlgorithm, IndexType> inherits publicly
336 //!from segment_manager_base<MemoryAlgorithm> and inherits from it
337 //!many public functions related to anonymous object and raw memory allocation.
338 //!See segment_manager_base reference to know about those functions.
339 template<class CharType
340         ,class MemoryAlgorithm
341         ,template<class IndexConfig> class IndexType>
342 class segment_manager
343    :  public segment_manager_base<MemoryAlgorithm>
344 {
345    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
346    //Non-copyable
347    segment_manager();
348    segment_manager(const segment_manager &);
349    segment_manager &operator=(const segment_manager &);
350    typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_t;
351    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
352
353    public:
354    typedef MemoryAlgorithm                                  memory_algorithm;
355    typedef typename segment_manager_base_t::void_pointer    void_pointer;
356    typedef typename segment_manager_base_t::size_type       size_type;
357    typedef typename segment_manager_base_t::difference_type difference_type;
358    typedef CharType                                         char_type;
359
360    typedef segment_manager_base<MemoryAlgorithm>   segment_manager_base_type;
361
362    static const size_type PayloadPerAllocation = segment_manager_base_t::PayloadPerAllocation;
363
364    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
365    private:
366    typedef ipcdetail::block_header<size_type> block_header_t;
367    typedef ipcdetail::index_config<CharType, MemoryAlgorithm>  index_config_named;
368    typedef ipcdetail::index_config<char, MemoryAlgorithm>      index_config_unique;
369    typedef IndexType<index_config_named>                    index_type;
370    typedef ipcdetail::bool_<is_intrusive_index<index_type>::value >    is_intrusive_t;
371    typedef ipcdetail::bool_<is_node_index<index_type>::value>          is_node_index_t;
372
373    public:
374    typedef IndexType<index_config_named>                    named_index_t;
375    typedef IndexType<index_config_unique>                   unique_index_t;
376    typedef ipcdetail::char_ptr_holder<CharType>                char_ptr_holder_t;
377    typedef ipcdetail::segment_manager_iterator_transform
378       <typename named_index_t::const_iterator
379       ,is_intrusive_index<index_type>::value>   named_transform;
380
381    typedef ipcdetail::segment_manager_iterator_transform
382       <typename unique_index_t::const_iterator
383       ,is_intrusive_index<index_type>::value>   unique_transform;
384    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
385
386    typedef typename segment_manager_base_t::mutex_family       mutex_family;
387
388    typedef transform_iterator
389       <typename named_index_t::const_iterator, named_transform> const_named_iterator;
390    typedef transform_iterator
391       <typename unique_index_t::const_iterator, unique_transform> const_unique_iterator;
392
393    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
394
395    //!Constructor proxy object definition helper class
396    template<class T>
397    struct construct_proxy
398    {
399       typedef ipcdetail::named_proxy<segment_manager, T, false>   type;
400    };
401
402    //!Constructor proxy object definition helper class
403    template<class T>
404    struct construct_iter_proxy
405    {
406       typedef ipcdetail::named_proxy<segment_manager, T, true>   type;
407    };
408
409    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
410
411    //!Constructor of the segment manager
412    //!"size" is the size of the memory segment where
413    //!the segment manager is being constructed.
414    //!Can throw
415    explicit segment_manager(size_type segment_size)
416       :  segment_manager_base_t(segment_size, priv_get_reserved_bytes())
417       ,  m_header(static_cast<segment_manager_base_t*>(get_this_pointer()))
418    {
419       (void) anonymous_instance;   (void) unique_instance;
420       //Check EBO is applied, it's required
421       const void * const this_addr = this;
422       const void *const segm_addr  = static_cast<segment_manager_base_t*>(this);
423       (void)this_addr;  (void)segm_addr;
424       BOOST_ASSERT( this_addr == segm_addr);
425    }
426
427    //!Tries to find a previous named/unique allocation. Returns the address
428    //!and the object count. On failure the first member of the
429    //!returned pair is 0.
430    template <class T>
431    std::pair<T*, size_type> find  (char_ptr_holder_t name)
432    {  return this->priv_find_impl<T>(name, true);  }
433
434    //!Tries to find a previous named/unique allocation. Returns the address
435    //!and the object count. On failure the first member of the
436    //!returned pair is 0. This search is not mutex-protected!
437    //!Use it only inside atomic_func() calls, where the internal mutex
438    //!is guaranteed to be locked.
439    template <class T>
440    std::pair<T*, size_type> find_no_lock  (char_ptr_holder_t name)
441    {  return this->priv_find_impl<T>(name, false);  }
442
443    //!Returns throwing "construct" proxy
444    //!object
445    template <class T>
446    typename construct_proxy<T>::type
447       construct(char_ptr_holder_t name)
448    {  return typename construct_proxy<T>::type (this, name, false, true);  }
449
450    //!Returns throwing "search or construct" proxy
451    //!object
452    template <class T>
453    typename construct_proxy<T>::type find_or_construct(char_ptr_holder_t name)
454    {  return typename construct_proxy<T>::type (this, name, true, true);  }
455
456    //!Returns no throwing "construct" proxy
457    //!object
458    template <class T>
459    typename construct_proxy<T>::type
460       construct(char_ptr_holder_t name, std::nothrow_t)
461    {  return typename construct_proxy<T>::type (this, name, false, false);  }
462
463    //!Returns no throwing "search or construct"
464    //!proxy object
465    template <class T>
466    typename construct_proxy<T>::type
467       find_or_construct(char_ptr_holder_t name, std::nothrow_t)
468    {  return typename construct_proxy<T>::type (this, name, true, false);  }
469
470    //!Returns throwing "construct from iterators" proxy object
471    template <class T>
472    typename construct_iter_proxy<T>::type
473       construct_it(char_ptr_holder_t name)
474    {  return typename construct_iter_proxy<T>::type (this, name, false, true);  }
475
476    //!Returns throwing "search or construct from iterators"
477    //!proxy object
478    template <class T>
479    typename construct_iter_proxy<T>::type
480       find_or_construct_it(char_ptr_holder_t name)
481    {  return typename construct_iter_proxy<T>::type (this, name, true, true);  }
482
483    //!Returns no throwing "construct from iterators"
484    //!proxy object
485    template <class T>
486    typename construct_iter_proxy<T>::type
487       construct_it(char_ptr_holder_t name, std::nothrow_t)
488    {  return typename construct_iter_proxy<T>::type (this, name, false, false);  }
489
490    //!Returns no throwing "search or construct from iterators"
491    //!proxy object
492    template <class T>
493    typename construct_iter_proxy<T>::type
494       find_or_construct_it(char_ptr_holder_t name, std::nothrow_t)
495    {  return typename construct_iter_proxy<T>::type (this, name, true, false);  }
496
497    //!Calls object function blocking recursive interprocess_mutex and guarantees that
498    //!no new named_alloc or destroy will be executed by any process while
499    //!executing the object function call
500    template <class Func>
501    void atomic_func(Func &f)
502    {  scoped_lock<rmutex> guard(m_header);  f();  }
503
504    //!Tries to calls a functor guaranteeing that no new construction, search or
505    //!destruction will be executed by any process while executing the object
506    //!function call. If the atomic function can't be immediatelly executed
507    //!because the internal mutex is already locked, returns false.
508    //!If the functor throws, this function throws.
509    template <class Func>
510    bool try_atomic_func(Func &f)
511    {
512       scoped_lock<rmutex> guard(m_header, try_to_lock);
513       if(guard){
514          f();
515          return true;
516       }
517       else{
518          return false;
519       }
520    }
521
522    //!Destroys a previously created named/unique instance.
523    //!Returns false if the object was not present.
524    template <class T>
525    bool destroy(char_ptr_holder_t name)
526    {
527       BOOST_ASSERT(!name.is_anonymous());
528       ipcdetail::placement_destroy<T> dtor;
529
530       if(name.is_unique()){
531          return this->priv_generic_named_destroy<char>
532             ( typeid(T).name(), m_header.m_unique_index , dtor, is_intrusive_t());
533       }
534       else{
535          return this->priv_generic_named_destroy<CharType>
536             ( name.get(), m_header.m_named_index, dtor, is_intrusive_t());
537       }
538    }
539
540    //!Destroys an anonymous, unique or named object
541    //!using its address
542    template <class T>
543    void destroy_ptr(const T *p)
544    {
545       //If T is void transform it to char
546       typedef typename ipcdetail::char_if_void<T>::type data_t;
547       ipcdetail::placement_destroy<data_t> dtor;
548       priv_destroy_ptr(p, dtor);
549    }
550
551    //!Returns the name of an object created with construct/find_or_construct
552    //!functions. Does not throw
553    template<class T>
554    static const CharType *get_instance_name(const T *ptr)
555    { return priv_get_instance_name(block_header_t::block_header_from_value(ptr));  }
556
557    //!Returns the length of an object created with construct/find_or_construct
558    //!functions. Does not throw.
559    template<class T>
560    static size_type get_instance_length(const T *ptr)
561    {  return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T));  }
562
563    //!Returns is the the name of an object created with construct/find_or_construct
564    //!functions. Does not throw
565    template<class T>
566    static instance_type get_instance_type(const T *ptr)
567    {  return priv_get_instance_type(block_header_t::block_header_from_value(ptr));  }
568
569    //!Preallocates needed index resources to optimize the
570    //!creation of "num" named objects in the managed memory segment.
571    //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
572    void reserve_named_objects(size_type num)
573    {
574       //-------------------------------
575       scoped_lock<rmutex> guard(m_header);
576       //-------------------------------
577       m_header.m_named_index.reserve(num);
578    }
579
580    //!Preallocates needed index resources to optimize the
581    //!creation of "num" unique objects in the managed memory segment.
582    //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
583    void reserve_unique_objects(size_type num)
584    {
585       //-------------------------------
586       scoped_lock<rmutex> guard(m_header);
587       //-------------------------------
588       m_header.m_unique_index.reserve(num);
589    }
590
591    //!Calls shrink_to_fit in both named and unique object indexes
592    //!to try to free unused memory from those indexes.
593    void shrink_to_fit_indexes()
594    {
595       //-------------------------------
596       scoped_lock<rmutex> guard(m_header);
597       //-------------------------------
598       m_header.m_named_index.shrink_to_fit();
599       m_header.m_unique_index.shrink_to_fit();
600    }
601
602    //!Returns the number of named objects stored in
603    //!the segment.
604    size_type get_num_named_objects()
605    {
606       //-------------------------------
607       scoped_lock<rmutex> guard(m_header);
608       //-------------------------------
609       return m_header.m_named_index.size();
610    }
611
612    //!Returns the number of unique objects stored in
613    //!the segment.
614    size_type get_num_unique_objects()
615    {
616       //-------------------------------
617       scoped_lock<rmutex> guard(m_header);
618       //-------------------------------
619       return m_header.m_unique_index.size();
620    }
621
622    //!Obtains the minimum size needed by the
623    //!segment manager
624    static size_type get_min_size()
625    {  return segment_manager_base_t::get_min_size(priv_get_reserved_bytes());  }
626
627    //!Returns a constant iterator to the beginning of the information about
628    //!the named allocations performed in this segment manager
629    const_named_iterator named_begin() const
630    {
631       return make_transform_iterator
632          (m_header.m_named_index.begin(), named_transform());
633    }
634
635    //!Returns a constant iterator to the end of the information about
636    //!the named allocations performed in this segment manager
637    const_named_iterator named_end() const
638    {
639       return make_transform_iterator
640          (m_header.m_named_index.end(), named_transform());
641    }
642
643    //!Returns a constant iterator to the beginning of the information about
644    //!the unique allocations performed in this segment manager
645    const_unique_iterator unique_begin() const
646    {
647       return make_transform_iterator
648          (m_header.m_unique_index.begin(), unique_transform());
649    }
650
651    //!Returns a constant iterator to the end of the information about
652    //!the unique allocations performed in this segment manager
653    const_unique_iterator unique_end() const
654    {
655       return make_transform_iterator
656          (m_header.m_unique_index.end(), unique_transform());
657    }
658
659    //!This is the default allocator to allocate types T
660    //!from this managed segment
661    template<class T>
662    struct allocator
663    {
664       typedef boost::interprocess::allocator<T, segment_manager> type;
665    };
666
667    //!Returns an instance of the default allocator for type T
668    //!initialized that allocates memory from this segment manager.
669    template<class T>
670    typename allocator<T>::type
671       get_allocator()
672    {   return typename allocator<T>::type(this); }
673
674    //!This is the default deleter to delete types T
675    //!from this managed segment.
676    template<class T>
677    struct deleter
678    {
679       typedef boost::interprocess::deleter<T, segment_manager> type;
680    };
681
682    //!Returns an instance of the default deleter for type T
683    //!that will delete an object constructed in this segment manager.
684    template<class T>
685    typename deleter<T>::type
686       get_deleter()
687    {   return typename deleter<T>::type(this); }
688
689    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
690
691    //!Generic named/anonymous new function. Offers all the possibilities,
692    //!such as throwing, search before creating, and the constructor is
693    //!encapsulated in an object function.
694    template<class T>
695    T *generic_construct(const CharType *name,
696                         size_type num,
697                          bool try2find,
698                          bool dothrow,
699                          ipcdetail::in_place_interface &table)
700    {
701       return static_cast<T*>
702          (priv_generic_construct(name, num, try2find, dothrow, table));
703    }
704
705    private:
706    //!Tries to find a previous named allocation. Returns the address
707    //!and the object count. On failure the first member of the
708    //!returned pair is 0.
709    template <class T>
710    std::pair<T*, size_type> priv_find_impl (const CharType* name, bool lock)
711    {
712       //The name can't be null, no anonymous object can be found by name
713       BOOST_ASSERT(name != 0);
714       ipcdetail::placement_destroy<T> table;
715       size_type sz;
716       void *ret;
717
718       if(name == reinterpret_cast<const CharType*>(-1)){
719          ret = priv_generic_find<char> (typeid(T).name(), m_header.m_unique_index, table, sz, is_intrusive_t(), lock);
720       }
721       else{
722          ret = priv_generic_find<CharType> (name, m_header.m_named_index, table, sz, is_intrusive_t(), lock);
723       }
724       return std::pair<T*, size_type>(static_cast<T*>(ret), sz);
725    }
726
727    //!Tries to find a previous unique allocation. Returns the address
728    //!and the object count. On failure the first member of the
729    //!returned pair is 0.
730    template <class T>
731    std::pair<T*, size_type> priv_find__impl (const ipcdetail::unique_instance_t* name, bool lock)
732    {
733       ipcdetail::placement_destroy<T> table;
734       size_type size;
735       void *ret = priv_generic_find<char>(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock);
736       return std::pair<T*, size_type>(static_cast<T*>(ret), size);
737    }
738
739    void *priv_generic_construct
740       (const CharType *name, size_type num, bool try2find, bool dothrow, ipcdetail::in_place_interface &table)
741    {
742       void *ret;
743       //Security overflow check
744      if(num > ((std::size_t)-1)/table.size){
745          if(dothrow)
746             throw bad_alloc();
747          else
748             return 0;
749       }
750       if(name == 0){
751          ret = this->prot_anonymous_construct(num, dothrow, table);
752       }
753       else if(name == reinterpret_cast<const CharType*>(-1)){
754          ret = this->priv_generic_named_construct<char>
755             (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t());
756       }
757       else{
758          ret = this->priv_generic_named_construct<CharType>
759             (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t());
760       }
761       return ret;
762    }
763
764    void priv_destroy_ptr(const void *ptr, ipcdetail::in_place_interface &dtor)
765    {
766       block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment);
767       switch(ctrl_data->alloc_type()){
768          case anonymous_type:
769             this->prot_anonymous_destroy(ptr, dtor);
770          break;
771
772          case named_type:
773             this->priv_generic_named_destroy<CharType>
774                (ctrl_data, m_header.m_named_index, dtor, is_node_index_t());
775          break;
776
777          case unique_type:
778             this->priv_generic_named_destroy<char>
779                (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t());
780          break;
781
782          default:
783             //This type is unknown, bad pointer passed to this function!
784             BOOST_ASSERT(0);
785          break;
786       }
787    }
788
789    //!Returns the name of an object created with construct/find_or_construct
790    //!functions. Does not throw
791    static const CharType *priv_get_instance_name(block_header_t *ctrl_data)
792    {
793       boost::interprocess::allocation_type type = ctrl_data->alloc_type();
794       if(type == anonymous_type){
795          BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) ||
796                 (type == unique_type    && ctrl_data->m_num_char != 0) );
797          return 0;
798       }
799       CharType *name = static_cast<CharType*>(ctrl_data->template name<CharType>());
800
801       //Sanity checks
802       BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType));
803       BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits<CharType>::length(name));
804       return name;
805    }
806
807    static size_type priv_get_instance_length(block_header_t *ctrl_data, size_type sizeofvalue)
808    {
809       //Get header
810       BOOST_ASSERT((ctrl_data->value_bytes() %sizeofvalue) == 0);
811       return ctrl_data->value_bytes()/sizeofvalue;
812    }
813
814    //!Returns is the the name of an object created with construct/find_or_construct
815    //!functions. Does not throw
816    static instance_type priv_get_instance_type(block_header_t *ctrl_data)
817    {
818       //Get header
819       BOOST_ASSERT((instance_type)ctrl_data->alloc_type() < max_allocation_type);
820       return (instance_type)ctrl_data->alloc_type();
821    }
822
823    static size_type priv_get_reserved_bytes()
824    {
825       //Get the number of bytes until the end of (*this)
826       //beginning in the end of the segment_manager_base_t base.
827       return sizeof(segment_manager) - sizeof(segment_manager_base_t);
828    }
829
830    template <class CharT>
831    void *priv_generic_find
832       (const CharT* name,
833        IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
834        ipcdetail::in_place_interface &table,
835        size_type &length, ipcdetail::true_ is_intrusive, bool use_lock)
836    {
837       (void)is_intrusive;
838       typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >         index_type;
839       typedef typename index_type::iterator           index_it;
840
841       //-------------------------------
842       scoped_lock<rmutex> guard(priv_get_lock(use_lock));
843       //-------------------------------
844       //Find name in index
845       ipcdetail::intrusive_compare_key<CharT> key
846          (name, std::char_traits<CharT>::length(name));
847       index_it it = index.find(key);
848
849       //Initialize return values
850       void *ret_ptr  = 0;
851       length         = 0;
852
853       //If found, assign values
854       if(it != index.end()){
855          //Get header
856          block_header_t *ctrl_data = it->get_block_header();
857
858          //Sanity check
859          BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
860          BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
861          ret_ptr  = ctrl_data->value();
862          length  = ctrl_data->m_value_bytes/table.size;
863       }
864       return ret_ptr;
865    }
866
867    template <class CharT>
868    void *priv_generic_find
869       (const CharT* name,
870        IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
871        ipcdetail::in_place_interface &table,
872        size_type &length, ipcdetail::false_ is_intrusive, bool use_lock)
873    {
874       (void)is_intrusive;
875       typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >      index_type;
876       typedef typename index_type::key_type        key_type;
877       typedef typename index_type::iterator        index_it;
878
879       //-------------------------------
880       scoped_lock<rmutex> guard(priv_get_lock(use_lock));
881       //-------------------------------
882       //Find name in index
883       index_it it = index.find(key_type(name, std::char_traits<CharT>::length(name)));
884
885       //Initialize return values
886       void *ret_ptr  = 0;
887       length         = 0;
888
889       //If found, assign values
890       if(it != index.end()){
891          //Get header
892          block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
893                                     (ipcdetail::to_raw_pointer(it->second.m_ptr));
894
895          //Sanity check
896          BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
897          BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT));
898          ret_ptr  = ctrl_data->value();
899          length  = ctrl_data->m_value_bytes/table.size;
900       }
901       return ret_ptr;
902    }
903
904    template <class CharT>
905    bool priv_generic_named_destroy
906      (block_header_t *block_header,
907       IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
908       ipcdetail::in_place_interface &table, ipcdetail::true_ is_node_index)
909    {
910       (void)is_node_index;
911       typedef typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator index_it;
912
913       index_it *ihdr = block_header_t::template to_first_header<index_it>(block_header);
914       return this->priv_generic_named_destroy_impl<CharT>(*ihdr, index, table);
915    }
916
917    template <class CharT>
918    bool priv_generic_named_destroy
919      (block_header_t *block_header,
920       IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
921       ipcdetail::in_place_interface &table,
922       ipcdetail::false_ is_node_index)
923    {
924       (void)is_node_index;
925       CharT *name = static_cast<CharT*>(block_header->template name<CharT>());
926       return this->priv_generic_named_destroy<CharT>(name, index, table, is_intrusive_t());
927    }
928
929    template <class CharT>
930    bool priv_generic_named_destroy(const CharT *name,
931                                    IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
932                                    ipcdetail::in_place_interface &table, ipcdetail::true_ is_intrusive_index)
933    {
934       (void)is_intrusive_index;
935       typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >         index_type;
936       typedef typename index_type::iterator           index_it;
937       typedef typename index_type::value_type         intrusive_value_type;
938
939       //-------------------------------
940       scoped_lock<rmutex> guard(m_header);
941       //-------------------------------
942       //Find name in index
943       ipcdetail::intrusive_compare_key<CharT> key
944          (name, std::char_traits<CharT>::length(name));
945       index_it it = index.find(key);
946
947       //If not found, return false
948       if(it == index.end()){
949          //This name is not present in the index, wrong pointer or name!
950          //BOOST_ASSERT(0);
951          return false;
952       }
953
954       block_header_t *ctrl_data = it->get_block_header();
955       intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data);
956       void *memory = iv;
957       void *values = ctrl_data->value();
958       std::size_t num = ctrl_data->m_value_bytes/table.size;
959
960       //Sanity check
961       BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
962       BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
963
964       //Erase node from index
965       index.erase(it);
966
967       //Destroy the headers
968       ctrl_data->~block_header_t();
969       iv->~intrusive_value_type();
970
971       //Call destructors and free memory
972       std::size_t destroyed;
973       table.destroy_n(values, num, destroyed);
974       this->deallocate(memory);
975       return true;
976    }
977
978    template <class CharT>
979    bool priv_generic_named_destroy(const CharT *name,
980                                    IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
981                                    ipcdetail::in_place_interface &table,
982                                    ipcdetail::false_ is_intrusive_index)
983    {
984       (void)is_intrusive_index;
985       typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >            index_type;
986       typedef typename index_type::iterator              index_it;
987       typedef typename index_type::key_type              key_type;
988
989       //-------------------------------
990       scoped_lock<rmutex> guard(m_header);
991       //-------------------------------
992       //Try to find the name in the index
993       index_it it = index.find(key_type (name,
994                                      std::char_traits<CharT>::length(name)));
995
996       //If not found, return false
997       if(it == index.end()){
998          //This name is not present in the index, wrong pointer or name!
999          //BOOST_ASSERT(0);
1000          return false;
1001       }
1002       return this->priv_generic_named_destroy_impl<CharT>(it, index, table);
1003    }
1004
1005    template <class CharT>
1006    bool priv_generic_named_destroy_impl
1007       (const typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
1008       IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
1009       ipcdetail::in_place_interface &table)
1010    {
1011       typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >      index_type;
1012       typedef typename index_type::iterator        index_it;
1013
1014       //Get allocation parameters
1015       block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
1016                                  (ipcdetail::to_raw_pointer(it->second.m_ptr));
1017       char *stored_name       = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
1018       (void)stored_name;
1019
1020       //Check if the distance between the name pointer and the memory pointer
1021       //is correct (this can detect incorrect type in destruction)
1022      std::size_t num = ctrl_data->m_value_bytes/table.size;
1023       void *values = ctrl_data->value();
1024
1025       //Sanity check
1026       BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
1027       BOOST_ASSERT(static_cast<void*>(stored_name) == static_cast<void*>(ctrl_data->template name<CharT>()));
1028       BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
1029
1030       //Erase node from index
1031       index.erase(it);
1032
1033       //Destroy the header
1034       ctrl_data->~block_header_t();
1035
1036       void *memory;
1037       if(is_node_index_t::value){
1038          index_it *ihdr = block_header_t::template
1039             to_first_header<index_it>(ctrl_data);
1040          ihdr->~index_it();
1041          memory = ihdr;
1042       }
1043       else{
1044          memory = ctrl_data;
1045       }
1046
1047       //Call destructors and free memory
1048       std::size_t destroyed;
1049       table.destroy_n(values, num, destroyed);
1050       this->deallocate(memory);
1051       return true;
1052    }
1053
1054    template<class CharT>
1055    void * priv_generic_named_construct
1056       (unsigned char type, const CharT *name, size_type num, bool try2find,
1057       bool dothrow, ipcdetail::in_place_interface &table, 
1058       IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::true_ is_intrusive)
1059    {
1060       (void)is_intrusive;
1061      std::size_t namelen  = std::char_traits<CharT>::length(name);
1062
1063       block_header_t block_info ( size_type(table.size*num)
1064                                  , size_type(table.alignment)
1065                                  , type
1066                                  , sizeof(CharT)
1067                                  , namelen);
1068
1069       typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >            index_type;
1070       typedef typename index_type::iterator              index_it;
1071       typedef std::pair<index_it, bool>                  index_ib;
1072
1073       //-------------------------------
1074       scoped_lock<rmutex> guard(m_header);
1075       //-------------------------------
1076       //Insert the node. This can throw.
1077       //First, we want to know if the key is already present before
1078       //we allocate any memory, and if the key is not present, we
1079       //want to allocate all memory in a single buffer that will
1080       //contain the name and the user buffer.
1081       //
1082       //Since equal_range(key) + insert(hint, value) approach is
1083       //quite inefficient in container implementations
1084       //(they re-test if the position is correct), I've chosen
1085       //to insert the node, do an ugly un-const cast and modify
1086       //the key (which is a smart pointer) to an equivalent one
1087       index_ib insert_ret;
1088
1089       typename index_type::insert_commit_data   commit_data;
1090       typedef typename index_type::value_type   intrusive_value_type;
1091
1092       BOOST_TRY{
1093          ipcdetail::intrusive_compare_key<CharT> key(name, namelen);
1094          insert_ret = index.insert_check(key, commit_data);
1095       }
1096       //Ignore exceptions
1097       BOOST_CATCH(...){
1098          if(dothrow)
1099             BOOST_RETHROW
1100          return 0;
1101       }
1102       BOOST_CATCH_END
1103
1104       index_it it = insert_ret.first;
1105
1106       //If found and this is find or construct, return data
1107       //else return null
1108       if(!insert_ret.second){
1109          if(try2find){
1110             return it->get_block_header()->value();
1111          }
1112          if(dothrow){
1113             throw interprocess_exception(already_exists_error);
1114          }
1115          else{
1116             return 0;
1117          }
1118       }
1119
1120       //Allocates buffer for name + data, this can throw (it hurts)
1121       void *buffer_ptr;
1122
1123       //Check if there is enough memory
1124       if(dothrow){
1125          buffer_ptr = this->allocate
1126             (block_info.template total_size_with_header<intrusive_value_type>());
1127       }
1128       else{
1129          buffer_ptr = this->allocate
1130             (block_info.template total_size_with_header<intrusive_value_type>(), std::nothrow_t());
1131          if(!buffer_ptr)
1132             return 0;
1133       }
1134
1135       //Now construct the intrusive hook plus the header
1136       intrusive_value_type * intrusive_hdr = new(buffer_ptr) intrusive_value_type();
1137       block_header_t * hdr = new(intrusive_hdr->get_block_header())block_header_t(block_info);
1138       void *ptr = 0; //avoid gcc warning
1139       ptr = hdr->value();
1140
1141       //Copy name to memory segment and insert data
1142       CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
1143       std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
1144
1145       BOOST_TRY{
1146          //Now commit the insertion using previous context data
1147          it = index.insert_commit(*intrusive_hdr, commit_data);
1148       }
1149       //Ignore exceptions
1150       BOOST_CATCH(...){
1151          if(dothrow)
1152             BOOST_RETHROW
1153          return 0;
1154       }
1155       BOOST_CATCH_END
1156
1157       //Avoid constructions if constructor is trivial
1158       //Build scoped ptr to avoid leaks with constructor exception
1159       ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
1160          (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
1161
1162       //Initialize the node value_eraser to erase inserted node
1163       //if something goes wrong. This will be executed *before*
1164       //the memory allocation as the intrusive value is built in that
1165       //memory
1166       value_eraser<index_type> v_eraser(index, it);
1167
1168       //Construct array, this can throw
1169       ipcdetail::array_construct(ptr, num, table);
1170
1171       //Release rollbacks since construction was successful
1172       v_eraser.release();
1173       mem.release();
1174       return ptr;
1175    }
1176
1177    //!Generic named new function for
1178    //!named functions
1179    template<class CharT>
1180    void * priv_generic_named_construct
1181       (unsigned char type, const CharT *name, size_type num, bool try2find, bool dothrow,
1182       ipcdetail::in_place_interface &table, 
1183       IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::false_ is_intrusive)
1184    {
1185       (void)is_intrusive;
1186       std::size_t namelen  = std::char_traits<CharT>::length(name);
1187
1188       block_header_t block_info ( size_type(table.size*num)
1189                                  , size_type(table.alignment)
1190                                  , type
1191                                  , sizeof(CharT)
1192                                  , namelen);
1193
1194       typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >            index_type;
1195       typedef typename index_type::key_type              key_type;
1196       typedef typename index_type::mapped_type           mapped_type;
1197       typedef typename index_type::value_type            value_type;
1198       typedef typename index_type::iterator              index_it;
1199       typedef std::pair<index_it, bool>                  index_ib;
1200
1201       //-------------------------------
1202       scoped_lock<rmutex> guard(m_header);
1203       //-------------------------------
1204       //Insert the node. This can throw.
1205       //First, we want to know if the key is already present before
1206       //we allocate any memory, and if the key is not present, we
1207       //want to allocate all memory in a single buffer that will
1208       //contain the name and the user buffer.
1209       //
1210       //Since equal_range(key) + insert(hint, value) approach is
1211       //quite inefficient in container implementations
1212       //(they re-test if the position is correct), I've chosen
1213       //to insert the node, do an ugly un-const cast and modify
1214       //the key (which is a smart pointer) to an equivalent one
1215       index_ib insert_ret;
1216       BOOST_TRY{
1217          insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0)));
1218       }
1219       //Ignore exceptions
1220       BOOST_CATCH(...){
1221          if(dothrow)
1222             BOOST_RETHROW;
1223          return 0;
1224       }
1225       BOOST_CATCH_END
1226
1227       index_it it = insert_ret.first;
1228
1229       //If found and this is find or construct, return data
1230       //else return null
1231       if(!insert_ret.second){
1232          if(try2find){
1233             block_header_t *hdr = static_cast<block_header_t*>
1234                (ipcdetail::to_raw_pointer(it->second.m_ptr));
1235             return hdr->value();
1236          }
1237          return 0;
1238       }
1239       //Initialize the node value_eraser to erase inserted node
1240       //if something goes wrong
1241       value_eraser<index_type> v_eraser(index, it);
1242
1243       //Allocates buffer for name + data, this can throw (it hurts)
1244       void *buffer_ptr;
1245       block_header_t * hdr;
1246
1247       //Allocate and construct the headers
1248       if(is_node_index_t::value){
1249          size_type total_size = block_info.template total_size_with_header<index_it>();
1250          if(dothrow){
1251             buffer_ptr = this->allocate(total_size);
1252          }
1253          else{
1254             buffer_ptr = this->allocate(total_size, std::nothrow_t());
1255             if(!buffer_ptr)
1256                return 0;
1257          }
1258          index_it *idr = new(buffer_ptr) index_it(it);
1259          hdr = block_header_t::template from_first_header<index_it>(idr);
1260       }
1261       else{
1262          if(dothrow){
1263             buffer_ptr = this->allocate(block_info.total_size());
1264          }
1265          else{
1266             buffer_ptr = this->allocate(block_info.total_size(), std::nothrow_t());
1267             if(!buffer_ptr)
1268                return 0;
1269          }
1270          hdr = static_cast<block_header_t*>(buffer_ptr);
1271       }
1272
1273       hdr = new(hdr)block_header_t(block_info);
1274       void *ptr = 0; //avoid gcc warning
1275       ptr = hdr->value();
1276
1277       //Copy name to memory segment and insert data
1278       CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
1279       std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
1280
1281       //Do the ugly cast, please mama, forgive me!
1282       //This new key points to an identical string, so it must have the
1283       //same position than the overwritten key according to the predicate
1284       const_cast<key_type &>(it->first).name(name_ptr);
1285       it->second.m_ptr  = hdr;
1286
1287       //Build scoped ptr to avoid leaks with constructor exception
1288       ipcdetail::mem_algo_deallocator<segment_manager_base_type> mem
1289          (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
1290
1291       //Construct array, this can throw
1292       ipcdetail::array_construct(ptr, num, table);
1293
1294       //All constructors successful, we don't want to release memory
1295       mem.release();
1296
1297       //Release node v_eraser since construction was successful
1298       v_eraser.release();
1299       return ptr;
1300    }
1301
1302    private:
1303    //!Returns the this pointer
1304    segment_manager *get_this_pointer()
1305    {  return this;  }
1306
1307    typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type   rmutex;
1308
1309    scoped_lock<rmutex> priv_get_lock(bool use_lock)
1310    {
1311       scoped_lock<rmutex> local(m_header, defer_lock);
1312       if(use_lock){
1313          local.lock();
1314       }
1315       return scoped_lock<rmutex>(boost::move(local));
1316    }
1317
1318    //!This struct includes needed data and derives from
1319    //!rmutex to allow EBO when using null interprocess_mutex
1320    struct header_t
1321       :  public rmutex
1322    {
1323       named_index_t           m_named_index;
1324       unique_index_t          m_unique_index;
1325
1326       header_t(segment_manager_base_t *segment_mngr_base)
1327          :  m_named_index (segment_mngr_base)
1328          ,  m_unique_index(segment_mngr_base)
1329       {}
1330    }  m_header;
1331
1332    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
1333 };
1334
1335
1336 }} //namespace boost { namespace interprocess
1337
1338 #include <boost/interprocess/detail/config_end.hpp>
1339
1340 #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
1341