node_handle.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /* Copyright 2023 Christian Mazakas.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See https://www.boost.org/libs/unordered for library home page.
  7. */
  8. #ifndef BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
  9. #define BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
  10. #include <boost/unordered/detail/opt_storage.hpp>
  11. #include <boost/config.hpp>
  12. #include <boost/core/allocator_access.hpp>
  13. namespace boost{
  14. namespace unordered{
  15. namespace detail{
  16. namespace foa{
  17. template <class Iterator,class NodeType>
  18. struct insert_return_type
  19. {
  20. Iterator position;
  21. bool inserted;
  22. NodeType node;
  23. };
  24. template <class TypePolicy,class Allocator>
  25. struct node_handle_base
  26. {
  27. protected:
  28. using type_policy=TypePolicy;
  29. using element_type=typename type_policy::element_type;
  30. public:
  31. using allocator_type = Allocator;
  32. private:
  33. using node_value_type=typename type_policy::value_type;
  34. element_type p_;
  35. BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS opt_storage<Allocator> a_;
  36. protected:
  37. node_value_type& data()noexcept
  38. {
  39. return *(p_.p);
  40. }
  41. node_value_type const& data()const noexcept
  42. {
  43. return *(p_.p);
  44. }
  45. element_type& element()noexcept
  46. {
  47. BOOST_ASSERT(!empty());
  48. return p_;
  49. }
  50. element_type const& element()const noexcept
  51. {
  52. BOOST_ASSERT(!empty());
  53. return p_;
  54. }
  55. Allocator& al()noexcept
  56. {
  57. BOOST_ASSERT(!empty());
  58. return a_.t_;
  59. }
  60. Allocator const& al()const noexcept
  61. {
  62. BOOST_ASSERT(!empty());
  63. return a_.t_;
  64. }
  65. void emplace(element_type&& x,Allocator a)
  66. {
  67. BOOST_ASSERT(empty());
  68. auto* p=x.p;
  69. p_.p=p;
  70. new(&a_.t_)Allocator(a);
  71. x.p=nullptr;
  72. }
  73. void reset()
  74. {
  75. a_.t_.~Allocator();
  76. p_.p=nullptr;
  77. }
  78. public:
  79. constexpr node_handle_base()noexcept:p_{nullptr}{}
  80. node_handle_base(node_handle_base&& nh) noexcept
  81. {
  82. p_.p = nullptr;
  83. if (!nh.empty()){
  84. emplace(std::move(nh.p_),nh.al());
  85. nh.reset();
  86. }
  87. }
  88. node_handle_base& operator=(node_handle_base&& nh)noexcept
  89. {
  90. if(this!=&nh){
  91. if(empty()){
  92. if(nh.empty()){ /* empty(), nh.empty() */
  93. /* nothing to do */
  94. }else{ /* empty(), !nh.empty() */
  95. emplace(std::move(nh.p_),std::move(nh.al()));
  96. nh.reset();
  97. }
  98. }else{
  99. if(nh.empty()){ /* !empty(), nh.empty() */
  100. type_policy::destroy(al(),&p_);
  101. reset();
  102. }else{ /* !empty(), !nh.empty() */
  103. bool const pocma=
  104. boost::allocator_propagate_on_container_move_assignment<
  105. Allocator>::type::value;
  106. BOOST_ASSERT(pocma||al()==nh.al());
  107. type_policy::destroy(al(),&p_);
  108. if(pocma){
  109. al()=std::move(nh.al());
  110. }
  111. p_=std::move(nh.p_);
  112. nh.reset();
  113. }
  114. }
  115. }else{
  116. if(empty()){ /* empty(), nh.empty() */
  117. /* nothing to do */
  118. }else{ /* !empty(), !nh.empty() */
  119. type_policy::destroy(al(),&p_);
  120. reset();
  121. }
  122. }
  123. return *this;
  124. }
  125. ~node_handle_base()
  126. {
  127. if(!empty()){
  128. type_policy::destroy(al(),&p_);
  129. reset();
  130. }
  131. }
  132. allocator_type get_allocator()const noexcept{return al();}
  133. explicit operator bool()const noexcept{ return !empty();}
  134. BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_.p==nullptr;}
  135. void swap(node_handle_base& nh) noexcept(
  136. boost::allocator_is_always_equal<Allocator>::type::value||
  137. boost::allocator_propagate_on_container_swap<Allocator>::type::value)
  138. {
  139. if(this!=&nh){
  140. if(empty()){
  141. if(nh.empty()) {
  142. /* nothing to do here */
  143. } else {
  144. emplace(std::move(nh.p_), nh.al());
  145. nh.reset();
  146. }
  147. }else{
  148. if(nh.empty()){
  149. nh.emplace(std::move(p_),al());
  150. reset();
  151. }else{
  152. bool const pocs=
  153. boost::allocator_propagate_on_container_swap<
  154. Allocator>::type::value;
  155. BOOST_ASSERT(pocs || al()==nh.al());
  156. using std::swap;
  157. p_.swap(nh.p_);
  158. if(pocs)swap(al(),nh.al());
  159. }
  160. }
  161. }
  162. }
  163. friend
  164. void swap(node_handle_base& lhs,node_handle_base& rhs)
  165. noexcept(noexcept(lhs.swap(rhs)))
  166. {
  167. return lhs.swap(rhs);
  168. }
  169. };
  170. }
  171. }
  172. }
  173. }
  174. #endif // BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP