node_alloc_holder.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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/container for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. #ifndef BOOST_CONTAINER_DETAIL_NODE_ALLOC_HPP_
  11. #define BOOST_CONTAINER_DETAIL_NODE_ALLOC_HPP_
  12. #if defined(_MSC_VER)
  13. # pragma once
  14. #endif
  15. #include "config_begin.hpp"
  16. #include <boost/container/detail/workaround.hpp>
  17. #include <utility>
  18. #include <functional>
  19. #include <boost/move/utility.hpp>
  20. #include <boost/intrusive/options.hpp>
  21. #include <boost/container/detail/version_type.hpp>
  22. #include <boost/container/detail/type_traits.hpp>
  23. #include <boost/container/detail/utilities.hpp>
  24. #include <boost/container/allocator_traits.hpp>
  25. #include <boost/container/detail/allocator_version_traits.hpp>
  26. #include <boost/container/detail/mpl.hpp>
  27. #include <boost/container/detail/destroyers.hpp>
  28. #include <boost/container/detail/allocator_version_traits.hpp>
  29. #include <boost/detail/no_exceptions_support.hpp>
  30. #ifndef BOOST_CONTAINER_PERFECT_FORWARDING
  31. #include <boost/container/detail/preprocessor.hpp>
  32. #endif
  33. #include <boost/container/detail/algorithms.hpp>
  34. #include <new>
  35. namespace boost {
  36. namespace container {
  37. namespace container_detail {
  38. template<class ValueCompare, class Node>
  39. struct node_compare
  40. : private ValueCompare
  41. {
  42. typedef typename ValueCompare::key_type key_type;
  43. typedef typename ValueCompare::value_type value_type;
  44. typedef typename ValueCompare::key_of_value key_of_value;
  45. explicit node_compare(const ValueCompare &pred)
  46. : ValueCompare(pred)
  47. {}
  48. node_compare()
  49. : ValueCompare()
  50. {}
  51. ValueCompare &value_comp()
  52. { return static_cast<ValueCompare &>(*this); }
  53. ValueCompare &value_comp() const
  54. { return static_cast<const ValueCompare &>(*this); }
  55. bool operator()(const Node &a, const Node &b) const
  56. { return ValueCompare::operator()(a.get_data(), b.get_data()); }
  57. };
  58. template<class A, class ICont, class ValPred = container_detail::nat>
  59. struct node_alloc_holder
  60. {
  61. typedef allocator_traits<A> allocator_traits_type;
  62. typedef typename allocator_traits_type::value_type value_type;
  63. typedef typename ICont::value_type Node;
  64. typedef typename allocator_traits_type::template
  65. portable_rebind_alloc<Node>::type NodeAlloc;
  66. typedef allocator_traits<NodeAlloc> node_allocator_traits_type;
  67. typedef container_detail::allocator_version_traits<NodeAlloc> node_allocator_version_traits_type;
  68. typedef A ValAlloc;
  69. typedef typename node_allocator_traits_type::pointer NodePtr;
  70. typedef container_detail::scoped_deallocator<NodeAlloc> Deallocator;
  71. typedef typename node_allocator_traits_type::size_type size_type;
  72. typedef typename node_allocator_traits_type::difference_type difference_type;
  73. typedef container_detail::integral_constant<unsigned, 1> allocator_v1;
  74. typedef container_detail::integral_constant<unsigned, 2> allocator_v2;
  75. typedef container_detail::integral_constant<unsigned,
  76. boost::container::container_detail::
  77. version<NodeAlloc>::value> alloc_version;
  78. typedef typename ICont::iterator icont_iterator;
  79. typedef typename ICont::const_iterator icont_citerator;
  80. typedef allocator_destroyer<NodeAlloc> Destroyer;
  81. typedef allocator_traits<NodeAlloc> NodeAllocTraits;
  82. typedef allocator_version_traits<NodeAlloc> AllocVersionTraits;
  83. private:
  84. BOOST_COPYABLE_AND_MOVABLE(node_alloc_holder)
  85. public:
  86. //Constructors for sequence containers
  87. node_alloc_holder()
  88. : members_()
  89. {}
  90. explicit node_alloc_holder(const ValAlloc &a)
  91. : members_(a)
  92. {}
  93. explicit node_alloc_holder(const node_alloc_holder &x)
  94. : members_(NodeAllocTraits::select_on_container_copy_construction(x.node_alloc()))
  95. {}
  96. explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x)
  97. : members_(boost::move(x.node_alloc()))
  98. { this->icont().swap(x.icont()); }
  99. //Constructors for associative containers
  100. explicit node_alloc_holder(const ValAlloc &a, const ValPred &c)
  101. : members_(a, c)
  102. {}
  103. explicit node_alloc_holder(const node_alloc_holder &x, const ValPred &c)
  104. : members_(NodeAllocTraits::select_on_container_copy_construction(x.node_alloc()), c)
  105. {}
  106. explicit node_alloc_holder(const ValPred &c)
  107. : members_(c)
  108. {}
  109. //helpers for move assignments
  110. explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x, const ValPred &c)
  111. : members_(boost::move(x.node_alloc()), c)
  112. { this->icont().swap(x.icont()); }
  113. void copy_assign_alloc(const node_alloc_holder &x)
  114. {
  115. container_detail::bool_<allocator_traits_type::propagate_on_container_copy_assignment::value> flag;
  116. container_detail::assign_alloc( static_cast<NodeAlloc &>(this->members_)
  117. , static_cast<const NodeAlloc &>(x.members_), flag);
  118. }
  119. void move_assign_alloc( node_alloc_holder &x)
  120. {
  121. container_detail::bool_<allocator_traits_type::propagate_on_container_move_assignment::value> flag;
  122. container_detail::move_alloc( static_cast<NodeAlloc &>(this->members_)
  123. , static_cast<NodeAlloc &>(x.members_), flag);
  124. }
  125. ~node_alloc_holder()
  126. { this->clear(alloc_version()); }
  127. size_type max_size() const
  128. { return allocator_traits_type::max_size(this->node_alloc()); }
  129. NodePtr allocate_one()
  130. { return AllocVersionTraits::allocate_one(this->node_alloc()); }
  131. void deallocate_one(const NodePtr &p)
  132. { AllocVersionTraits::deallocate_one(this->node_alloc(), p); }
  133. #ifdef BOOST_CONTAINER_PERFECT_FORWARDING
  134. template<class ...Args>
  135. NodePtr create_node(Args &&...args)
  136. {
  137. NodePtr p = this->allocate_one();
  138. Deallocator node_deallocator(p, this->node_alloc());
  139. allocator_traits<NodeAlloc>::construct
  140. ( this->node_alloc()
  141. , container_detail::addressof(p->m_data), boost::forward<Args>(args)...);
  142. node_deallocator.release();
  143. //This does not throw
  144. typedef typename Node::hook_type hook_type;
  145. ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p))) hook_type;
  146. return (p);
  147. }
  148. #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING
  149. #define BOOST_PP_LOCAL_MACRO(n) \
  150. \
  151. BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \
  152. NodePtr create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \
  153. { \
  154. NodePtr p = this->allocate_one(); \
  155. Deallocator node_deallocator(p, this->node_alloc()); \
  156. allocator_traits<NodeAlloc>::construct \
  157. (this->node_alloc(), container_detail::addressof(p->m_data) \
  158. BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \
  159. node_deallocator.release(); \
  160. typedef typename Node::hook_type hook_type; \
  161. ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p))) hook_type; \
  162. return (p); \
  163. } \
  164. //!
  165. #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS)
  166. #include BOOST_PP_LOCAL_ITERATE()
  167. #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING
  168. template<class It>
  169. NodePtr create_node_from_it(const It &it)
  170. {
  171. NodePtr p = this->allocate_one();
  172. Deallocator node_deallocator(p, this->node_alloc());
  173. ::boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->m_data), it);
  174. node_deallocator.release();
  175. //This does not throw
  176. typedef typename Node::hook_type hook_type;
  177. ::new(static_cast<hook_type*>(container_detail::to_raw_pointer(p))) hook_type;
  178. return (p);
  179. }
  180. void destroy_node(const NodePtr &nodep)
  181. {
  182. allocator_traits<NodeAlloc>::destroy(this->node_alloc(), container_detail::to_raw_pointer(nodep));
  183. this->deallocate_one(nodep);
  184. }
  185. void swap(node_alloc_holder &x)
  186. {
  187. this->icont().swap(x.icont());
  188. container_detail::bool_<allocator_traits_type::propagate_on_container_swap::value> flag;
  189. container_detail::swap_alloc(this->node_alloc(), x.node_alloc(), flag);
  190. }
  191. template<class FwdIterator, class Inserter>
  192. void allocate_many_and_construct
  193. (FwdIterator beg, difference_type n, Inserter inserter)
  194. {
  195. if(n){
  196. typedef typename node_allocator_version_traits_type::multiallocation_chain multiallocation_chain;
  197. //Try to allocate memory in a single block
  198. typedef typename multiallocation_chain::iterator multialloc_iterator;
  199. multiallocation_chain mem;
  200. NodeAlloc &nalloc = this->node_alloc();
  201. node_allocator_version_traits_type::allocate_individual(nalloc, n, mem);
  202. multialloc_iterator itbeg(mem.begin()), itlast(mem.last());
  203. mem.clear();
  204. Node *p = 0;
  205. BOOST_TRY{
  206. Deallocator node_deallocator(NodePtr(), nalloc);
  207. container_detail::scoped_destructor<NodeAlloc> sdestructor(nalloc, 0);
  208. while(n--){
  209. p = container_detail::to_raw_pointer(&*itbeg);
  210. node_deallocator.set(p);
  211. ++itbeg;
  212. //This can throw
  213. boost::container::construct_in_place(nalloc, container_detail::addressof(p->m_data), beg);
  214. sdestructor.set(p);
  215. ++beg;
  216. //This does not throw
  217. typedef typename Node::hook_type hook_type;
  218. ::new(static_cast<hook_type*>(p)) hook_type;
  219. //This can throw in some containers (predicate might throw).
  220. //(sdestructor will destruct the node and node_deallocator will deallocate it in case of exception)
  221. inserter(*p);
  222. sdestructor.set(0);
  223. }
  224. sdestructor.release();
  225. node_deallocator.release();
  226. }
  227. BOOST_CATCH(...){
  228. mem.incorporate_after(mem.last(), &*itbeg, &*itlast, n);
  229. node_allocator_version_traits_type::deallocate_individual(this->node_alloc(), mem);
  230. BOOST_RETHROW
  231. }
  232. BOOST_CATCH_END
  233. }
  234. }
  235. void clear(allocator_v1)
  236. { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); }
  237. void clear(allocator_v2)
  238. {
  239. typename NodeAlloc::multiallocation_chain chain;
  240. allocator_destroyer_and_chain_builder<NodeAlloc> builder(this->node_alloc(), chain);
  241. this->icont().clear_and_dispose(builder);
  242. //BOOST_STATIC_ASSERT((::boost::has_move_emulation_enabled<typename NodeAlloc::multiallocation_chain>::value == true));
  243. if(!chain.empty())
  244. this->node_alloc().deallocate_individual(chain);
  245. }
  246. icont_iterator erase_range(const icont_iterator &first, const icont_iterator &last, allocator_v1)
  247. { return this->icont().erase_and_dispose(first, last, Destroyer(this->node_alloc())); }
  248. icont_iterator erase_range(const icont_iterator &first, const icont_iterator &last, allocator_v2)
  249. {
  250. typedef typename NodeAlloc::multiallocation_chain multiallocation_chain;
  251. NodeAlloc & nalloc = this->node_alloc();
  252. multiallocation_chain chain;
  253. allocator_destroyer_and_chain_builder<NodeAlloc> chain_builder(nalloc, chain);
  254. icont_iterator ret_it = this->icont().erase_and_dispose(first, last, chain_builder);
  255. nalloc.deallocate_individual(chain);
  256. return ret_it;
  257. }
  258. template<class Key, class Comparator>
  259. size_type erase_key(const Key& k, const Comparator &comp, allocator_v1)
  260. { return this->icont().erase_and_dispose(k, comp, Destroyer(this->node_alloc())); }
  261. template<class Key, class Comparator>
  262. size_type erase_key(const Key& k, const Comparator &comp, allocator_v2)
  263. {
  264. allocator_multialloc_chain_node_deallocator<NodeAlloc> chain_holder(this->node_alloc());
  265. return this->icont().erase_and_dispose(k, comp, chain_holder.get_chain_builder());
  266. }
  267. protected:
  268. struct cloner
  269. {
  270. cloner(node_alloc_holder &holder)
  271. : m_holder(holder)
  272. {}
  273. NodePtr operator()(const Node &other) const
  274. { return m_holder.create_node(other.get_data()); }
  275. node_alloc_holder &m_holder;
  276. };
  277. struct members_holder
  278. : public NodeAlloc
  279. {
  280. private:
  281. members_holder(const members_holder&);
  282. members_holder & operator=(const members_holder&);
  283. public:
  284. members_holder()
  285. : NodeAlloc(), m_icont()
  286. {}
  287. template<class ConvertibleToAlloc>
  288. explicit members_holder(BOOST_FWD_REF(ConvertibleToAlloc) c2alloc)
  289. : NodeAlloc(boost::forward<ConvertibleToAlloc>(c2alloc))
  290. , m_icont()
  291. {}
  292. template<class ConvertibleToAlloc>
  293. members_holder(BOOST_FWD_REF(ConvertibleToAlloc) c2alloc, const ValPred &c)
  294. : NodeAlloc(boost::forward<ConvertibleToAlloc>(c2alloc))
  295. , m_icont(typename ICont::value_compare(c))
  296. {}
  297. explicit members_holder(const ValPred &c)
  298. : NodeAlloc()
  299. , m_icont(typename ICont::value_compare(c))
  300. {}
  301. //The intrusive container
  302. ICont m_icont;
  303. };
  304. ICont &non_const_icont() const
  305. { return const_cast<ICont&>(this->members_.m_icont); }
  306. ICont &icont()
  307. { return this->members_.m_icont; }
  308. const ICont &icont() const
  309. { return this->members_.m_icont; }
  310. NodeAlloc &node_alloc()
  311. { return static_cast<NodeAlloc &>(this->members_); }
  312. const NodeAlloc &node_alloc() const
  313. { return static_cast<const NodeAlloc &>(this->members_); }
  314. members_holder members_;
  315. };
  316. } //namespace container_detail {
  317. } //namespace container {
  318. } //namespace boost {
  319. #include <boost/container/detail/config_end.hpp>
  320. #endif // BOOST_CONTAINER_DETAIL_NODE_ALLOC_HPP_