node_handle.hpp 15 KB

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