node_alloc_holder.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2005-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_DETAIL_NODE_ALLOC_HPP_
  11. #define BOOST_CONTAINER_DETAIL_NODE_ALLOC_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. // container
  21. #include <boost/container/allocator_traits.hpp>
  22. // container/detail
  23. #include <boost/container/detail/addressof.hpp>
  24. #include <boost/container/detail/alloc_helpers.hpp>
  25. #include <boost/container/detail/allocator_version_traits.hpp>
  26. #include <boost/container/detail/construct_in_place.hpp>
  27. #include <boost/container/detail/destroyers.hpp>
  28. #include <boost/move/detail/iterator_to_raw_pointer.hpp>
  29. #include <boost/container/detail/mpl.hpp>
  30. #include <boost/container/detail/placement_new.hpp>
  31. #include <boost/move/detail/to_raw_pointer.hpp>
  32. #include <boost/container/detail/type_traits.hpp>
  33. #include <boost/container/detail/version_type.hpp>
  34. // intrusive
  35. #include <boost/intrusive/detail/mpl.hpp>
  36. #include <boost/intrusive/options.hpp>
  37. // move
  38. #include <boost/move/utility_core.hpp>
  39. #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  40. #include <boost/move/detail/fwd_macros.hpp>
  41. #endif
  42. // other
  43. #include <boost/core/no_exceptions_support.hpp>
  44. namespace boost {
  45. namespace container {
  46. namespace dtl {
  47. BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(value_compare)
  48. BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(predicate_type)
  49. template<class Allocator, class ICont>
  50. struct node_alloc_holder
  51. {
  52. //If the intrusive container is an associative container, obtain the predicate, which will
  53. //be of type node_compare<>. If not an associative container value_compare will be a "nat" type.
  54. typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT
  55. ( boost::container::dtl::
  56. , ICont, value_compare, dtl::nat) intrusive_value_compare;
  57. //In that case obtain the value predicate from the node predicate via predicate_type
  58. //if intrusive_value_compare is node_compare<>, nat otherwise
  59. typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT
  60. ( boost::container::dtl::
  61. , intrusive_value_compare
  62. , predicate_type, dtl::nat) value_compare;
  63. typedef allocator_traits<Allocator> allocator_traits_type;
  64. typedef typename allocator_traits_type::value_type value_type;
  65. typedef ICont intrusive_container;
  66. typedef typename ICont::value_type Node;
  67. typedef typename allocator_traits_type::template
  68. portable_rebind_alloc<Node>::type NodeAlloc;
  69. typedef allocator_traits<NodeAlloc> node_allocator_traits_type;
  70. typedef dtl::allocator_version_traits<NodeAlloc> node_allocator_version_traits_type;
  71. typedef Allocator ValAlloc;
  72. typedef typename node_allocator_traits_type::pointer NodePtr;
  73. typedef dtl::scoped_deallocator<NodeAlloc> Deallocator;
  74. typedef typename node_allocator_traits_type::size_type size_type;
  75. typedef typename node_allocator_traits_type::difference_type difference_type;
  76. typedef dtl::integral_constant<unsigned,
  77. boost::container::dtl::
  78. version<NodeAlloc>::value> alloc_version;
  79. typedef typename ICont::iterator icont_iterator;
  80. typedef typename ICont::const_iterator icont_citerator;
  81. typedef allocator_destroyer<NodeAlloc> Destroyer;
  82. typedef allocator_traits<NodeAlloc> NodeAllocTraits;
  83. typedef allocator_version_traits<NodeAlloc> AllocVersionTraits;
  84. private:
  85. BOOST_COPYABLE_AND_MOVABLE(node_alloc_holder)
  86. public:
  87. //Constructors for sequence containers
  88. node_alloc_holder()
  89. : members_()
  90. {}
  91. explicit node_alloc_holder(const ValAlloc &a)
  92. : members_(a)
  93. {}
  94. //Constructors for associative containers
  95. node_alloc_holder(const value_compare &c, const ValAlloc &a)
  96. : members_(a, c)
  97. {}
  98. explicit node_alloc_holder(const node_alloc_holder &x)
  99. : members_(NodeAllocTraits::select_on_container_copy_construction(x.node_alloc()))
  100. {}
  101. node_alloc_holder(const node_alloc_holder &x, const value_compare &c)
  102. : members_(NodeAllocTraits::select_on_container_copy_construction(x.node_alloc()), c)
  103. {}
  104. explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x)
  105. : members_(boost::move(x.node_alloc()))
  106. { this->icont().swap(x.icont()); }
  107. explicit node_alloc_holder(const value_compare &c)
  108. : members_(c)
  109. {}
  110. //helpers for move assignments
  111. explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x, const value_compare &c)
  112. : members_(boost::move(x.node_alloc()), c)
  113. { this->icont().swap(x.icont()); }
  114. void copy_assign_alloc(const node_alloc_holder &x)
  115. {
  116. dtl::bool_<allocator_traits_type::propagate_on_container_copy_assignment::value> flag;
  117. dtl::assign_alloc( static_cast<NodeAlloc &>(this->members_)
  118. , static_cast<const NodeAlloc &>(x.members_), flag);
  119. }
  120. void move_assign_alloc( node_alloc_holder &x)
  121. {
  122. dtl::bool_<allocator_traits_type::propagate_on_container_move_assignment::value> flag;
  123. dtl::move_alloc( static_cast<NodeAlloc &>(this->members_)
  124. , static_cast<NodeAlloc &>(x.members_), flag);
  125. }
  126. ~node_alloc_holder()
  127. { this->clear(alloc_version()); }
  128. size_type max_size() const
  129. { return allocator_traits_type::max_size(this->node_alloc()); }
  130. NodePtr allocate_one()
  131. { return AllocVersionTraits::allocate_one(this->node_alloc()); }
  132. void deallocate_one(const NodePtr &p)
  133. { AllocVersionTraits::deallocate_one(this->node_alloc(), p); }
  134. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  135. template<class ...Args>
  136. NodePtr create_node(Args &&...args)
  137. {
  138. NodePtr p = this->allocate_one();
  139. Deallocator node_deallocator(p, this->node_alloc());
  140. allocator_traits<NodeAlloc>::construct
  141. ( this->node_alloc()
  142. , dtl::addressof(p->m_data), boost::forward<Args>(args)...);
  143. node_deallocator.release();
  144. //This does not throw
  145. typedef typename Node::hook_type hook_type;
  146. ::new(static_cast<hook_type*>(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) hook_type;
  147. return (p);
  148. }
  149. #else //defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  150. #define BOOST_CONTAINER_NODE_ALLOC_HOLDER_CONSTRUCT_IMPL(N) \
  151. BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
  152. NodePtr create_node(BOOST_MOVE_UREF##N)\
  153. {\
  154. NodePtr p = this->allocate_one();\
  155. Deallocator node_deallocator(p, this->node_alloc());\
  156. allocator_traits<NodeAlloc>::construct\
  157. ( this->node_alloc()\
  158. , dtl::addressof(p->m_data)\
  159. BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
  160. node_deallocator.release();\
  161. typedef typename Node::hook_type hook_type;\
  162. ::new(static_cast<hook_type*>(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) hook_type;\
  163. return (p);\
  164. }\
  165. //
  166. BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_NODE_ALLOC_HOLDER_CONSTRUCT_IMPL)
  167. #undef BOOST_CONTAINER_NODE_ALLOC_HOLDER_CONSTRUCT_IMPL
  168. #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  169. template<class It>
  170. NodePtr create_node_from_it(const It &it)
  171. {
  172. NodePtr p = this->allocate_one();
  173. Deallocator node_deallocator(p, this->node_alloc());
  174. ::boost::container::construct_in_place(this->node_alloc(), dtl::addressof(p->m_data), it);
  175. node_deallocator.release();
  176. //This does not throw
  177. typedef typename Node::hook_type hook_type;
  178. ::new(static_cast<hook_type*>(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) hook_type;
  179. return (p);
  180. }
  181. template<class KeyConvertible>
  182. NodePtr create_node_from_key(BOOST_FWD_REF(KeyConvertible) key)
  183. {
  184. NodePtr p = this->allocate_one();
  185. NodeAlloc &na = this->node_alloc();
  186. Deallocator node_deallocator(p, this->node_alloc());
  187. node_allocator_traits_type::construct
  188. (na, dtl::addressof(p->m_data.first), boost::forward<KeyConvertible>(key));
  189. BOOST_TRY{
  190. node_allocator_traits_type::construct(na, dtl::addressof(p->m_data.second));
  191. }
  192. BOOST_CATCH(...){
  193. node_allocator_traits_type::destroy(na, dtl::addressof(p->m_data.first));
  194. BOOST_RETHROW;
  195. }
  196. BOOST_CATCH_END
  197. node_deallocator.release();
  198. //This does not throw
  199. typedef typename Node::hook_type hook_type;
  200. ::new(static_cast<hook_type*>(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) hook_type;
  201. return (p);
  202. }
  203. void destroy_node(const NodePtr &nodep)
  204. {
  205. allocator_traits<NodeAlloc>::destroy(this->node_alloc(), boost::movelib::to_raw_pointer(nodep));
  206. this->deallocate_one(nodep);
  207. }
  208. void swap(node_alloc_holder &x)
  209. {
  210. this->icont().swap(x.icont());
  211. dtl::bool_<allocator_traits_type::propagate_on_container_swap::value> flag;
  212. dtl::swap_alloc(this->node_alloc(), x.node_alloc(), flag);
  213. }
  214. template<class FwdIterator, class Inserter>
  215. void allocate_many_and_construct
  216. (FwdIterator beg, difference_type n, Inserter inserter)
  217. {
  218. if(n){
  219. typedef typename node_allocator_version_traits_type::multiallocation_chain multiallocation_chain;
  220. //Try to allocate memory in a single block
  221. typedef typename multiallocation_chain::iterator multialloc_iterator;
  222. multiallocation_chain mem;
  223. NodeAlloc &nalloc = this->node_alloc();
  224. node_allocator_version_traits_type::allocate_individual(nalloc, n, mem);
  225. multialloc_iterator itbeg(mem.begin()), itlast(mem.last());
  226. mem.clear();
  227. Node *p = 0;
  228. BOOST_TRY{
  229. Deallocator node_deallocator(NodePtr(), nalloc);
  230. dtl::scoped_destructor<NodeAlloc> sdestructor(nalloc, 0);
  231. while(n--){
  232. p = boost::movelib::iterator_to_raw_pointer(itbeg);
  233. node_deallocator.set(p);
  234. ++itbeg;
  235. //This can throw
  236. boost::container::construct_in_place(nalloc, dtl::addressof(p->m_data), beg);
  237. sdestructor.set(p);
  238. ++beg;
  239. //This does not throw
  240. typedef typename Node::hook_type hook_type;
  241. ::new(static_cast<hook_type*>(p), boost_container_new_t()) hook_type;
  242. //This can throw in some containers (predicate might throw).
  243. //(sdestructor will destruct the node and node_deallocator will deallocate it in case of exception)
  244. inserter(*p);
  245. sdestructor.set(0);
  246. }
  247. sdestructor.release();
  248. node_deallocator.release();
  249. }
  250. BOOST_CATCH(...){
  251. mem.incorporate_after(mem.last(), &*itbeg, &*itlast, n);
  252. node_allocator_version_traits_type::deallocate_individual(this->node_alloc(), mem);
  253. BOOST_RETHROW
  254. }
  255. BOOST_CATCH_END
  256. }
  257. }
  258. void clear(version_1)
  259. { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); }
  260. void clear(version_2)
  261. {
  262. typename NodeAlloc::multiallocation_chain chain;
  263. allocator_destroyer_and_chain_builder<NodeAlloc> builder(this->node_alloc(), chain);
  264. this->icont().clear_and_dispose(builder);
  265. //BOOST_STATIC_ASSERT((::boost::has_move_emulation_enabled<typename NodeAlloc::multiallocation_chain>::value == true));
  266. if(!chain.empty())
  267. this->node_alloc().deallocate_individual(chain);
  268. }
  269. icont_iterator erase_range(const icont_iterator &first, const icont_iterator &last, version_1)
  270. { return this->icont().erase_and_dispose(first, last, Destroyer(this->node_alloc())); }
  271. icont_iterator erase_range(const icont_iterator &first, const icont_iterator &last, version_2)
  272. {
  273. typedef typename NodeAlloc::multiallocation_chain multiallocation_chain;
  274. NodeAlloc & nalloc = this->node_alloc();
  275. multiallocation_chain chain;
  276. allocator_destroyer_and_chain_builder<NodeAlloc> chain_builder(nalloc, chain);
  277. icont_iterator ret_it = this->icont().erase_and_dispose(first, last, chain_builder);
  278. nalloc.deallocate_individual(chain);
  279. return ret_it;
  280. }
  281. template<class Key, class Comparator>
  282. size_type erase_key(const Key& k, const Comparator &comp, version_1)
  283. { return this->icont().erase_and_dispose(k, comp, Destroyer(this->node_alloc())); }
  284. template<class Key, class Comparator>
  285. size_type erase_key(const Key& k, const Comparator &comp, version_2)
  286. {
  287. allocator_multialloc_chain_node_deallocator<NodeAlloc> chain_holder(this->node_alloc());
  288. return this->icont().erase_and_dispose(k, comp, chain_holder.get_chain_builder());
  289. }
  290. protected:
  291. struct cloner
  292. {
  293. explicit cloner(node_alloc_holder &holder)
  294. : m_holder(holder)
  295. {}
  296. NodePtr operator()(const Node &other) const
  297. { return m_holder.create_node(other.m_data); }
  298. node_alloc_holder &m_holder;
  299. };
  300. struct move_cloner
  301. {
  302. move_cloner(node_alloc_holder &holder)
  303. : m_holder(holder)
  304. {}
  305. NodePtr operator()(Node &other)
  306. { //Use m_data instead of get_data to allow moving const key in [multi]map
  307. return m_holder.create_node(::boost::move(other.m_data));
  308. }
  309. node_alloc_holder &m_holder;
  310. };
  311. struct members_holder
  312. : public NodeAlloc
  313. {
  314. private:
  315. members_holder(const members_holder&);
  316. members_holder & operator=(const members_holder&);
  317. public:
  318. members_holder()
  319. : NodeAlloc(), m_icont()
  320. {}
  321. template<class ConvertibleToAlloc>
  322. explicit members_holder(BOOST_FWD_REF(ConvertibleToAlloc) c2alloc)
  323. : NodeAlloc(boost::forward<ConvertibleToAlloc>(c2alloc))
  324. , m_icont()
  325. {}
  326. template<class ConvertibleToAlloc>
  327. members_holder(BOOST_FWD_REF(ConvertibleToAlloc) c2alloc, const value_compare &c)
  328. : NodeAlloc(boost::forward<ConvertibleToAlloc>(c2alloc))
  329. , m_icont(typename ICont::key_compare(c))
  330. {}
  331. explicit members_holder(const value_compare &c)
  332. : NodeAlloc()
  333. , m_icont(typename ICont::key_compare(c))
  334. {}
  335. //The intrusive container
  336. ICont m_icont;
  337. };
  338. ICont &non_const_icont() const
  339. { return const_cast<ICont&>(this->members_.m_icont); }
  340. NodeAlloc &node_alloc()
  341. { return static_cast<NodeAlloc &>(this->members_); }
  342. const NodeAlloc &node_alloc() const
  343. { return static_cast<const NodeAlloc &>(this->members_); }
  344. members_holder members_;
  345. public:
  346. ICont &icont()
  347. { return this->members_.m_icont; }
  348. const ICont &icont() const
  349. { return this->members_.m_icont; }
  350. };
  351. } //namespace dtl {
  352. } //namespace container {
  353. } //namespace boost {
  354. #include <boost/container/detail/config_end.hpp>
  355. #endif // BOOST_CONTAINER_DETAIL_NODE_ALLOC_HPP_