node_handle.hpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /* Copyright 2023 Christian Mazakas.
  2. * Copyright 2024 Joaquin M Lopez Munoz.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. *
  7. * See https://www.boost.org/libs/unordered for library home page.
  8. */
  9. #ifndef BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
  10. #define BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
  11. #include <boost/unordered/detail/opt_storage.hpp>
  12. #include <boost/assert.hpp>
  13. #include <boost/config.hpp>
  14. #include <boost/config/workaround.hpp>
  15. #include <boost/core/allocator_access.hpp>
  16. #include <type_traits>
  17. namespace boost{
  18. namespace unordered{
  19. namespace detail{
  20. namespace foa{
  21. template <class Iterator,class NodeType>
  22. struct insert_return_type
  23. {
  24. Iterator position;
  25. bool inserted;
  26. NodeType node;
  27. };
  28. template <class NodeType>
  29. struct iteratorless_insert_return_type
  30. {
  31. bool inserted;
  32. NodeType node;
  33. };
  34. template <class TypePolicy,class Allocator>
  35. struct node_handle_base
  36. {
  37. protected:
  38. using type_policy=TypePolicy;
  39. using element_type=typename type_policy::element_type;
  40. public:
  41. using allocator_type = Allocator;
  42. private:
  43. using node_value_type=typename type_policy::value_type;
  44. element_type p_;
  45. BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS opt_storage<Allocator> a_;
  46. friend struct node_handle_access;
  47. template<bool B>
  48. void move_assign_allocator_if(node_handle_base&& nh)noexcept
  49. {
  50. move_assign_allocator_if(
  51. std::integral_constant<bool,B>{}, std::move(nh));
  52. }
  53. void move_assign_allocator_if(
  54. std::true_type, node_handle_base&& nh)noexcept
  55. {
  56. al()=std::move(nh.al());
  57. }
  58. void move_assign_allocator_if(
  59. std::false_type, node_handle_base&&)noexcept
  60. {
  61. }
  62. protected:
  63. node_value_type& data()noexcept
  64. {
  65. return *(p_.p);
  66. }
  67. node_value_type const& data()const noexcept
  68. {
  69. return *(p_.p);
  70. }
  71. element_type& element()noexcept
  72. {
  73. BOOST_ASSERT(!empty());
  74. return p_;
  75. }
  76. element_type const& element()const noexcept
  77. {
  78. BOOST_ASSERT(!empty());
  79. return p_;
  80. }
  81. Allocator& al()noexcept
  82. {
  83. BOOST_ASSERT(!empty());
  84. return a_.t_;
  85. }
  86. Allocator const& al()const noexcept
  87. {
  88. BOOST_ASSERT(!empty());
  89. return a_.t_;
  90. }
  91. void emplace(element_type&& x,Allocator a)
  92. {
  93. BOOST_ASSERT(empty());
  94. auto* p=x.p;
  95. p_.p=p;
  96. new(&a_.t_)Allocator(a);
  97. x.p=nullptr;
  98. }
  99. void reset()
  100. {
  101. a_.t_.~Allocator();
  102. p_.p=nullptr;
  103. }
  104. public:
  105. constexpr node_handle_base()noexcept:p_{nullptr}{}
  106. node_handle_base(node_handle_base&& nh) noexcept
  107. {
  108. p_.p = nullptr;
  109. if (!nh.empty()){
  110. emplace(std::move(nh.p_),nh.al());
  111. nh.reset();
  112. }
  113. }
  114. node_handle_base& operator=(node_handle_base&& nh)noexcept
  115. {
  116. if(this!=&nh){
  117. if(empty()){
  118. if(nh.empty()){ /* empty(), nh.empty() */
  119. /* nothing to do */
  120. }else{ /* empty(), !nh.empty() */
  121. emplace(std::move(nh.p_),std::move(nh.al()));
  122. nh.reset();
  123. }
  124. }else{
  125. if(nh.empty()){ /* !empty(), nh.empty() */
  126. type_policy::destroy(al(),&p_);
  127. reset();
  128. }else{ /* !empty(), !nh.empty() */
  129. bool const pocma=
  130. boost::allocator_propagate_on_container_move_assignment<
  131. Allocator>::type::value;
  132. BOOST_ASSERT(pocma||al()==nh.al());
  133. type_policy::destroy(al(),&p_);
  134. move_assign_allocator_if<pocma>(std::move(nh));
  135. p_=std::move(nh.p_);
  136. nh.reset();
  137. }
  138. }
  139. }else{
  140. if(empty()){ /* empty(), nh.empty() */
  141. /* nothing to do */
  142. }else{ /* !empty(), !nh.empty() */
  143. type_policy::destroy(al(),&p_);
  144. reset();
  145. }
  146. }
  147. return *this;
  148. }
  149. ~node_handle_base()
  150. {
  151. if(!empty()){
  152. type_policy::destroy(al(),&p_);
  153. reset();
  154. }
  155. }
  156. allocator_type get_allocator()const
  157. {
  158. #if defined(BOOST_GCC)
  159. /* GCC lifetime analysis incorrectly warns about uninitialized
  160. * allocator object under some circumstances.
  161. */
  162. if(empty())__builtin_unreachable();
  163. #endif
  164. return al();
  165. }
  166. explicit operator bool()const noexcept{ return !empty();}
  167. BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_.p==nullptr;}
  168. void swap(node_handle_base& nh) noexcept(
  169. boost::allocator_is_always_equal<Allocator>::type::value||
  170. boost::allocator_propagate_on_container_swap<Allocator>::type::value)
  171. {
  172. if(this!=&nh){
  173. if(empty()){
  174. if(nh.empty()) {
  175. /* nothing to do here */
  176. } else {
  177. emplace(std::move(nh.p_), nh.al());
  178. nh.reset();
  179. }
  180. }else{
  181. if(nh.empty()){
  182. nh.emplace(std::move(p_),al());
  183. reset();
  184. }else{
  185. bool const pocs=
  186. boost::allocator_propagate_on_container_swap<
  187. Allocator>::type::value;
  188. BOOST_ASSERT(pocs || al()==nh.al());
  189. using std::swap;
  190. p_.swap(nh.p_);
  191. if(pocs)swap(al(),nh.al());
  192. }
  193. }
  194. }
  195. }
  196. friend
  197. void swap(node_handle_base& lhs,node_handle_base& rhs)
  198. noexcept(noexcept(lhs.swap(rhs)))
  199. {
  200. return lhs.swap(rhs);
  201. }
  202. };
  203. // Internal usage of node_handle_base protected API
  204. struct node_handle_access
  205. {
  206. template <class TypePolicy, class Allocator>
  207. using node_type = node_handle_base<TypePolicy, Allocator>;
  208. #if BOOST_WORKAROUND(BOOST_CLANG_VERSION,<190000)
  209. // https://github.com/llvm/llvm-project/issues/25708
  210. template <class TypePolicy, class Allocator>
  211. struct element_type_impl
  212. {
  213. using type = typename node_type<TypePolicy, Allocator>::element_type;
  214. };
  215. template <class TypePolicy, class Allocator>
  216. using element_type = typename element_type_impl<TypePolicy, Allocator>::type;
  217. #else
  218. template <class TypePolicy, class Allocator>
  219. using element_type = typename node_type<TypePolicy, Allocator>::element_type;
  220. #endif
  221. template <class TypePolicy, class Allocator>
  222. static element_type<TypePolicy, Allocator>&
  223. element(node_type<TypePolicy, Allocator>& nh)noexcept
  224. {
  225. return nh.element();
  226. }
  227. template <class TypePolicy, class Allocator>
  228. static element_type<TypePolicy, Allocator>
  229. const& element(node_type<TypePolicy, Allocator> const& nh)noexcept
  230. {
  231. return nh.element();
  232. }
  233. template <class TypePolicy, class Allocator>
  234. static void emplace(
  235. node_type<TypePolicy, Allocator>& nh,
  236. element_type<TypePolicy, Allocator>&& x, Allocator a)
  237. {
  238. nh.emplace(std::move(x), a);
  239. }
  240. template <class TypePolicy,class Allocator>
  241. static void reset(node_type<TypePolicy, Allocator>& nh)
  242. {
  243. nh.reset();
  244. }
  245. };
  246. template <class TypePolicy, class Allocator>
  247. class node_handle_emplacer_class
  248. {
  249. using access = node_handle_access;
  250. using node_type = access::node_type<TypePolicy, Allocator>;
  251. using element_type = access::element_type<TypePolicy, Allocator>;
  252. node_type & nh;
  253. public:
  254. node_handle_emplacer_class(node_type& nh_): nh(nh_) {}
  255. void operator()(element_type&& x,Allocator a)
  256. {
  257. access::emplace(nh, std::move(x), a);
  258. }
  259. };
  260. template <class TypePolicy, class Allocator>
  261. node_handle_emplacer_class<TypePolicy, Allocator>
  262. node_handle_emplacer(node_handle_base<TypePolicy, Allocator>& nh)
  263. {
  264. return {nh};
  265. }
  266. }
  267. }
  268. }
  269. }
  270. #endif // BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP