allocator.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. #ifndef BOOST_INTERPROCESS_ALLOCATOR_HPP
  11. #define BOOST_INTERPROCESS_ALLOCATOR_HPP
  12. #ifndef BOOST_CONFIG_HPP
  13. # include <boost/config.hpp>
  14. #endif
  15. #
  16. #if defined(BOOST_HAS_PRAGMA_ONCE)
  17. # pragma once
  18. #endif
  19. #include <boost/interprocess/detail/config_begin.hpp>
  20. #include <boost/interprocess/detail/workaround.hpp>
  21. #include <boost/intrusive/pointer_traits.hpp>
  22. #include <boost/interprocess/interprocess_fwd.hpp>
  23. #include <boost/interprocess/containers/allocation_type.hpp>
  24. #include <boost/container/detail/multiallocation_chain.hpp>
  25. #include <boost/interprocess/allocators/detail/allocator_common.hpp>
  26. #include <boost/interprocess/detail/utilities.hpp>
  27. #include <boost/interprocess/containers/version_type.hpp>
  28. #include <boost/interprocess/exceptions.hpp>
  29. #include <boost/assert.hpp>
  30. #include <boost/utility/addressof.hpp>
  31. #include <boost/interprocess/detail/type_traits.hpp>
  32. #include <boost/container/detail/placement_new.hpp>
  33. #include <cstddef>
  34. #include <stdexcept>
  35. //!\file
  36. //!Describes an allocator that allocates portions of fixed size
  37. //!memory buffer (shared memory, mapped file...)
  38. namespace boost {
  39. namespace interprocess {
  40. //!An STL compatible allocator that uses a segment manager as
  41. //!memory source. The internal pointer type will of the same type (raw, smart) as
  42. //!"typename SegmentManager::void_pointer" type. This allows
  43. //!placing the allocator in shared memory, memory mapped-files, etc...
  44. template<class T, class SegmentManager>
  45. class allocator
  46. {
  47. public:
  48. //Segment manager
  49. typedef SegmentManager segment_manager;
  50. typedef typename SegmentManager::void_pointer void_pointer;
  51. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  52. private:
  53. //Self type
  54. typedef allocator<T, SegmentManager> self_t;
  55. //Pointer to void
  56. typedef typename segment_manager::void_pointer aux_pointer_t;
  57. //Typedef to const void pointer
  58. typedef typename boost::intrusive::
  59. pointer_traits<aux_pointer_t>::template
  60. rebind_pointer<const void>::type cvoid_ptr;
  61. //Pointer to the allocator
  62. typedef typename boost::intrusive::
  63. pointer_traits<cvoid_ptr>::template
  64. rebind_pointer<segment_manager>::type alloc_ptr_t;
  65. //Not assignable from related allocator
  66. template<class T2, class SegmentManager2>
  67. allocator& operator=(const allocator<T2, SegmentManager2>&);
  68. //Not assignable from other allocator
  69. allocator& operator=(const allocator&);
  70. //Pointer to the allocator
  71. alloc_ptr_t mp_mngr;
  72. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  73. public:
  74. typedef T value_type;
  75. typedef typename boost::intrusive::
  76. pointer_traits<cvoid_ptr>::template
  77. rebind_pointer<T>::type pointer;
  78. typedef typename boost::intrusive::
  79. pointer_traits<pointer>::template
  80. rebind_pointer<const T>::type const_pointer;
  81. typedef typename ipcdetail::add_reference
  82. <value_type>::type reference;
  83. typedef typename ipcdetail::add_reference
  84. <const value_type>::type const_reference;
  85. typedef typename segment_manager::size_type size_type;
  86. typedef typename segment_manager::difference_type difference_type;
  87. typedef boost::interprocess::version_type<allocator, 2> version;
  88. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  89. //Experimental. Don't use.
  90. typedef boost::container::dtl::transform_multiallocation_chain
  91. <typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
  92. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  93. //!Obtains an allocator that allocates
  94. //!objects of type T2
  95. template<class T2>
  96. struct rebind
  97. {
  98. typedef allocator<T2, SegmentManager> other;
  99. };
  100. //!Returns the segment manager.
  101. //!Never throws
  102. segment_manager* get_segment_manager()const
  103. { return ipcdetail::to_raw_pointer(mp_mngr); }
  104. //!Constructor from the segment manager.
  105. //!Never throws
  106. allocator(segment_manager *segment_mngr)
  107. : mp_mngr(segment_mngr) { }
  108. //!Constructor from other allocator.
  109. //!Never throws
  110. allocator(const allocator &other)
  111. : mp_mngr(other.get_segment_manager()){ }
  112. //!Constructor from related allocator.
  113. //!Never throws
  114. template<class T2>
  115. allocator(const allocator<T2, SegmentManager> &other)
  116. : mp_mngr(other.get_segment_manager()){}
  117. //!Allocates memory for an array of count elements.
  118. //!Throws boost::interprocess::bad_alloc if there is no enough memory
  119. pointer allocate(size_type count, cvoid_ptr hint = 0)
  120. {
  121. (void)hint;
  122. if(size_overflows<sizeof(T)>(count)){
  123. throw bad_alloc();
  124. }
  125. return pointer(static_cast<value_type*>(mp_mngr->allocate(count*sizeof(T))));
  126. }
  127. //!Deallocates memory previously allocated.
  128. //!Never throws
  129. void deallocate(const pointer &ptr, size_type)
  130. { mp_mngr->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); }
  131. //!Returns the number of elements that could be allocated.
  132. //!Never throws
  133. size_type max_size() const
  134. { return mp_mngr->get_size()/sizeof(T); }
  135. //!Swap segment manager. Does not throw. If each allocator is placed in
  136. //!different memory segments, the result is undefined.
  137. friend void swap(self_t &alloc1, self_t &alloc2)
  138. { boost::adl_move_swap(alloc1.mp_mngr, alloc2.mp_mngr); }
  139. //!Returns maximum the number of objects the previously allocated memory
  140. //!pointed by p can hold. This size only works for memory allocated with
  141. //!allocate, allocation_command and allocate_many.
  142. size_type size(const pointer &p) const
  143. {
  144. return (size_type)mp_mngr->size(ipcdetail::to_raw_pointer(p))/sizeof(T);
  145. }
  146. pointer allocation_command(boost::interprocess::allocation_type command,
  147. size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse)
  148. {
  149. value_type *reuse_raw = ipcdetail::to_raw_pointer(reuse);
  150. pointer const p = mp_mngr->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse_raw);
  151. reuse = reuse_raw;
  152. return p;
  153. }
  154. //!Allocates many elements of size elem_size in a contiguous block
  155. //!of memory. The minimum number to be allocated is min_elements,
  156. //!the preferred and maximum number is
  157. //!preferred_elements. The number of actually allocated elements is
  158. //!will be assigned to received_size. The elements must be deallocated
  159. //!with deallocate(...)
  160. void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain)
  161. {
  162. if(size_overflows<sizeof(T)>(elem_size)){
  163. throw bad_alloc();
  164. }
  165. mp_mngr->allocate_many(elem_size*sizeof(T), num_elements, chain);
  166. }
  167. //!Allocates n_elements elements, each one of size elem_sizes[i]in a
  168. //!contiguous block
  169. //!of memory. The elements must be deallocated
  170. void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
  171. {
  172. mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T), chain);
  173. }
  174. //!Allocates many elements of size elem_size in a contiguous block
  175. //!of memory. The minimum number to be allocated is min_elements,
  176. //!the preferred and maximum number is
  177. //!preferred_elements. The number of actually allocated elements is
  178. //!will be assigned to received_size. The elements must be deallocated
  179. //!with deallocate(...)
  180. void deallocate_many(multiallocation_chain &chain)
  181. { mp_mngr->deallocate_many(chain); }
  182. //!Allocates just one object. Memory allocated with this function
  183. //!must be deallocated only with deallocate_one().
  184. //!Throws boost::interprocess::bad_alloc if there is no enough memory
  185. pointer allocate_one()
  186. { return this->allocate(1); }
  187. //!Allocates many elements of size == 1 in a contiguous block
  188. //!of memory. The minimum number to be allocated is min_elements,
  189. //!the preferred and maximum number is
  190. //!preferred_elements. The number of actually allocated elements is
  191. //!will be assigned to received_size. Memory allocated with this function
  192. //!must be deallocated only with deallocate_one().
  193. void allocate_individual(size_type num_elements, multiallocation_chain &chain)
  194. { this->allocate_many(1, num_elements, chain); }
  195. //!Deallocates memory previously allocated with allocate_one().
  196. //!You should never use deallocate_one to deallocate memory allocated
  197. //!with other functions different from allocate_one(). Never throws
  198. void deallocate_one(const pointer &p)
  199. { return this->deallocate(p, 1); }
  200. //!Allocates many elements of size == 1 in a contiguous block
  201. //!of memory. The minimum number to be allocated is min_elements,
  202. //!the preferred and maximum number is
  203. //!preferred_elements. The number of actually allocated elements is
  204. //!will be assigned to received_size. Memory allocated with this function
  205. //!must be deallocated only with deallocate_one().
  206. void deallocate_individual(multiallocation_chain &chain)
  207. { this->deallocate_many(chain); }
  208. //!Returns address of mutable object.
  209. //!Never throws
  210. pointer address(reference value) const
  211. { return pointer(boost::addressof(value)); }
  212. //!Returns address of non mutable object.
  213. //!Never throws
  214. const_pointer address(const_reference value) const
  215. { return const_pointer(boost::addressof(value)); }
  216. //!Constructs an object
  217. //!Throws if T's constructor throws
  218. //!For backwards compatibility with libraries using C++03 allocators
  219. template<class P>
  220. void construct(const pointer &ptr, BOOST_FWD_REF(P) p)
  221. { ::new((void*)ipcdetail::to_raw_pointer(ptr), boost_container_new_t()) value_type(::boost::forward<P>(p)); }
  222. //!Destroys object. Throws if object's
  223. //!destructor throws
  224. void destroy(const pointer &ptr)
  225. { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
  226. };
  227. //!Equality test for same type
  228. //!of allocator
  229. template<class T, class SegmentManager> inline
  230. bool operator==(const allocator<T , SegmentManager> &alloc1,
  231. const allocator<T, SegmentManager> &alloc2)
  232. { return alloc1.get_segment_manager() == alloc2.get_segment_manager(); }
  233. //!Inequality test for same type
  234. //!of allocator
  235. template<class T, class SegmentManager> inline
  236. bool operator!=(const allocator<T, SegmentManager> &alloc1,
  237. const allocator<T, SegmentManager> &alloc2)
  238. { return alloc1.get_segment_manager() != alloc2.get_segment_manager(); }
  239. } //namespace interprocess {
  240. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  241. template<class T>
  242. struct has_trivial_destructor;
  243. template<class T, class SegmentManager>
  244. struct has_trivial_destructor
  245. <boost::interprocess::allocator <T, SegmentManager> >
  246. {
  247. static const bool value = true;
  248. };
  249. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  250. } //namespace boost {
  251. #include <boost/interprocess/detail/config_end.hpp>
  252. #endif //BOOST_INTERPROCESS_ALLOCATOR_HPP