allocator.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2007-2013. 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/container for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. #ifndef BOOST_CONTAINER_ALLOCATOR_HPP
  11. #define BOOST_CONTAINER_ALLOCATOR_HPP
  12. #ifndef BOOST_CONFIG_HPP
  13. # include <boost/config.hpp>
  14. #endif
  15. #if defined(BOOST_HAS_PRAGMA_ONCE)
  16. # pragma once
  17. #endif
  18. #include <boost/container/detail/config_begin.hpp>
  19. #include <boost/container/detail/workaround.hpp>
  20. #include <boost/container/container_fwd.hpp>
  21. #include <boost/container/detail/version_type.hpp>
  22. #include <boost/container/throw_exception.hpp>
  23. #include <boost/container/detail/dlmalloc.hpp>
  24. #include <boost/container/detail/multiallocation_chain.hpp>
  25. #include <boost/static_assert.hpp>
  26. #include <boost/move/detail/force_ptr.hpp>
  27. #include <cstddef>
  28. #include <cassert>
  29. //!\file
  30. namespace boost {
  31. namespace container {
  32. #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  33. template<unsigned Version, unsigned int AllocationDisableMask>
  34. class allocator<void, Version, AllocationDisableMask>
  35. {
  36. typedef allocator<void, Version, AllocationDisableMask> self_t;
  37. public:
  38. typedef void value_type;
  39. typedef void * pointer;
  40. typedef const void* const_pointer;
  41. typedef int & reference;
  42. typedef const int & const_reference;
  43. typedef std::size_t size_type;
  44. typedef std::ptrdiff_t difference_type;
  45. typedef boost::container::dtl::
  46. version_type<self_t, Version> version;
  47. #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  48. typedef boost::container::dtl::
  49. basic_multiallocation_chain<void*> multiallocation_chain;
  50. #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  51. //!Obtains an allocator that allocates
  52. //!objects of type T2
  53. template<class T2>
  54. struct rebind
  55. {
  56. typedef allocator< T2
  57. #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  58. , Version, AllocationDisableMask
  59. #endif
  60. > other;
  61. };
  62. //!Default constructor
  63. //!Never throws
  64. allocator()
  65. {}
  66. //!Constructor from other allocator.
  67. //!Never throws
  68. allocator(const allocator &)
  69. {}
  70. //!Constructor from related allocator.
  71. //!Never throws
  72. template<class T2>
  73. allocator(const allocator<T2, Version, AllocationDisableMask> &)
  74. {}
  75. };
  76. #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  77. //! This class is an extended STL-compatible that offers advanced allocation mechanism
  78. //!(in-place expansion, shrinking, burst-allocation...)
  79. //!
  80. //! This allocator is a wrapper around a modified DLmalloc.
  81. //! If Version is 1, the allocator is a STL conforming allocator. If Version is 2,
  82. //! the allocator offers advanced expand in place and burst allocation capabilities.
  83. //!
  84. //! AllocationDisableMask works only if Version is 2 and it can be an inclusive OR
  85. //! of allocation types the user wants to disable.
  86. template< class T
  87. , unsigned Version BOOST_CONTAINER_DOCONLY(=2)
  88. , unsigned int AllocationDisableMask BOOST_CONTAINER_DOCONLY(=0)>
  89. class allocator
  90. {
  91. typedef unsigned int allocation_type;
  92. #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  93. private:
  94. //Self type
  95. typedef allocator<T, Version, AllocationDisableMask> self_t;
  96. //Not assignable from related allocator
  97. template<class T2, unsigned int Version2, unsigned int AllocationDisableMask2>
  98. allocator& operator=(const allocator<T2, Version2, AllocationDisableMask2>&);
  99. static const unsigned int ForbiddenMask =
  100. BOOST_CONTAINER_ALLOCATE_NEW | BOOST_CONTAINER_EXPAND_BWD | BOOST_CONTAINER_EXPAND_FWD ;
  101. //The mask can't disable all the allocation types
  102. BOOST_STATIC_ASSERT(( (AllocationDisableMask & ForbiddenMask) != ForbiddenMask ));
  103. //The mask is only valid for version 2 allocators
  104. BOOST_STATIC_ASSERT(( Version != 1 || (AllocationDisableMask == 0) ));
  105. #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  106. public:
  107. typedef T value_type;
  108. typedef T * pointer;
  109. typedef const T * const_pointer;
  110. typedef T & reference;
  111. typedef const T & const_reference;
  112. typedef std::size_t size_type;
  113. typedef std::ptrdiff_t difference_type;
  114. typedef boost::container::dtl::
  115. version_type<self_t, Version> version;
  116. #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  117. typedef boost::container::dtl::
  118. basic_multiallocation_chain<void*> void_multiallocation_chain;
  119. typedef boost::container::dtl::
  120. transform_multiallocation_chain
  121. <void_multiallocation_chain, T> multiallocation_chain;
  122. #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  123. //!Obtains an allocator that allocates
  124. //!objects of type T2
  125. template<class T2>
  126. struct rebind
  127. {
  128. typedef allocator<T2, Version, AllocationDisableMask> other;
  129. };
  130. //!Default constructor
  131. //!Never throws
  132. allocator() BOOST_NOEXCEPT_OR_NOTHROW
  133. {}
  134. //!Constructor from other allocator.
  135. //!Never throws
  136. allocator(const allocator &) BOOST_NOEXCEPT_OR_NOTHROW
  137. {}
  138. //!Constructor from related allocator.
  139. //!Never throws
  140. template<class T2>
  141. allocator(const allocator<T2
  142. #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
  143. , Version, AllocationDisableMask
  144. #endif
  145. > &) BOOST_NOEXCEPT_OR_NOTHROW
  146. {}
  147. //!Allocates memory for an array of count elements.
  148. //!Throws bad_alloc if there is no enough memory
  149. //!If Version is 2, this allocated memory can only be deallocated
  150. //!with deallocate() or (for Version == 2) deallocate_many()
  151. BOOST_CONTAINER_ATTRIBUTE_NODISCARD pointer allocate(size_type count, const void * hint= 0)
  152. {
  153. (void)hint;
  154. if(count > size_type(-1)/(2u*sizeof(T)))
  155. boost::container::throw_bad_alloc();
  156. void *ret = dlmalloc_malloc(count*sizeof(T));
  157. if(!ret)
  158. boost::container::throw_bad_alloc();
  159. return static_cast<pointer>(ret);
  160. }
  161. //!Deallocates previously allocated memory.
  162. //!Never throws
  163. BOOST_CONTAINER_FORCEINLINE void deallocate(pointer ptr, size_type) BOOST_NOEXCEPT_OR_NOTHROW
  164. { dlmalloc_free(ptr); }
  165. //!Returns the maximum number of elements that could be allocated.
  166. //!Never throws
  167. BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW
  168. { return size_type(-1)/(2u*sizeof(T)); }
  169. //!Swaps two allocators, does nothing
  170. //!because this allocator is stateless
  171. BOOST_CONTAINER_FORCEINLINE friend void swap(self_t &, self_t &) BOOST_NOEXCEPT_OR_NOTHROW
  172. {}
  173. //!An allocator always compares to true, as memory allocated with one
  174. //!instance can be deallocated by another instance
  175. BOOST_CONTAINER_ATTRIBUTE_NODISCARD
  176. friend bool operator==(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW
  177. { return true; }
  178. //!An allocator always compares to false, as memory allocated with one
  179. //!instance can be deallocated by another instance
  180. BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
  181. friend bool operator!=(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW
  182. { return false; }
  183. //!An advanced function that offers in-place expansion shrink to fit and new allocation
  184. //!capabilities. Memory allocated with this function can only be deallocated with deallocate()
  185. //!or deallocate_many().
  186. //!This function is available only with Version == 2
  187. BOOST_CONTAINER_ATTRIBUTE_NODISCARD pointer allocation_command(allocation_type command,
  188. size_type limit_size,
  189. size_type &prefer_in_recvd_out_size,
  190. pointer &reuse)
  191. {
  192. BOOST_STATIC_ASSERT(( Version > 1 ));
  193. const allocation_type mask(AllocationDisableMask);
  194. command &= ~mask;
  195. pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse);
  196. if(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION))
  197. boost::container::throw_bad_alloc();
  198. return ret;
  199. }
  200. //!Returns maximum the number of objects the previously allocated memory
  201. //!pointed by p can hold.
  202. //!Memory must not have been allocated with
  203. //!allocate_one or allocate_individual.
  204. //!This function is available only with Version == 2
  205. BOOST_CONTAINER_ATTRIBUTE_NODISCARD size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW
  206. {
  207. BOOST_STATIC_ASSERT(( Version > 1 ));
  208. return dlmalloc_size(p);
  209. }
  210. //!Allocates just one object. Memory allocated with this function
  211. //!must be deallocated only with deallocate_one().
  212. //!Throws bad_alloc if there is no enough memory
  213. //!This function is available only with Version == 2
  214. BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE pointer allocate_one()
  215. {
  216. BOOST_STATIC_ASSERT(( Version > 1 ));
  217. return this->allocate(1);
  218. }
  219. //!Allocates many elements of size == 1.
  220. //!Elements must be individually deallocated with deallocate_one()
  221. //!This function is available only with Version == 2
  222. BOOST_CONTAINER_FORCEINLINE void allocate_individual(std::size_t num_elements, multiallocation_chain &chain)
  223. {
  224. BOOST_STATIC_ASSERT(( Version > 1 ));
  225. this->allocate_many(1, num_elements, chain);
  226. }
  227. //!Deallocates memory previously allocated with allocate_one().
  228. //!You should never use deallocate_one to deallocate memory allocated
  229. //!with other functions different from allocate_one() or allocate_individual.
  230. //Never throws
  231. void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW
  232. {
  233. BOOST_STATIC_ASSERT(( Version > 1 ));
  234. return this->deallocate(p, 1);
  235. }
  236. //!Deallocates memory allocated with allocate_one() or allocate_individual().
  237. //!This function is available only with Version == 2
  238. BOOST_CONTAINER_FORCEINLINE
  239. void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW
  240. {
  241. BOOST_STATIC_ASSERT(( Version > 1 ));
  242. return this->deallocate_many(chain);
  243. }
  244. //!Allocates many elements of size elem_size.
  245. //!Elements must be individually deallocated with deallocate()
  246. //!This function is available only with Version == 2
  247. void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain)
  248. {
  249. BOOST_STATIC_ASSERT(( Version > 1 ));
  250. dlmalloc_memchain ch;
  251. BOOST_CONTAINER_MEMCHAIN_INIT(&ch);
  252. if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){
  253. boost::container::throw_bad_alloc();
  254. }
  255. chain.incorporate_after(chain.before_begin()
  256. ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch)
  257. ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
  258. ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );
  259. /*
  260. if(!dlmalloc_multialloc_nodes( n_elements, elem_size*sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS
  261. , move_detail::force_ptr<dlmalloc_memchain *>(&chain))){
  262. boost::container::throw_bad_alloc();
  263. }*/
  264. }
  265. //!Allocates n_elements elements, each one of size elem_sizes[i]
  266. //!Elements must be individually deallocated with deallocate()
  267. //!This function is available only with Version == 2
  268. void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
  269. {
  270. BOOST_STATIC_ASSERT(( Version > 1 ));
  271. dlmalloc_memchain ch;
  272. BOOST_CONTAINER_MEMCHAIN_INIT(&ch);
  273. if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){
  274. boost::container::throw_bad_alloc();
  275. }
  276. chain.incorporate_after(chain.before_begin()
  277. ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch)
  278. ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
  279. ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );
  280. /*
  281. if(!dlmalloc_multialloc_arrays( n_elements, elem_sizes, sizeof(T), BOOST_CONTAINER_DL_MULTIALLOC_DEFAULT_CONTIGUOUS
  282. , move_detail::force_ptr<dlmalloc_memchain *>(&chain))){
  283. boost::container::throw_bad_alloc();
  284. }*/
  285. }
  286. //!Deallocates several elements allocated by
  287. //!allocate_many(), allocate(), or allocation_command().
  288. //!This function is available only with Version == 2
  289. void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW
  290. {
  291. BOOST_STATIC_ASSERT(( Version > 1 ));
  292. dlmalloc_memchain ch;
  293. void *beg(&*chain.begin()), *last(&*chain.last());
  294. size_t size(chain.size());
  295. BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, beg, last, size);
  296. dlmalloc_multidealloc(&ch);
  297. //dlmalloc_multidealloc(move_detail::force_ptr<dlmalloc_memchain *>(&chain));
  298. }
  299. private:
  300. pointer priv_allocation_command
  301. (allocation_type command, std::size_t limit_size
  302. ,size_type &prefer_in_recvd_out_size
  303. ,pointer &reuse_ptr)
  304. {
  305. std::size_t const preferred_size = prefer_in_recvd_out_size;
  306. dlmalloc_command_ret_t ret = {0 , 0};
  307. if((limit_size > this->max_size()) || (preferred_size > this->max_size())){
  308. return pointer();
  309. }
  310. std::size_t l_size = limit_size*sizeof(T);
  311. std::size_t p_size = preferred_size*sizeof(T);
  312. std::size_t r_size;
  313. {
  314. void* reuse_ptr_void = reuse_ptr;
  315. ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void);
  316. reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0;
  317. }
  318. prefer_in_recvd_out_size = r_size/sizeof(T);
  319. return (pointer)ret.first;
  320. }
  321. };
  322. } //namespace container {
  323. } //namespace boost {
  324. #include <boost/container/detail/config_end.hpp>
  325. #endif //BOOST_CONTAINER_ALLOCATOR_HPP