You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

common.h 7.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright 2018 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_H_
  15. #define ABSL_CONTAINER_INTERNAL_CONTAINER_H_
  16. #include <cassert>
  17. #include <type_traits>
  18. #include "absl/meta/type_traits.h"
  19. #include "absl/types/optional.h"
  20. namespace absl
  21. {
  22. ABSL_NAMESPACE_BEGIN
  23. namespace container_internal
  24. {
  25. template<class, class = void>
  26. struct IsTransparent : std::false_type
  27. {
  28. };
  29. template<class T>
  30. struct IsTransparent<T, absl::void_t<typename T::is_transparent>> : std::true_type
  31. {
  32. };
  33. template<bool is_transparent>
  34. struct KeyArg
  35. {
  36. // Transparent. Forward `K`.
  37. template<typename K, typename key_type>
  38. using type = K;
  39. };
  40. template<>
  41. struct KeyArg<false>
  42. {
  43. // Not transparent. Always use `key_type`.
  44. template<typename K, typename key_type>
  45. using type = key_type;
  46. };
  47. // The node_handle concept from C++17.
  48. // We specialize node_handle for sets and maps. node_handle_base holds the
  49. // common API of both.
  50. template<typename PolicyTraits, typename Alloc>
  51. class node_handle_base
  52. {
  53. protected:
  54. using slot_type = typename PolicyTraits::slot_type;
  55. public:
  56. using allocator_type = Alloc;
  57. constexpr node_handle_base() = default;
  58. node_handle_base(node_handle_base&& other) noexcept
  59. {
  60. *this = std::move(other);
  61. }
  62. ~node_handle_base()
  63. {
  64. destroy();
  65. }
  66. node_handle_base& operator=(node_handle_base&& other) noexcept
  67. {
  68. destroy();
  69. if (!other.empty())
  70. {
  71. alloc_ = other.alloc_;
  72. PolicyTraits::transfer(alloc(), slot(), other.slot());
  73. other.reset();
  74. }
  75. return *this;
  76. }
  77. bool empty() const noexcept
  78. {
  79. return !alloc_;
  80. }
  81. explicit operator bool() const noexcept
  82. {
  83. return !empty();
  84. }
  85. allocator_type get_allocator() const
  86. {
  87. return *alloc_;
  88. }
  89. protected:
  90. friend struct CommonAccess;
  91. struct transfer_tag_t
  92. {
  93. };
  94. node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s) :
  95. alloc_(a)
  96. {
  97. PolicyTraits::transfer(alloc(), slot(), s);
  98. }
  99. struct construct_tag_t
  100. {
  101. };
  102. template<typename... Args>
  103. node_handle_base(construct_tag_t, const allocator_type& a, Args&&... args) :
  104. alloc_(a)
  105. {
  106. PolicyTraits::construct(alloc(), slot(), std::forward<Args>(args)...);
  107. }
  108. void destroy()
  109. {
  110. if (!empty())
  111. {
  112. PolicyTraits::destroy(alloc(), slot());
  113. reset();
  114. }
  115. }
  116. void reset()
  117. {
  118. assert(alloc_.has_value());
  119. alloc_ = absl::nullopt;
  120. }
  121. slot_type* slot() const
  122. {
  123. assert(!empty());
  124. return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
  125. }
  126. allocator_type* alloc()
  127. {
  128. return std::addressof(*alloc_);
  129. }
  130. private:
  131. absl::optional<allocator_type> alloc_ = {};
  132. alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {};
  133. };
  134. // For sets.
  135. template<typename Policy, typename PolicyTraits, typename Alloc, typename = void>
  136. class node_handle : public node_handle_base<PolicyTraits, Alloc>
  137. {
  138. using Base = node_handle_base<PolicyTraits, Alloc>;
  139. public:
  140. using value_type = typename PolicyTraits::value_type;
  141. constexpr node_handle()
  142. {
  143. }
  144. value_type& value() const
  145. {
  146. return PolicyTraits::element(this->slot());
  147. }
  148. private:
  149. friend struct CommonAccess;
  150. using Base::Base;
  151. };
  152. // For maps.
  153. template<typename Policy, typename PolicyTraits, typename Alloc>
  154. class node_handle<Policy, PolicyTraits, Alloc, absl::void_t<typename Policy::mapped_type>> : public node_handle_base<PolicyTraits, Alloc>
  155. {
  156. using Base = node_handle_base<PolicyTraits, Alloc>;
  157. using slot_type = typename PolicyTraits::slot_type;
  158. public:
  159. using key_type = typename Policy::key_type;
  160. using mapped_type = typename Policy::mapped_type;
  161. constexpr node_handle()
  162. {
  163. }
  164. // When C++17 is available, we can use std::launder to provide mutable
  165. // access to the key. Otherwise, we provide const access.
  166. auto key() const
  167. -> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>()))
  168. {
  169. return PolicyTraits::mutable_key(this->slot());
  170. }
  171. mapped_type& mapped() const
  172. {
  173. return PolicyTraits::value(&PolicyTraits::element(this->slot()));
  174. }
  175. private:
  176. friend struct CommonAccess;
  177. using Base::Base;
  178. };
  179. // Provide access to non-public node-handle functions.
  180. struct CommonAccess
  181. {
  182. template<typename Node>
  183. static auto GetSlot(const Node& node) -> decltype(node.slot())
  184. {
  185. return node.slot();
  186. }
  187. template<typename Node>
  188. static void Destroy(Node* node)
  189. {
  190. node->destroy();
  191. }
  192. template<typename Node>
  193. static void Reset(Node* node)
  194. {
  195. node->reset();
  196. }
  197. template<typename T, typename... Args>
  198. static T Transfer(Args&&... args)
  199. {
  200. return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...);
  201. }
  202. template<typename T, typename... Args>
  203. static T Construct(Args&&... args)
  204. {
  205. return T(typename T::construct_tag_t{}, std::forward<Args>(args)...);
  206. }
  207. };
  208. // Implement the insert_return_type<> concept of C++17.
  209. template<class Iterator, class NodeType>
  210. struct InsertReturnType
  211. {
  212. Iterator position;
  213. bool inserted;
  214. NodeType node;
  215. };
  216. } // namespace container_internal
  217. ABSL_NAMESPACE_END
  218. } // namespace absl
  219. #endif // ABSL_CONTAINER_INTERNAL_CONTAINER_H_