node_handle.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2016-2016. 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_NODE_HANDLE_HPP
  11. #define BOOST_CONTAINER_NODE_HANDLE_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/static_assert.hpp>
  21. #include <boost/container/detail/placement_new.hpp>
  22. #include <boost/move/detail/to_raw_pointer.hpp>
  23. #include <boost/container/allocator_traits.hpp>
  24. #include <boost/container/detail/mpl.hpp>
  25. #include <boost/move/utility_core.hpp>
  26. #include <boost/move/adl_move_swap.hpp>
  27. #include <boost/container/detail/mpl.hpp>
  28. #include <boost/assert.hpp>
  29. //!\file
  30. namespace boost {
  31. namespace container {
  32. ///@cond
  33. template<class Value, class KeyMapped>
  34. struct node_handle_keymapped_traits
  35. {
  36. typedef typename KeyMapped::key_type key_type;
  37. typedef typename KeyMapped::mapped_type mapped_type;
  38. };
  39. template<class Value>
  40. struct node_handle_keymapped_traits<Value, void>
  41. {
  42. typedef Value key_type;
  43. typedef Value mapped_type;
  44. };
  45. class node_handle_friend
  46. {
  47. public:
  48. template<class NH>
  49. BOOST_CONTAINER_FORCEINLINE static void destroy_alloc(NH &nh) BOOST_NOEXCEPT
  50. { nh.destroy_alloc(); }
  51. template<class NH>
  52. BOOST_CONTAINER_FORCEINLINE static typename NH::node_pointer &get_node_pointer(NH &nh) BOOST_NOEXCEPT
  53. { return nh.get_node_pointer(); }
  54. };
  55. ///@endcond
  56. //! A node_handle is an object that accepts ownership of a single element from an associative container.
  57. //! It may be used to transfer that ownership to another container with compatible nodes. Containers
  58. //! with compatible nodes have the same node handle type. Elements may be transferred in either direction
  59. //! between container types in the same row:.
  60. //!
  61. //! Container types with compatible nodes
  62. //!
  63. //! map<K, T, C1, A> <-> map<K, T, C2, A>
  64. //!
  65. //! map<K, T, C1, A> <-> multimap<K, T, C2, A>
  66. //!
  67. //! set<K, C1, A> <-> set<K, C2, A>
  68. //!
  69. //! set<K, C1, A> <-> multiset<K, C2, A>
  70. //!
  71. //! If a node handle is not empty, then it contains an allocator that is equal to the allocator of the container
  72. //! when the element was extracted. If a node handle is empty, it contains no allocator.
  73. template <class NodeAllocator, class KeyMapped = void>
  74. class node_handle
  75. {
  76. typedef NodeAllocator nallocator_type;
  77. typedef allocator_traits<NodeAllocator> nator_traits;
  78. typedef typename nator_traits::value_type priv_node_t;
  79. typedef typename priv_node_t::value_type priv_value_t;
  80. typedef node_handle_keymapped_traits<priv_value_t, KeyMapped> keymapped_t;
  81. public:
  82. typedef priv_value_t value_type;
  83. typedef typename keymapped_t::key_type key_type;
  84. typedef typename keymapped_t::mapped_type mapped_type;
  85. typedef typename nator_traits::template portable_rebind_alloc
  86. <value_type>::type allocator_type;
  87. typedef priv_node_t container_node_type;
  88. friend class node_handle_friend;
  89. ///@cond
  90. private:
  91. BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle)
  92. typedef typename nator_traits::pointer node_pointer;
  93. typedef typename dtl::aligned_storage
  94. < sizeof(nallocator_type)
  95. , dtl::alignment_of<nallocator_type>::value
  96. >::type nalloc_storage_t;
  97. node_pointer m_ptr;
  98. nalloc_storage_t m_nalloc_storage;
  99. void move_construct_alloc(nallocator_type &al)
  100. { ::new((void*)m_nalloc_storage.data, boost_container_new_t()) nallocator_type(::boost::move(al)); }
  101. void destroy_deallocate_node()
  102. {
  103. boost::movelib::to_raw_pointer(m_ptr)->destructor(this->node_alloc());
  104. nator_traits::deallocate(this->node_alloc(), m_ptr, 1u);
  105. }
  106. template<class OtherNodeHandle>
  107. void move_construct_end(OtherNodeHandle &nh)
  108. {
  109. if(m_ptr){
  110. ::new ((void*)m_nalloc_storage.data, boost_container_new_t()) nallocator_type(::boost::move(nh.node_alloc()));
  111. node_handle_friend::destroy_alloc(nh);
  112. node_handle_friend::get_node_pointer(nh) = node_pointer();
  113. }
  114. BOOST_ASSERT(nh.empty());
  115. }
  116. void destroy_alloc() BOOST_NOEXCEPT
  117. { static_cast<nallocator_type*>((void*)m_nalloc_storage.data)->~nallocator_type(); }
  118. node_pointer &get_node_pointer() BOOST_NOEXCEPT
  119. { return m_ptr; }
  120. ///@endcond
  121. public:
  122. //! <b>Effects</b>: Initializes m_ptr to nullptr.
  123. //!
  124. //! <b>Postcondition</b>: this->empty()
  125. BOOST_CXX14_CONSTEXPR node_handle() BOOST_NOEXCEPT
  126. : m_ptr()
  127. { }
  128. //! <b>Effects</b>: Constructs a node_handle object initializing internal pointer with p.
  129. //! If p != nullptr copy constructs internal allocator from al.
  130. node_handle(node_pointer p, const nallocator_type &al) BOOST_NOEXCEPT
  131. : m_ptr(p)
  132. {
  133. if(m_ptr){
  134. ::new ((void*)m_nalloc_storage.data, boost_container_new_t()) nallocator_type(al);
  135. }
  136. }
  137. //! <b>Effects</b>: Constructs a node_handle object initializing internal pointer with a related nh's internal pointer
  138. //! and assigns nullptr to the later. If nh's internal pointer was not nullptr, move constructs internal
  139. //! allocator with nh's internal allocator and destroy nh's internal allocator.
  140. //!
  141. //! <b>Postcondition</b>: nh.empty()
  142. //!
  143. //! <b>Note</b>: Two node_handle's are related if only one of KeyMapped template parameter
  144. //! of a node handle is void.
  145. template<class KeyMapped2>
  146. node_handle( BOOST_RV_REF_BEG node_handle<NodeAllocator, KeyMapped2> BOOST_RV_REF_END nh
  147. , typename dtl::enable_if_c
  148. < ((unsigned)dtl::is_same<KeyMapped, void>::value +
  149. (unsigned)dtl::is_same<KeyMapped2, void>::value) == 1u
  150. >::type* = 0) BOOST_NOEXCEPT
  151. : m_ptr(nh.get())
  152. { this->move_construct_end(nh); }
  153. //! <b>Effects</b>: Constructs a node_handle object initializing internal pointer with nh's internal pointer
  154. //! and assigns nullptr to the later. If nh's internal pointer was not nullptr, move constructs internal
  155. //! allocator with nh's internal allocator and destroy nh's internal allocator.
  156. //!
  157. //! <b>Postcondition</b>: nh.empty()
  158. node_handle (BOOST_RV_REF(node_handle) nh) BOOST_NOEXCEPT
  159. : m_ptr(nh.m_ptr)
  160. { this->move_construct_end(nh); }
  161. //! <b>Effects</b>: If !this->empty(), destroys the value_type subobject in the container_node_type object
  162. //! pointed to by c by calling allocator_traits<impl_defined>::destroy, then deallocates m_ptr by calling
  163. //! nator_traits::rebind_traits<container_node_type>::deallocate.
  164. ~node_handle() BOOST_NOEXCEPT
  165. {
  166. if(!this->empty()){
  167. this->destroy_deallocate_node();
  168. this->destroy_alloc();
  169. }
  170. }
  171. //! <b>Requires</b>: Either this->empty(), or nator_traits::propagate_on_container_move_assignment is true, or
  172. //! node_alloc() == nh.node_alloc().
  173. //!
  174. //! <b>Effects</b>: If m_ptr != nullptr, destroys the value_type subobject in the container_node_type object
  175. //! pointed to by m_ptr by calling nator_traits::destroy, then deallocates m_ptr by calling
  176. //! nator_traits::deallocate. Assigns nh.m_ptr to m_ptr. If this->empty()
  177. //! or nator_traits::propagate_on_container_move_assignment is true, move assigns nh.node_alloc() to
  178. //! node_alloc(). Assigns nullptr to nh.m_ptr and assigns nullopt to nh.node_alloc().
  179. //!
  180. //! <b>Returns</b>: *this.
  181. //!
  182. //! <b>Throws</b>: Nothing.
  183. node_handle & operator=(BOOST_RV_REF(node_handle) nh) BOOST_NOEXCEPT
  184. {
  185. BOOST_ASSERT(this->empty() || nator_traits::propagate_on_container_move_assignment::value
  186. || nator_traits::equal(node_alloc(), nh.node_alloc()));
  187. bool const was_this_non_null = !this->empty();
  188. bool const was_nh_non_null = !nh.empty();
  189. if(was_nh_non_null){
  190. if(was_this_non_null){
  191. this->destroy_deallocate_node();
  192. if(nator_traits::propagate_on_container_move_assignment::value){
  193. this->node_alloc() = ::boost::move(nh.node_alloc());
  194. }
  195. }
  196. else{
  197. this->move_construct_alloc(nh.node_alloc());
  198. }
  199. m_ptr = nh.m_ptr;
  200. nh.m_ptr = node_pointer();
  201. nh.destroy_alloc();
  202. }
  203. else if(was_this_non_null){
  204. this->destroy_deallocate_node();
  205. this->destroy_alloc();
  206. m_ptr = node_pointer();
  207. }
  208. return *this;
  209. }
  210. //! <b>Requires</b>: empty() == false.
  211. //!
  212. //! <b>Returns</b>: A reference to the value_type subobject in the container_node_type object pointed to by m_ptr
  213. //!
  214. //! <b>Throws</b>: Nothing.
  215. value_type& value() const BOOST_NOEXCEPT
  216. {
  217. BOOST_STATIC_ASSERT((dtl::is_same<KeyMapped, void>::value));
  218. BOOST_ASSERT(!empty());
  219. return m_ptr->get_data();
  220. }
  221. //! <b>Requires</b>: empty() == false.
  222. //!
  223. //! <b>Returns</b>: A non-const reference to the key_type member of the value_type subobject in the
  224. //! container_node_type object pointed to by m_ptr.
  225. //!
  226. //! <b>Throws</b>: Nothing.
  227. //!
  228. //! <b>Requires</b>: Modifying the key through the returned reference is permitted.
  229. key_type& key() const BOOST_NOEXCEPT
  230. {
  231. BOOST_STATIC_ASSERT((!dtl::is_same<KeyMapped, void>::value));
  232. BOOST_ASSERT(!empty());
  233. return const_cast<key_type &>(KeyMapped().key_of_value(m_ptr->get_data()));
  234. }
  235. //! <b>Requires</b>: empty() == false.
  236. //!
  237. //! <b>Returns</b>: A reference to the mapped_type member of the value_type subobject
  238. //! in the container_node_type object pointed to by m_ptr
  239. //!
  240. //! <b>Throws</b>: Nothing.
  241. mapped_type& mapped() const BOOST_NOEXCEPT
  242. {
  243. BOOST_STATIC_ASSERT((!dtl::is_same<KeyMapped, void>::value));
  244. BOOST_ASSERT(!empty());
  245. return KeyMapped().mapped_of_value(m_ptr->get_data());
  246. }
  247. //! <b>Requires</b>: empty() == false.
  248. //!
  249. //! <b>Returns</b>: A copy of the internally hold allocator.
  250. //!
  251. //! <b>Throws</b>: Nothing.
  252. allocator_type get_allocator() const
  253. {
  254. BOOST_ASSERT(!empty());
  255. return this->node_alloc();
  256. }
  257. //! <b>Returns</b>: m_ptr != nullptr.
  258. //!
  259. #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
  260. BOOST_CONTAINER_FORCEINLINE explicit operator bool
  261. #else
  262. private: struct bool_conversion {int for_bool; int for_arg(); }; typedef int bool_conversion::* explicit_bool_arg;
  263. public: BOOST_CONTAINER_FORCEINLINE operator explicit_bool_arg
  264. #endif
  265. ()const BOOST_NOEXCEPT
  266. { return m_ptr ? &bool_conversion::for_bool : explicit_bool_arg(0); }
  267. //! <b>Returns</b>: m_ptr == nullptr.
  268. //!
  269. bool empty() const BOOST_NOEXCEPT
  270. {
  271. return !this->m_ptr;
  272. }
  273. //! <b>Requires</b>: this->empty(), or nh.empty(), or nator_traits::propagate_on_container_swap is true, or
  274. //! node_alloc() == nh.node_alloc().
  275. //!
  276. //! <b>Effects</b>: Calls swap(m_ptr, nh.m_ptr). If this->empty(), or nh.empty(), or nator_traits::propagate_on_-
  277. //! container_swap is true calls swap(node_alloc(), nh.node_alloc()).
  278. void swap(node_handle &nh)
  279. BOOST_NOEXCEPT_IF(nator_traits::propagate_on_container_swap::value || nator_traits::is_always_equal::value)
  280. {
  281. BOOST_ASSERT(this->empty() || nh.empty() || nator_traits::propagate_on_container_swap::value
  282. || nator_traits::equal(node_alloc(), nh.node_alloc()));
  283. bool const was_this_non_null = !this->empty();
  284. bool const was_nh_non_null = !nh.empty();
  285. if(was_nh_non_null){
  286. if(was_this_non_null){
  287. if(nator_traits::propagate_on_container_swap::value){
  288. ::boost::adl_move_swap(this->node_alloc(), nh.node_alloc());
  289. }
  290. }
  291. else{
  292. this->move_construct_alloc(nh.node_alloc());
  293. nh.destroy_alloc();
  294. }
  295. }
  296. else if(was_this_non_null){
  297. nh.move_construct_alloc(this->node_alloc());
  298. this->destroy_alloc();
  299. }
  300. ::boost::adl_move_swap(m_ptr, nh.m_ptr);
  301. }
  302. //! <b>Effects</b>: If this->empty() returns nullptr, otherwise returns m_ptr
  303. //! resets m_ptr to nullptr and destroys the internal allocator.
  304. //!
  305. //! <b>Postcondition</b>: this->empty()
  306. //!
  307. //! <b>Note</b>: Non-standard extensions
  308. node_pointer release() BOOST_NOEXCEPT
  309. {
  310. node_pointer p(m_ptr);
  311. m_ptr = node_pointer();
  312. if(p)
  313. this->destroy_alloc();
  314. return p;
  315. }
  316. //! <b>Effects</b>: Returns m_ptr.
  317. //!
  318. //! <b>Note</b>: Non-standard extensions
  319. node_pointer get() const BOOST_NOEXCEPT
  320. {
  321. return m_ptr;
  322. }
  323. //! <b>Effects</b>: Returns a reference to the internal node allocator.
  324. //!
  325. //! <b>Note</b>: Non-standard extensions
  326. nallocator_type &node_alloc() BOOST_NOEXCEPT
  327. {
  328. BOOST_ASSERT(!empty());
  329. return *static_cast<nallocator_type*>((void*)m_nalloc_storage.data);
  330. }
  331. //! <b>Effects</b>: Returns a reference to the internal node allocator.
  332. //!
  333. //! <b>Note</b>: Non-standard extensions
  334. const nallocator_type &node_alloc() const BOOST_NOEXCEPT
  335. {
  336. BOOST_ASSERT(!empty());
  337. return *static_cast<const nallocator_type*>((const void*)m_nalloc_storage.data);
  338. }
  339. //! <b>Effects</b>: x.swap(y).
  340. //!
  341. friend void swap(node_handle & x, node_handle & y) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y)))
  342. { x.swap(y); }
  343. };
  344. //! A class template used to describe the results of inserting a
  345. //! Container::node_type in a Container with unique keys.
  346. //! Includes at least the following non-static public data members:
  347. //!
  348. //! <ul><li>bool inserted</li>;
  349. //! <li>Iterator position</li>;
  350. //! <li>NodeType node</li></ul>
  351. //!
  352. //! This type is MoveConstructible, MoveAssignable, DefaultConstructible,
  353. //! Destructible, and lvalues of that type are swappable
  354. template<class Iterator, class NodeType>
  355. struct insert_return_type_base
  356. {
  357. private:
  358. BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_base)
  359. public:
  360. insert_return_type_base()
  361. : inserted(false), position(), node()
  362. {}
  363. insert_return_type_base(BOOST_RV_REF(insert_return_type_base) other)
  364. : inserted(other.inserted), position(other.position), node(boost::move(other.node))
  365. {}
  366. template<class RelatedIt, class RelatedNode>
  367. insert_return_type_base(bool insert, RelatedIt it, BOOST_RV_REF(RelatedNode) n)
  368. : inserted(insert), position(it), node(boost::move(n))
  369. {}
  370. insert_return_type_base & operator=(BOOST_RV_REF(insert_return_type_base) other)
  371. {
  372. inserted = other.inserted;
  373. position = other.position;
  374. node = boost::move(other.node);
  375. return *this;
  376. }
  377. bool inserted;
  378. Iterator position;
  379. NodeType node;
  380. };
  381. } //namespace container {
  382. } //namespace boost {
  383. #include <boost/container/detail/config_end.hpp>
  384. #endif //BOOST_CONTAINER_NODE_HANDLE_HPP