fix doc example typo
[boost.git] / boost / interprocess / segment_manager.hpp
blob972e08cb679ccbfa5eae87754694ac2c7ee98c99
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-2008. 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 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
12 #define BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
14 #if (defined _MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif
18 #include <boost/interprocess/detail/config_begin.hpp>
19 #include <boost/interprocess/detail/workaround.hpp>
21 #include <boost/detail/no_exceptions_support.hpp>
22 #include <boost/interprocess/detail/type_traits.hpp>
24 #include <boost/interprocess/detail/transform_iterator.hpp>
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/interprocess/detail/move.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 #ifndef BOOST_NO_EXCEPTIONS
42 #include <exception>
43 #endif
45 //!\file
46 //!Describes the object placed in a memory segment that provides
47 //!named object allocation capabilities for single-segment and
48 //!multi-segment allocations.
50 namespace boost{
51 namespace interprocess{
53 //!This object is the public base class of segment manager.
54 //!This class only depends on the memory allocation algorithm
55 //!and implements all the allocation features not related
56 //!to named or unique objects.
57 //!
58 //!Storing a reference to segment_manager forces
59 //!the holder class to be dependent on index types and character types.
60 //!When such dependence is not desirable and only anonymous and raw
61 //!allocations are needed, segment_manager_base is the correct answer.
62 template<class MemoryAlgorithm>
63 class segment_manager_base
64 : private MemoryAlgorithm
66 public:
67 typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
68 typedef typename MemoryAlgorithm::void_pointer void_pointer;
69 typedef typename MemoryAlgorithm::mutex_family mutex_family;
70 typedef MemoryAlgorithm memory_algorithm;
72 /// @cond
74 //Experimental. Don't use
75 typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
77 /// @endcond
79 //!This constant indicates the payload size
80 //!associated with each allocation of the memory algorithm
81 static const std::size_t PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation;
83 //!Constructor of the segment_manager_base
84 //!
85 //!"size" is the size of the memory segment where
86 //!the basic segment manager is being constructed.
87 //!
88 //!"reserved_bytes" is the number of bytes
89 //!after the end of the memory algorithm object itself
90 //!that the memory algorithm will exclude from
91 //!dynamic allocation
92 //!
93 //!Can throw
94 segment_manager_base(std::size_t size, std::size_t reserved_bytes)
95 : MemoryAlgorithm(size, reserved_bytes)
97 assert((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm)));
100 //!Returns the size of the memory
101 //!segment
102 std::size_t get_size() const
103 { return MemoryAlgorithm::get_size(); }
105 //!Returns the number of free bytes of the memory
106 //!segment
107 std::size_t get_free_memory() const
108 { return MemoryAlgorithm::get_free_memory(); }
110 //!Obtains the minimum size needed by
111 //!the segment manager
112 static std::size_t get_min_size (std::size_t size)
113 { return MemoryAlgorithm::get_min_size(size); }
115 //!Allocates nbytes bytes. This function is only used in
116 //!single-segment management. Never throws
117 void * allocate (std::size_t nbytes, std::nothrow_t)
118 { return MemoryAlgorithm::allocate(nbytes); }
120 /// @cond
122 //Experimental. Dont' use.
123 //!Allocates n_elements of
124 //!elem_size bytes. Throws bad_alloc on failure.
125 multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements)
127 multiallocation_chain mem(MemoryAlgorithm::allocate_many(elem_bytes, num_elements));
128 if(mem.empty()) throw bad_alloc();
129 return boost::interprocess::move(mem);
132 //!Allocates n_elements, each one of
133 //!element_lenghts[i]*sizeof_element bytes. Throws bad_alloc on failure.
134 multiallocation_chain allocate_many
135 (const std::size_t *element_lenghts, std::size_t n_elements, std::size_t sizeof_element = 1)
137 multiallocation_chain mem(MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element));
138 if(mem.empty()) throw bad_alloc();
139 return boost::interprocess::move(mem);
142 //!Allocates n_elements of
143 //!elem_size bytes. Returns a default constructed iterator on failure.
144 multiallocation_chain allocate_many
145 (std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t)
146 { return MemoryAlgorithm::allocate_many(elem_bytes, num_elements); }
148 //!Allocates n_elements, each one of
149 //!element_lenghts[i]*sizeof_element bytes.
150 //!Returns a default constructed iterator on failure.
151 multiallocation_chain allocate_many
152 (const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element, std::nothrow_t)
153 { return MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element); }
155 //!Deallocates elements pointed by the
156 //!multiallocation iterator range.
157 void deallocate_many(multiallocation_chain chain)
158 { MemoryAlgorithm::deallocate_many(boost::interprocess::move(chain)); }
160 /// @endcond
162 //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
163 //!on failure
164 void * allocate(std::size_t nbytes)
166 void * ret = MemoryAlgorithm::allocate(nbytes);
167 if(!ret)
168 throw bad_alloc();
169 return ret;
172 //!Allocates nbytes bytes. This function is only used in
173 //!single-segment management. Never throws
174 void * allocate_aligned (std::size_t nbytes, std::size_t alignment, std::nothrow_t)
175 { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); }
177 //!Allocates nbytes bytes. This function is only used in
178 //!single-segment management. Throws bad_alloc when fails
179 void * allocate_aligned(std::size_t nbytes, std::size_t alignment)
181 void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment);
182 if(!ret)
183 throw bad_alloc();
184 return ret;
187 template<class T>
188 std::pair<T *, bool>
189 allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size,
190 std::size_t preferred_size,std::size_t &received_size,
191 T *reuse_ptr = 0)
193 std::pair<T *, bool> ret = MemoryAlgorithm::allocation_command
194 ( command | boost::interprocess::nothrow_allocation, limit_size, preferred_size, received_size
195 , reuse_ptr);
196 if(!(command & boost::interprocess::nothrow_allocation) && !ret.first)
197 throw bad_alloc();
198 return ret;
201 std::pair<void *, bool>
202 raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_objects,
203 std::size_t preferred_objects,std::size_t &received_objects,
204 void *reuse_ptr = 0, std::size_t sizeof_object = 1)
206 std::pair<void *, bool> ret = MemoryAlgorithm::raw_allocation_command
207 ( command | boost::interprocess::nothrow_allocation, limit_objects, preferred_objects, received_objects
208 , reuse_ptr, sizeof_object);
209 if(!(command & boost::interprocess::nothrow_allocation) && !ret.first)
210 throw bad_alloc();
211 return ret;
214 //!Deallocates the bytes allocated with allocate/allocate_many()
215 //!pointed by addr
216 void deallocate (void *addr)
217 { MemoryAlgorithm::deallocate(addr); }
219 //!Increases managed memory in extra_size bytes more. This only works
220 //!with single-segment management.
221 void grow(std::size_t extra_size)
222 { MemoryAlgorithm::grow(extra_size); }
224 //!Decreases managed memory to the minimum. This only works
225 //!with single-segment management.
226 void shrink_to_fit()
227 { MemoryAlgorithm::shrink_to_fit(); }
229 //!Returns the result of "all_memory_deallocated()" function
230 //!of the used memory algorithm
231 bool all_memory_deallocated()
232 { return MemoryAlgorithm::all_memory_deallocated(); }
234 //!Returns the result of "check_sanity()" function
235 //!of the used memory algorithm
236 bool check_sanity()
237 { return MemoryAlgorithm::check_sanity(); }
239 //!Writes to zero free memory (memory not yet allocated)
240 //!of the memory algorithm
241 void zero_free_memory()
242 { MemoryAlgorithm::zero_free_memory(); }
244 //!Returns the size of the buffer previously allocated pointed by ptr
245 std::size_t size(const void *ptr) const
246 { return MemoryAlgorithm::size(ptr); }
248 /// @cond
249 protected:
250 void * prot_anonymous_construct
251 (std::size_t num, bool dothrow, detail::in_place_interface &table)
253 typedef detail::block_header block_header_t;
254 block_header_t block_info ( table.size*num
255 , table.alignment
256 , anonymous_type
258 , 0);
260 //Allocate memory
261 void *ptr_struct = this->allocate(block_info.total_size(), std::nothrow_t());
263 //Check if there is enough memory
264 if(!ptr_struct){
265 if(dothrow){
266 throw bad_alloc();
268 else{
269 return 0;
273 //Build scoped ptr to avoid leaks with constructor exception
274 detail::mem_algo_deallocator<MemoryAlgorithm> mem(ptr_struct, *this);
276 //Now construct the header
277 block_header_t * hdr = new(ptr_struct) block_header_t(block_info);
278 void *ptr = 0; //avoid gcc warning
279 ptr = hdr->value();
281 //Now call constructors
282 detail::array_construct(ptr, num, table);
284 //All constructors successful, we don't want erase memory
285 mem.release();
286 return ptr;
289 //!Calls the destructor and makes an anonymous deallocate
290 void prot_anonymous_destroy(const void *object, detail::in_place_interface &table)
293 //Get control data from associated with this object
294 typedef detail::block_header block_header_t;
295 block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment);
297 //-------------------------------
298 //scoped_lock<rmutex> guard(m_header);
299 //-------------------------------
301 if(ctrl_data->alloc_type() != anonymous_type){
302 //This is not an anonymous object, the pointer is wrong!
303 assert(0);
306 //Call destructors and free memory
307 //Build scoped ptr to avoid leaks with destructor exception
308 std::size_t destroyed = 0;
309 table.destroy_n(const_cast<void*>(object), ctrl_data->m_value_bytes/table.size, destroyed);
310 this->deallocate(ctrl_data);
312 /// @endcond
315 //!This object is placed in the beginning of memory segment and
316 //!implements the allocation (named or anonymous) of portions
317 //!of the segment. This object contains two indexes that
318 //!maintain an association between a name and a portion of the segment.
320 //!The first index contains the mappings for normal named objects using the
321 //!char type specified in the template parameter.
323 //!The second index contains the association for unique instances. The key will
324 //!be the const char * returned from type_info.name() function for the unique
325 //!type to be constructed.
327 //!segment_manager<CharType, MemoryAlgorithm, IndexType> inherits publicly
328 //!from segment_manager_base<MemoryAlgorithm> and inherits from it
329 //!many public functions related to anonymous object and raw memory allocation.
330 //!See segment_manager_base reference to know about those functions.
331 template<class CharType
332 ,class MemoryAlgorithm
333 ,template<class IndexConfig> class IndexType>
334 class segment_manager
335 : public segment_manager_base<MemoryAlgorithm>
337 /// @cond
338 //Non-copyable
339 segment_manager();
340 segment_manager(const segment_manager &);
341 segment_manager &operator=(const segment_manager &);
342 typedef segment_manager_base<MemoryAlgorithm> Base;
343 typedef detail::block_header block_header_t;
344 /// @endcond
346 public:
347 typedef MemoryAlgorithm memory_algorithm;
348 typedef typename Base::void_pointer void_pointer;
349 typedef CharType char_type;
351 typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
353 static const std::size_t PayloadPerAllocation = Base::PayloadPerAllocation;
355 /// @cond
356 private:
357 typedef detail::index_config<CharType, MemoryAlgorithm> index_config_named;
358 typedef detail::index_config<char, MemoryAlgorithm> index_config_unique;
359 typedef IndexType<index_config_named> index_type;
360 typedef detail::bool_<is_intrusive_index<index_type>::value > is_intrusive_t;
361 typedef detail::bool_<is_node_index<index_type>::value> is_node_index_t;
363 public:
364 typedef IndexType<index_config_named> named_index_t;
365 typedef IndexType<index_config_unique> unique_index_t;
366 typedef detail::char_ptr_holder<CharType> char_ptr_holder_t;
367 typedef detail::segment_manager_iterator_transform
368 <typename named_index_t::const_iterator
369 ,is_intrusive_index<index_type>::value> named_transform;
371 typedef detail::segment_manager_iterator_transform
372 <typename unique_index_t::const_iterator
373 ,is_intrusive_index<index_type>::value> unique_transform;
374 /// @endcond
376 typedef typename Base::mutex_family mutex_family;
378 typedef transform_iterator
379 <typename named_index_t::const_iterator, named_transform> const_named_iterator;
380 typedef transform_iterator
381 <typename unique_index_t::const_iterator, unique_transform> const_unique_iterator;
383 /// @cond
385 //!Constructor proxy object definition helper class
386 template<class T>
387 struct construct_proxy
389 typedef detail::named_proxy<segment_manager, T, false> type;
392 //!Constructor proxy object definition helper class
393 template<class T>
394 struct construct_iter_proxy
396 typedef detail::named_proxy<segment_manager, T, true> type;
399 /// @endcond
401 //!Constructor of the segment manager
402 //!"size" is the size of the memory segment where
403 //!the segment manager is being constructed.
404 //!Can throw
405 segment_manager(std::size_t size)
406 : Base(size, priv_get_reserved_bytes())
407 , m_header(static_cast<Base*>(get_this_pointer()))
409 (void) anonymous_instance; (void) unique_instance;
410 assert(static_cast<const void*>(this) == static_cast<const void*>(static_cast<Base*>(this)));
413 //!Tries to find a previous named allocation. Returns the address
414 //!and the object count. On failure the first member of the
415 //!returned pair is 0.
416 template <class T>
417 std::pair<T*, std::size_t> find (const CharType* name)
418 { return this->priv_find_impl<T>(name, true); }
420 //!Tries to find a previous unique allocation. Returns the address
421 //!and the object count. On failure the first member of the
422 //!returned pair is 0.
423 template <class T>
424 std::pair<T*, std::size_t> find (const detail::unique_instance_t* name)
425 { return this->priv_find_impl<T>(name, true); }
427 //!Tries to find a previous named allocation. Returns the address
428 //!and the object count. On failure the first member of the
429 //!returned pair is 0. This search is not mutex-protected!
430 template <class T>
431 std::pair<T*, std::size_t> find_no_lock (const CharType* name)
432 { return this->priv_find_impl<T>(name, false); }
434 //!Tries to find a previous 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 template <class T>
438 std::pair<T*, std::size_t> find_no_lock (const detail::unique_instance_t* name)
439 { return this->priv_find_impl<T>(name, false); }
441 //!Returns throwing "construct" proxy
442 //!object
443 template <class T>
444 typename construct_proxy<T>::type
445 construct(char_ptr_holder_t name)
446 { return typename construct_proxy<T>::type (this, name, false, true); }
448 //!Returns throwing "search or construct" proxy
449 //!object
450 template <class T>
451 typename construct_proxy<T>::type find_or_construct(char_ptr_holder_t name)
452 { return typename construct_proxy<T>::type (this, name, true, true); }
454 //!Returns no throwing "construct" proxy
455 //!object
456 template <class T>
457 typename construct_proxy<T>::type
458 construct(char_ptr_holder_t name, std::nothrow_t)
459 { return typename construct_proxy<T>::type (this, name, false, false); }
461 //!Returns no throwing "search or construct"
462 //!proxy object
463 template <class T>
464 typename construct_proxy<T>::type
465 find_or_construct(char_ptr_holder_t name, std::nothrow_t)
466 { return typename construct_proxy<T>::type (this, name, true, false); }
468 //!Returns throwing "construct from iterators" proxy object
469 template <class T>
470 typename construct_iter_proxy<T>::type
471 construct_it(char_ptr_holder_t name)
472 { return typename construct_iter_proxy<T>::type (this, name, false, true); }
474 //!Returns throwing "search or construct from iterators"
475 //!proxy object
476 template <class T>
477 typename construct_iter_proxy<T>::type
478 find_or_construct_it(char_ptr_holder_t name)
479 { return typename construct_iter_proxy<T>::type (this, name, true, true); }
481 //!Returns no throwing "construct from iterators"
482 //!proxy object
483 template <class T>
484 typename construct_iter_proxy<T>::type
485 construct_it(char_ptr_holder_t name, std::nothrow_t)
486 { return typename construct_iter_proxy<T>::type (this, name, false, false); }
488 //!Returns no throwing "search or construct from iterators"
489 //!proxy object
490 template <class T>
491 typename construct_iter_proxy<T>::type
492 find_or_construct_it(char_ptr_holder_t name, std::nothrow_t)
493 { return typename construct_iter_proxy<T>::type (this, name, true, false); }
495 //!Calls object function blocking recursive interprocess_mutex and guarantees that
496 //!no new named_alloc or destroy will be executed by any process while
497 //!executing the object function call*/
498 template <class Func>
499 void atomic_func(Func &f)
500 { scoped_lock<rmutex> guard(m_header); f(); }
502 //!Destroys a previously created unique instance.
503 //!Returns false if the object was not present.
504 template <class T>
505 bool destroy(const detail::unique_instance_t *)
507 detail::placement_destroy<T> dtor;
508 return this->priv_generic_named_destroy<char>
509 (typeid(T).name(), m_header.m_unique_index, dtor, is_intrusive_t());
512 //!Destroys the named object with
513 //!the given name. Returns false if that object can't be found.
514 template <class T>
515 bool destroy(const CharType *name)
517 detail::placement_destroy<T> dtor;
518 return this->priv_generic_named_destroy<CharType>
519 (name, m_header.m_named_index, dtor, is_intrusive_t());
522 //!Destroys an anonymous, unique or named object
523 //!using it's address
524 template <class T>
525 void destroy_ptr(const T *p)
527 //If T is void transform it to char
528 typedef typename detail::char_if_void<T>::type data_t;
529 detail::placement_destroy<data_t> dtor;
530 priv_destroy_ptr(p, dtor);
533 //!Returns the name of an object created with construct/find_or_construct
534 //!functions. Does not throw
535 template<class T>
536 static const CharType *get_instance_name(const T *ptr)
537 { return priv_get_instance_name(block_header_t::block_header_from_value(ptr)); }
539 //!Returns the length of an object created with construct/find_or_construct
540 //!functions. Does not throw.
541 template<class T>
542 static std::size_t get_instance_length(const T *ptr)
543 { return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T)); }
545 //!Returns is the the name of an object created with construct/find_or_construct
546 //!functions. Does not throw
547 template<class T>
548 static instance_type get_instance_type(const T *ptr)
549 { return priv_get_instance_type(block_header_t::block_header_from_value(ptr)); }
551 //!Preallocates needed index resources to optimize the
552 //!creation of "num" named objects in the managed memory segment.
553 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
554 void reserve_named_objects(std::size_t num)
556 //-------------------------------
557 scoped_lock<rmutex> guard(m_header);
558 //-------------------------------
559 m_header.m_named_index.reserve(num);
562 //!Preallocates needed index resources to optimize the
563 //!creation of "num" unique objects in the managed memory segment.
564 //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
565 void reserve_unique_objects(std::size_t num)
567 //-------------------------------
568 scoped_lock<rmutex> guard(m_header);
569 //-------------------------------
570 m_header.m_unique_index.reserve(num);
573 //!Calls shrink_to_fit in both named and unique object indexes
574 //!to try to free unused memory from those indexes.
575 void shrink_to_fit_indexes()
577 //-------------------------------
578 scoped_lock<rmutex> guard(m_header);
579 //-------------------------------
580 m_header.m_named_index.shrink_to_fit();
581 m_header.m_unique_index.shrink_to_fit();
584 //!Returns the number of named objects stored in
585 //!the segment.
586 std::size_t get_num_named_objects()
588 //-------------------------------
589 scoped_lock<rmutex> guard(m_header);
590 //-------------------------------
591 return m_header.m_named_index.size();
594 //!Returns the number of unique objects stored in
595 //!the segment.
596 std::size_t get_num_unique_objects()
598 //-------------------------------
599 scoped_lock<rmutex> guard(m_header);
600 //-------------------------------
601 return m_header.m_unique_index.size();
604 //!Obtains the minimum size needed by the
605 //!segment manager
606 static std::size_t get_min_size()
607 { return Base::get_min_size(priv_get_reserved_bytes()); }
609 //!Returns a constant iterator to the beginning of the information about
610 //!the named allocations performed in this segment manager
611 const_named_iterator named_begin() const
613 return make_transform_iterator
614 (m_header.m_named_index.begin(), named_transform());
617 //!Returns a constant iterator to the end of the information about
618 //!the named allocations performed in this segment manager
619 const_named_iterator named_end() const
621 return make_transform_iterator
622 (m_header.m_named_index.end(), named_transform());
625 //!Returns a constant iterator to the beginning of the information about
626 //!the unique allocations performed in this segment manager
627 const_unique_iterator unique_begin() const
629 return make_transform_iterator
630 (m_header.m_unique_index.begin(), unique_transform());
633 //!Returns a constant iterator to the end of the information about
634 //!the unique allocations performed in this segment manager
635 const_unique_iterator unique_end() const
637 return make_transform_iterator
638 (m_header.m_unique_index.end(), unique_transform());
641 //!This is the default allocator to allocate types T
642 //!from this managed segment
643 template<class T>
644 struct allocator
646 typedef boost::interprocess::allocator<T, segment_manager> type;
649 //!Returns an instance of the default allocator for type T
650 //!initialized that allocates memory from this segment manager.
651 template<class T>
652 typename allocator<T>::type
653 get_allocator()
654 { return typename allocator<T>::type(this); }
656 //!This is the default deleter to delete types T
657 //!from this managed segment.
658 template<class T>
659 struct deleter
661 typedef boost::interprocess::deleter<T, segment_manager> type;
664 //!Returns an instance of the default allocator for type T
665 //!initialized that allocates memory from this segment manager.
666 template<class T>
667 typename deleter<T>::type
668 get_deleter()
669 { return typename deleter<T>::type(this); }
671 /// @cond
673 //!Generic named/anonymous new function. Offers all the possibilities,
674 //!such as throwing, search before creating, and the constructor is
675 //!encapsulated in an object function.
676 template<class T>
677 T *generic_construct(const CharType *name,
678 std::size_t num,
679 bool try2find,
680 bool dothrow,
681 detail::in_place_interface &table)
683 return static_cast<T*>
684 (priv_generic_construct(name, num, try2find, dothrow, table));
687 private:
688 //!Tries to find a previous named allocation. Returns the address
689 //!and the object count. On failure the first member of the
690 //!returned pair is 0.
691 template <class T>
692 std::pair<T*, std::size_t> priv_find_impl (const CharType* name, bool lock)
694 //The name can't be null, no anonymous object can be found by name
695 assert(name != 0);
696 detail::placement_destroy<T> table;
697 std::size_t size;
698 void *ret;
700 if(name == reinterpret_cast<const CharType*>(-1)){
701 ret = priv_generic_find<char> (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), lock);
703 else{
704 ret = priv_generic_find<CharType> (name, m_header.m_named_index, table, size, is_intrusive_t(), lock);
706 return std::pair<T*, std::size_t>(static_cast<T*>(ret), size);
709 //!Tries to find a previous unique allocation. Returns the address
710 //!and the object count. On failure the first member of the
711 //!returned pair is 0.
712 template <class T>
713 std::pair<T*, std::size_t> priv_find__impl (const detail::unique_instance_t* name, bool lock)
715 detail::placement_destroy<T> table;
716 std::size_t size;
717 void *ret = priv_generic_find<char>(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock);
718 return std::pair<T*, std::size_t>(static_cast<T*>(ret), size);
721 void *priv_generic_construct(const CharType *name,
722 std::size_t num,
723 bool try2find,
724 bool dothrow,
725 detail::in_place_interface &table)
727 void *ret;
728 //Security overflow check
729 if(num > ((std::size_t)-1)/table.size){
730 if(dothrow)
731 throw bad_alloc();
732 else
733 return 0;
735 if(name == 0){
736 ret = this->prot_anonymous_construct(num, dothrow, table);
738 else if(name == reinterpret_cast<const CharType*>(-1)){
739 ret = this->priv_generic_named_construct<char>
740 (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t());
742 else{
743 ret = this->priv_generic_named_construct<CharType>
744 (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t());
746 return ret;
749 void priv_destroy_ptr(const void *ptr, detail::in_place_interface &dtor)
751 block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment);
752 switch(ctrl_data->alloc_type()){
753 case anonymous_type:
754 this->prot_anonymous_destroy(ptr, dtor);
755 break;
757 case named_type:
758 this->priv_generic_named_destroy<CharType>
759 (ctrl_data, m_header.m_named_index, dtor, is_node_index_t());
760 break;
762 case unique_type:
763 this->priv_generic_named_destroy<char>
764 (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t());
765 break;
767 default:
768 //This type is unknown, bad pointer passed to this function!
769 assert(0);
770 break;
774 //!Returns the name of an object created with construct/find_or_construct
775 //!functions. Does not throw
776 static const CharType *priv_get_instance_name(block_header_t *ctrl_data)
778 boost::interprocess::allocation_type type = ctrl_data->alloc_type();
779 if(type != named_type){
780 assert((type == anonymous_type && ctrl_data->m_num_char == 0) ||
781 (type == unique_type && ctrl_data->m_num_char != 0) );
782 return 0;
784 CharType *name = static_cast<CharType*>(ctrl_data->template name<CharType>());
786 //Sanity checks
787 assert(ctrl_data->sizeof_char() == sizeof(CharType));
788 assert(ctrl_data->m_num_char == std::char_traits<CharType>::length(name));
789 return name;
792 static std::size_t priv_get_instance_length(block_header_t *ctrl_data, std::size_t sizeofvalue)
794 //Get header
795 assert((ctrl_data->value_bytes() %sizeofvalue) == 0);
796 return ctrl_data->value_bytes()/sizeofvalue;
799 //!Returns is the the name of an object created with construct/find_or_construct
800 //!functions. Does not throw
801 static instance_type priv_get_instance_type(block_header_t *ctrl_data)
803 //Get header
804 assert((instance_type)ctrl_data->alloc_type() < max_allocation_type);
805 return (instance_type)ctrl_data->alloc_type();
808 static std::size_t priv_get_reserved_bytes()
810 //Get the number of bytes until the end of (*this)
811 //beginning in the end of the Base base.
812 return sizeof(segment_manager) - sizeof(Base);
815 template <class CharT>
816 void *priv_generic_find
817 (const CharT* name,
818 IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
819 detail::in_place_interface &table,
820 std::size_t &length,
821 detail::true_ is_intrusive,
822 bool use_lock)
824 (void)is_intrusive;
825 typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
826 typedef detail::index_key<CharT, void_pointer> index_key_t;
827 typedef typename index_type::iterator index_it;
829 //-------------------------------
830 scoped_lock<rmutex> guard(priv_get_lock(use_lock));
831 //-------------------------------
832 //Find name in index
833 detail::intrusive_compare_key<CharT> key
834 (name, std::char_traits<CharT>::length(name));
835 index_it it = index.find(key);
837 //Initialize return values
838 void *ret_ptr = 0;
839 length = 0;
841 //If found, assign values
842 if(it != index.end()){
843 //Get header
844 block_header_t *ctrl_data = it->get_block_header();
846 //Sanity check
847 assert((ctrl_data->m_value_bytes % table.size) == 0);
848 assert(ctrl_data->sizeof_char() == sizeof(CharT));
849 ret_ptr = ctrl_data->value();
850 length = ctrl_data->m_value_bytes/table.size;
852 return ret_ptr;
855 template <class CharT>
856 void *priv_generic_find
857 (const CharT* name,
858 IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
859 detail::in_place_interface &table,
860 std::size_t &length,
861 detail::false_ is_intrusive,
862 bool use_lock)
864 (void)is_intrusive;
865 typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
866 typedef typename index_type::key_type key_type;
867 typedef typename index_type::iterator index_it;
869 //-------------------------------
870 scoped_lock<rmutex> guard(priv_get_lock(use_lock));
871 //-------------------------------
872 //Find name in index
873 index_it it = index.find(key_type(name, std::char_traits<CharT>::length(name)));
875 //Initialize return values
876 void *ret_ptr = 0;
877 length = 0;
879 //If found, assign values
880 if(it != index.end()){
881 //Get header
882 block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
883 (detail::get_pointer(it->second.m_ptr));
885 //Sanity check
886 assert((ctrl_data->m_value_bytes % table.size) == 0);
887 assert(ctrl_data->sizeof_char() == sizeof(CharT));
888 ret_ptr = ctrl_data->value();
889 length = ctrl_data->m_value_bytes/table.size;
891 return ret_ptr;
894 template <class CharT>
895 bool priv_generic_named_destroy
896 (block_header_t *block_header,
897 IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
898 detail::in_place_interface &table,
899 detail::true_ is_node_index)
901 (void)is_node_index;
902 typedef typename IndexType<detail::index_config<CharT, MemoryAlgorithm> >::iterator index_it;
904 index_it *ihdr = block_header_t::to_first_header<index_it>(block_header);
905 return this->priv_generic_named_destroy_impl<CharT>(*ihdr, index, table);
908 template <class CharT>
909 bool priv_generic_named_destroy
910 (block_header_t *block_header,
911 IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
912 detail::in_place_interface &table,
913 detail::false_ is_node_index)
915 (void)is_node_index;
916 CharT *name = static_cast<CharT*>(block_header->template name<CharT>());
917 return this->priv_generic_named_destroy<CharT>(name, index, table, is_intrusive_t());
920 template <class CharT>
921 bool priv_generic_named_destroy(const CharT *name,
922 IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
923 detail::in_place_interface &table,
924 detail::true_ is_intrusive_index)
926 (void)is_intrusive_index;
927 typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
928 typedef detail::index_key<CharT, void_pointer> index_key_t;
929 typedef typename index_type::iterator index_it;
930 typedef typename index_type::value_type intrusive_value_type;
932 //-------------------------------
933 scoped_lock<rmutex> guard(m_header);
934 //-------------------------------
935 //Find name in index
936 detail::intrusive_compare_key<CharT> key
937 (name, std::char_traits<CharT>::length(name));
938 index_it it = index.find(key);
940 //If not found, return false
941 if(it == index.end()){
942 //This name is not present in the index, wrong pointer or name!
943 //assert(0);
944 return false;
947 block_header_t *ctrl_data = it->get_block_header();
948 intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data);
949 void *memory = iv;
950 void *values = ctrl_data->value();
951 std::size_t num = ctrl_data->m_value_bytes/table.size;
953 //Sanity check
954 assert((ctrl_data->m_value_bytes % table.size) == 0);
955 assert(sizeof(CharT) == ctrl_data->sizeof_char());
957 //Erase node from index
958 index.erase(it);
960 //Destroy the headers
961 ctrl_data->~block_header_t();
962 iv->~intrusive_value_type();
964 //Call destructors and free memory
965 std::size_t destroyed;
966 table.destroy_n(values, num, destroyed);
967 this->deallocate(memory);
968 return true;
971 template <class CharT>
972 bool priv_generic_named_destroy(const CharT *name,
973 IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
974 detail::in_place_interface &table,
975 detail::false_ is_intrusive_index)
977 (void)is_intrusive_index;
978 typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
979 typedef typename index_type::iterator index_it;
980 typedef typename index_type::key_type key_type;
982 //-------------------------------
983 scoped_lock<rmutex> guard(m_header);
984 //-------------------------------
985 //Try to find the name in the index
986 index_it it = index.find(key_type (name,
987 std::char_traits<CharT>::length(name)));
989 //If not found, return false
990 if(it == index.end()){
991 //This name is not present in the index, wrong pointer or name!
992 assert(0);
993 return false;
995 return this->priv_generic_named_destroy_impl<CharT>(it, index, table);
998 template <class CharT>
999 bool priv_generic_named_destroy_impl
1000 (const typename IndexType<detail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
1001 IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
1002 detail::in_place_interface &table)
1004 typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
1005 typedef typename index_type::iterator index_it;
1007 //Get allocation parameters
1008 block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
1009 (detail::get_pointer(it->second.m_ptr));
1010 char *stored_name = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
1011 (void)stored_name;
1013 //Check if the distance between the name pointer and the memory pointer
1014 //is correct (this can detect incorrect type in destruction)
1015 std::size_t num = ctrl_data->m_value_bytes/table.size;
1016 void *values = ctrl_data->value();
1018 //Sanity check
1019 assert((ctrl_data->m_value_bytes % table.size) == 0);
1020 assert(static_cast<void*>(stored_name) == static_cast<void*>(ctrl_data->template name<CharT>()));
1021 assert(sizeof(CharT) == ctrl_data->sizeof_char());
1023 //Erase node from index
1024 index.erase(it);
1026 //Destroy the header
1027 ctrl_data->~block_header_t();
1029 void *memory;
1030 if(is_node_index_t::value){
1031 index_it *ihdr = block_header_t::
1032 to_first_header<index_it>(ctrl_data);
1033 ihdr->~index_it();
1034 memory = ihdr;
1036 else{
1037 memory = ctrl_data;
1040 //Call destructors and free memory
1041 std::size_t destroyed;
1042 table.destroy_n(values, num, destroyed);
1043 this->deallocate(memory);
1044 return true;
1047 template<class CharT>
1048 void * priv_generic_named_construct(std::size_t type,
1049 const CharT *name,
1050 std::size_t num,
1051 bool try2find,
1052 bool dothrow,
1053 detail::in_place_interface &table,
1054 IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
1055 detail::true_ is_intrusive)
1057 (void)is_intrusive;
1058 std::size_t namelen = std::char_traits<CharT>::length(name);
1060 block_header_t block_info ( table.size*num
1061 , table.alignment
1062 , type
1063 , sizeof(CharT)
1064 , namelen);
1066 typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
1067 typedef typename index_type::iterator index_it;
1068 typedef std::pair<index_it, bool> index_ib;
1070 //-------------------------------
1071 scoped_lock<rmutex> guard(m_header);
1072 //-------------------------------
1073 //Insert the node. This can throw.
1074 //First, we want to know if the key is already present before
1075 //we allocate any memory, and if the key is not present, we
1076 //want to allocate all memory in a single buffer that will
1077 //contain the name and the user buffer.
1079 //Since equal_range(key) + insert(hint, value) approach is
1080 //quite inefficient in container implementations
1081 //(they re-test if the position is correct), I've chosen
1082 //to insert the node, do an ugly un-const cast and modify
1083 //the key (which is a smart pointer) to an equivalent one
1084 index_ib insert_ret;
1086 typename index_type::insert_commit_data commit_data;
1087 typedef typename index_type::value_type intrusive_value_type;
1089 BOOST_TRY{
1090 detail::intrusive_compare_key<CharT> key(name, namelen);
1091 insert_ret = index.insert_check(key, commit_data);
1093 //Ignore exceptions
1094 BOOST_CATCH(...){
1095 if(dothrow)
1096 BOOST_RETHROW
1097 return 0;
1099 BOOST_CATCH_END
1101 index_it it = insert_ret.first;
1103 //If found and this is find or construct, return data
1104 //else return null
1105 if(!insert_ret.second){
1106 if(try2find){
1107 return it->get_block_header()->value();
1109 if(dothrow){
1110 throw interprocess_exception(already_exists_error);
1112 else{
1113 return 0;
1117 //Allocates buffer for name + data, this can throw (it hurts)
1118 void *buffer_ptr;
1120 //Check if there is enough memory
1121 if(dothrow){
1122 buffer_ptr = this->allocate
1123 (block_info.total_size_with_header<intrusive_value_type>());
1125 else{
1126 buffer_ptr = this->allocate
1127 (block_info.total_size_with_header<intrusive_value_type>(), std::nothrow_t());
1128 if(!buffer_ptr)
1129 return 0;
1132 //Now construct the intrusive hook plus the header
1133 intrusive_value_type * intrusive_hdr = new(buffer_ptr) intrusive_value_type();
1134 block_header_t * hdr = new(intrusive_hdr->get_block_header())block_header_t(block_info);
1135 void *ptr = 0; //avoid gcc warning
1136 ptr = hdr->value();
1138 //Copy name to memory segment and insert data
1139 CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
1140 std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
1142 BOOST_TRY{
1143 //Now commit the insertion using previous context data
1144 it = index.insert_commit(*intrusive_hdr, commit_data);
1146 //Ignore exceptions
1147 BOOST_CATCH(...){
1148 if(dothrow)
1149 BOOST_RETHROW
1150 return 0;
1152 BOOST_CATCH_END
1154 //Avoid constructions if constructor is trivial
1155 //Build scoped ptr to avoid leaks with constructor exception
1156 detail::mem_algo_deallocator<segment_manager_base_type> mem
1157 (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
1159 //Initialize the node value_eraser to erase inserted node
1160 //if something goes wrong. This will be executed *before*
1161 //the memory allocation as the intrusive value is built in that
1162 //memory
1163 value_eraser<index_type> v_eraser(index, it);
1165 //Construct array, this can throw
1166 detail::array_construct(ptr, num, table);
1168 //Release rollbacks since construction was successful
1169 v_eraser.release();
1170 mem.release();
1171 return ptr;
1174 //!Generic named new function for
1175 //!named functions
1176 template<class CharT>
1177 void * priv_generic_named_construct(std::size_t type,
1178 const CharT *name,
1179 std::size_t num,
1180 bool try2find,
1181 bool dothrow,
1182 detail::in_place_interface &table,
1183 IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
1184 detail::false_ is_intrusive)
1186 (void)is_intrusive;
1187 std::size_t namelen = std::char_traits<CharT>::length(name);
1189 block_header_t block_info ( table.size*num
1190 , table.alignment
1191 , type
1192 , sizeof(CharT)
1193 , namelen);
1195 typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
1196 typedef typename index_type::key_type key_type;
1197 typedef typename index_type::mapped_type mapped_type;
1198 typedef typename index_type::value_type value_type;
1199 typedef typename index_type::iterator index_it;
1200 typedef std::pair<index_it, bool> index_ib;
1202 //-------------------------------
1203 scoped_lock<rmutex> guard(m_header);
1204 //-------------------------------
1205 //Insert the node. This can throw.
1206 //First, we want to know if the key is already present before
1207 //we allocate any memory, and if the key is not present, we
1208 //want to allocate all memory in a single buffer that will
1209 //contain the name and the user buffer.
1211 //Since equal_range(key) + insert(hint, value) approach is
1212 //quite inefficient in container implementations
1213 //(they re-test if the position is correct), I've chosen
1214 //to insert the node, do an ugly un-const cast and modify
1215 //the key (which is a smart pointer) to an equivalent one
1216 index_ib insert_ret;
1217 BOOST_TRY{
1218 insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0)));
1220 //Ignore exceptions
1221 BOOST_CATCH(...){
1222 if(dothrow)
1223 BOOST_RETHROW;
1224 return 0;
1226 BOOST_CATCH_END
1228 index_it it = insert_ret.first;
1230 //If found and this is find or construct, return data
1231 //else return null
1232 if(!insert_ret.second){
1233 if(try2find){
1234 block_header_t *hdr = static_cast<block_header_t*>
1235 (detail::get_pointer(it->second.m_ptr));
1236 return hdr->value();
1238 return 0;
1240 //Initialize the node value_eraser to erase inserted node
1241 //if something goes wrong
1242 value_eraser<index_type> v_eraser(index, it);
1244 //Allocates buffer for name + data, this can throw (it hurts)
1245 void *buffer_ptr;
1246 block_header_t * hdr;
1248 //Allocate and construct the headers
1249 if(is_node_index_t::value){
1250 std::size_t total_size = block_info.total_size_with_header<index_it>();
1251 if(dothrow){
1252 buffer_ptr = this->allocate(total_size);
1254 else{
1255 buffer_ptr = this->allocate(total_size, std::nothrow_t());
1256 if(!buffer_ptr)
1257 return 0;
1259 index_it *idr = new(buffer_ptr) index_it(it);
1260 hdr = block_header_t::from_first_header<index_it>(idr);
1262 else{
1263 if(dothrow){
1264 buffer_ptr = this->allocate(block_info.total_size());
1266 else{
1267 buffer_ptr = this->allocate(block_info.total_size(), std::nothrow_t());
1268 if(!buffer_ptr)
1269 return 0;
1271 hdr = static_cast<block_header_t*>(buffer_ptr);
1274 hdr = new(hdr)block_header_t(block_info);
1275 void *ptr = 0; //avoid gcc warning
1276 ptr = hdr->value();
1278 //Copy name to memory segment and insert data
1279 CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
1280 std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
1282 //Do the ugly cast, please mama, forgive me!
1283 //This new key points to an identical string, so it must have the
1284 //same position than the overwritten key according to the predicate
1285 const_cast<key_type &>(it->first).name(name_ptr);
1286 it->second.m_ptr = hdr;
1288 //Build scoped ptr to avoid leaks with constructor exception
1289 detail::mem_algo_deallocator<segment_manager_base_type> mem
1290 (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
1292 //Construct array, this can throw
1293 detail::array_construct(ptr, num, table);
1295 //All constructors successful, we don't want to release memory
1296 mem.release();
1298 //Release node v_eraser since construction was successful
1299 v_eraser.release();
1300 return ptr;
1303 private:
1304 //!Returns the this pointer
1305 segment_manager *get_this_pointer()
1306 { return this; }
1308 typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex;
1310 scoped_lock<rmutex> priv_get_lock(bool use_lock)
1312 scoped_lock<rmutex> local(m_header, defer_lock);
1313 if(use_lock){
1314 local.lock();
1316 return scoped_lock<rmutex>(boost::interprocess::move(local));
1319 //!This struct includes needed data and derives from
1320 //!rmutex to allow EBO when using null interprocess_mutex
1321 struct header_t
1322 : public rmutex
1324 named_index_t m_named_index;
1325 unique_index_t m_unique_index;
1327 header_t(Base *restricted_segment_mngr)
1328 : m_named_index (restricted_segment_mngr)
1329 , m_unique_index(restricted_segment_mngr)
1331 } m_header;
1333 /// @endcond
1337 }} //namespace boost { namespace interprocess
1339 #include <boost/interprocess/detail/config_end.hpp>
1341 #endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP