node_alloc_holder.hpp 17 KB

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