common.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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_COMMON_H_
  15. #define ABSL_CONTAINER_INTERNAL_COMMON_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. ABSL_NAMESPACE_BEGIN
  22. namespace container_internal {
  23. template <class, class = void>
  24. struct IsTransparent : std::false_type {};
  25. template <class T>
  26. struct IsTransparent<T, absl::void_t<typename T::is_transparent>>
  27. : std::true_type {};
  28. template <bool is_transparent>
  29. struct KeyArg {
  30. // Transparent. Forward `K`.
  31. template <typename K, typename key_type>
  32. using type = K;
  33. };
  34. template <>
  35. struct KeyArg<false> {
  36. // Not transparent. Always use `key_type`.
  37. template <typename K, typename key_type>
  38. using type = key_type;
  39. };
  40. // The node_handle concept from C++17.
  41. // We specialize node_handle for sets and maps. node_handle_base holds the
  42. // common API of both.
  43. template <typename PolicyTraits, typename Alloc>
  44. class node_handle_base {
  45. protected:
  46. using slot_type = typename PolicyTraits::slot_type;
  47. public:
  48. using allocator_type = Alloc;
  49. constexpr node_handle_base() = default;
  50. node_handle_base(node_handle_base&& other) noexcept {
  51. *this = std::move(other);
  52. }
  53. ~node_handle_base() { destroy(); }
  54. node_handle_base& operator=(node_handle_base&& other) noexcept {
  55. destroy();
  56. if (!other.empty()) {
  57. alloc_ = other.alloc_;
  58. PolicyTraits::transfer(alloc(), slot(), other.slot());
  59. other.reset();
  60. }
  61. return *this;
  62. }
  63. bool empty() const noexcept { return !alloc_; }
  64. explicit operator bool() const noexcept { return !empty(); }
  65. allocator_type get_allocator() const { return *alloc_; }
  66. protected:
  67. friend struct CommonAccess;
  68. struct transfer_tag_t {};
  69. node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s)
  70. : alloc_(a) {
  71. PolicyTraits::transfer(alloc(), slot(), s);
  72. }
  73. struct construct_tag_t {};
  74. template <typename... Args>
  75. node_handle_base(construct_tag_t, const allocator_type& a, Args&&... args)
  76. : alloc_(a) {
  77. PolicyTraits::construct(alloc(), slot(), std::forward<Args>(args)...);
  78. }
  79. void destroy() {
  80. if (!empty()) {
  81. PolicyTraits::destroy(alloc(), slot());
  82. reset();
  83. }
  84. }
  85. void reset() {
  86. assert(alloc_.has_value());
  87. alloc_ = absl::nullopt;
  88. }
  89. slot_type* slot() const {
  90. assert(!empty());
  91. return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
  92. }
  93. allocator_type* alloc() { return std::addressof(*alloc_); }
  94. private:
  95. absl::optional<allocator_type> alloc_ = {};
  96. alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {};
  97. };
  98. // For sets.
  99. template <typename Policy, typename PolicyTraits, typename Alloc,
  100. typename = void>
  101. class node_handle : public node_handle_base<PolicyTraits, Alloc> {
  102. using Base = node_handle_base<PolicyTraits, Alloc>;
  103. public:
  104. using value_type = typename PolicyTraits::value_type;
  105. constexpr node_handle() {}
  106. value_type& value() const { return PolicyTraits::element(this->slot()); }
  107. private:
  108. friend struct CommonAccess;
  109. using Base::Base;
  110. };
  111. // For maps.
  112. template <typename Policy, typename PolicyTraits, typename Alloc>
  113. class node_handle<Policy, PolicyTraits, Alloc,
  114. absl::void_t<typename Policy::mapped_type>>
  115. : public node_handle_base<PolicyTraits, Alloc> {
  116. using Base = node_handle_base<PolicyTraits, Alloc>;
  117. using slot_type = typename PolicyTraits::slot_type;
  118. public:
  119. using key_type = typename Policy::key_type;
  120. using mapped_type = typename Policy::mapped_type;
  121. constexpr node_handle() {}
  122. // When C++17 is available, we can use std::launder to provide mutable
  123. // access to the key. Otherwise, we provide const access.
  124. auto key() const
  125. -> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>())) {
  126. return PolicyTraits::mutable_key(this->slot());
  127. }
  128. mapped_type& mapped() const {
  129. return PolicyTraits::value(&PolicyTraits::element(this->slot()));
  130. }
  131. private:
  132. friend struct CommonAccess;
  133. using Base::Base;
  134. };
  135. // Provide access to non-public node-handle functions.
  136. struct CommonAccess {
  137. template <typename Node>
  138. static auto GetSlot(const Node& node) -> decltype(node.slot()) {
  139. return node.slot();
  140. }
  141. template <typename Node>
  142. static void Destroy(Node* node) {
  143. node->destroy();
  144. }
  145. template <typename Node>
  146. static void Reset(Node* node) {
  147. node->reset();
  148. }
  149. template <typename T, typename... Args>
  150. static T Transfer(Args&&... args) {
  151. return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...);
  152. }
  153. template <typename T, typename... Args>
  154. static T Construct(Args&&... args) {
  155. return T(typename T::construct_tag_t{}, std::forward<Args>(args)...);
  156. }
  157. };
  158. // Implement the insert_return_type<> concept of C++17.
  159. template <class Iterator, class NodeType>
  160. struct InsertReturnType {
  161. Iterator position;
  162. bool inserted;
  163. NodeType node;
  164. };
  165. } // namespace container_internal
  166. ABSL_NAMESPACE_END
  167. } // namespace absl
  168. #endif // ABSL_CONTAINER_INTERNAL_COMMON_H_