common_policy_traits.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright 2022 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_POLICY_TRAITS_H_
  15. #define ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_
  16. #include <cstddef>
  17. #include <cstring>
  18. #include <memory>
  19. #include <new>
  20. #include <type_traits>
  21. #include <utility>
  22. #include "absl/meta/type_traits.h"
  23. namespace absl {
  24. ABSL_NAMESPACE_BEGIN
  25. namespace container_internal {
  26. template <class Policy, class = void>
  27. struct policy_trait_element_is_owner : std::false_type {};
  28. template <class Policy>
  29. struct policy_trait_element_is_owner<
  30. Policy,
  31. std::enable_if_t<!std::is_void<typename Policy::element_is_owner>::value>>
  32. : Policy::element_is_owner {};
  33. // Defines how slots are initialized/destroyed/moved.
  34. template <class Policy, class = void>
  35. struct common_policy_traits {
  36. // The actual object stored in the container.
  37. using slot_type = typename Policy::slot_type;
  38. using reference = decltype(Policy::element(std::declval<slot_type*>()));
  39. using value_type = typename std::remove_reference<reference>::type;
  40. // PRECONDITION: `slot` is UNINITIALIZED
  41. // POSTCONDITION: `slot` is INITIALIZED
  42. template <class Alloc, class... Args>
  43. static void construct(Alloc* alloc, slot_type* slot, Args&&... args) {
  44. Policy::construct(alloc, slot, std::forward<Args>(args)...);
  45. }
  46. // PRECONDITION: `slot` is INITIALIZED
  47. // POSTCONDITION: `slot` is UNINITIALIZED
  48. // Returns std::true_type in case destroy is trivial.
  49. template <class Alloc>
  50. static auto destroy(Alloc* alloc, slot_type* slot) {
  51. return Policy::destroy(alloc, slot);
  52. }
  53. // Transfers the `old_slot` to `new_slot`. Any memory allocated by the
  54. // allocator inside `old_slot` to `new_slot` can be transferred.
  55. //
  56. // OPTIONAL: defaults to:
  57. //
  58. // clone(new_slot, std::move(*old_slot));
  59. // destroy(old_slot);
  60. //
  61. // PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED
  62. // POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is
  63. // UNINITIALIZED
  64. template <class Alloc>
  65. static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot) {
  66. transfer_impl(alloc, new_slot, old_slot, Rank2{});
  67. }
  68. // PRECONDITION: `slot` is INITIALIZED
  69. // POSTCONDITION: `slot` is INITIALIZED
  70. // Note: we use remove_const_t so that the two overloads have different args
  71. // in the case of sets with explicitly const value_types.
  72. template <class P = Policy>
  73. static auto element(absl::remove_const_t<slot_type>* slot)
  74. -> decltype(P::element(slot)) {
  75. return P::element(slot);
  76. }
  77. template <class P = Policy>
  78. static auto element(const slot_type* slot) -> decltype(P::element(slot)) {
  79. return P::element(slot);
  80. }
  81. static constexpr bool transfer_uses_memcpy() {
  82. return std::is_same<decltype(transfer_impl<std::allocator<char>>(
  83. nullptr, nullptr, nullptr, Rank2{})),
  84. std::true_type>::value;
  85. }
  86. // Returns true if destroy is trivial and can be omitted.
  87. template <class Alloc>
  88. static constexpr bool destroy_is_trivial() {
  89. return std::is_same<decltype(destroy<Alloc>(nullptr, nullptr)),
  90. std::true_type>::value;
  91. }
  92. private:
  93. // Use go/ranked-overloads for dispatching.
  94. struct Rank0 {};
  95. struct Rank1 : Rank0 {};
  96. struct Rank2 : Rank1 {};
  97. // Use auto -> decltype as an enabler.
  98. // P::transfer returns std::true_type if transfer uses memcpy (e.g. in
  99. // node_slot_policy).
  100. template <class Alloc, class P = Policy>
  101. static auto transfer_impl(Alloc* alloc, slot_type* new_slot,
  102. slot_type* old_slot,
  103. Rank2) -> decltype(P::transfer(alloc, new_slot,
  104. old_slot)) {
  105. return P::transfer(alloc, new_slot, old_slot);
  106. }
  107. #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
  108. // This overload returns true_type for the trait below.
  109. // The conditional_t is to make the enabler type dependent.
  110. template <class Alloc,
  111. typename = std::enable_if_t<absl::is_trivially_relocatable<
  112. std::conditional_t<false, Alloc, value_type>>::value>>
  113. static std::true_type transfer_impl(Alloc*, slot_type* new_slot,
  114. slot_type* old_slot, Rank1) {
  115. // TODO(b/247130232): remove casts after fixing warnings.
  116. // TODO(b/251814870): remove casts after fixing warnings.
  117. std::memcpy(
  118. static_cast<void*>(std::launder(
  119. const_cast<std::remove_const_t<value_type>*>(&element(new_slot)))),
  120. static_cast<const void*>(&element(old_slot)), sizeof(value_type));
  121. return {};
  122. }
  123. #endif
  124. template <class Alloc>
  125. static void transfer_impl(Alloc* alloc, slot_type* new_slot,
  126. slot_type* old_slot, Rank0) {
  127. construct(alloc, new_slot, std::move(element(old_slot)));
  128. destroy(alloc, old_slot);
  129. }
  130. };
  131. } // namespace container_internal
  132. ABSL_NAMESPACE_END
  133. } // namespace absl
  134. #endif // ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_