Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:10

0001 // Copyright 2022 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 
0015 #ifndef ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_
0016 #define ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_
0017 
0018 #include <cstddef>
0019 #include <cstring>
0020 #include <memory>
0021 #include <new>
0022 #include <type_traits>
0023 #include <utility>
0024 
0025 #include "absl/meta/type_traits.h"
0026 
0027 namespace absl {
0028 ABSL_NAMESPACE_BEGIN
0029 namespace container_internal {
0030 
0031 // Defines how slots are initialized/destroyed/moved.
0032 template <class Policy, class = void>
0033 struct common_policy_traits {
0034   // The actual object stored in the container.
0035   using slot_type = typename Policy::slot_type;
0036   using reference = decltype(Policy::element(std::declval<slot_type*>()));
0037   using value_type = typename std::remove_reference<reference>::type;
0038 
0039   // PRECONDITION: `slot` is UNINITIALIZED
0040   // POSTCONDITION: `slot` is INITIALIZED
0041   template <class Alloc, class... Args>
0042   static void construct(Alloc* alloc, slot_type* slot, Args&&... args) {
0043     Policy::construct(alloc, slot, std::forward<Args>(args)...);
0044   }
0045 
0046   // PRECONDITION: `slot` is INITIALIZED
0047   // POSTCONDITION: `slot` is UNINITIALIZED
0048   // Returns std::true_type in case destroy is trivial.
0049   template <class Alloc>
0050   static auto destroy(Alloc* alloc, slot_type* slot) {
0051     return Policy::destroy(alloc, slot);
0052   }
0053 
0054   // Transfers the `old_slot` to `new_slot`. Any memory allocated by the
0055   // allocator inside `old_slot` to `new_slot` can be transferred.
0056   //
0057   // OPTIONAL: defaults to:
0058   //
0059   //     clone(new_slot, std::move(*old_slot));
0060   //     destroy(old_slot);
0061   //
0062   // PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED
0063   // POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is
0064   //                UNINITIALIZED
0065   template <class Alloc>
0066   static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot) {
0067     transfer_impl(alloc, new_slot, old_slot, Rank2{});
0068   }
0069 
0070   // PRECONDITION: `slot` is INITIALIZED
0071   // POSTCONDITION: `slot` is INITIALIZED
0072   // Note: we use remove_const_t so that the two overloads have different args
0073   // in the case of sets with explicitly const value_types.
0074   template <class P = Policy>
0075   static auto element(absl::remove_const_t<slot_type>* slot)
0076       -> decltype(P::element(slot)) {
0077     return P::element(slot);
0078   }
0079   template <class P = Policy>
0080   static auto element(const slot_type* slot) -> decltype(P::element(slot)) {
0081     return P::element(slot);
0082   }
0083 
0084   static constexpr bool transfer_uses_memcpy() {
0085     return std::is_same<decltype(transfer_impl<std::allocator<char>>(
0086                             nullptr, nullptr, nullptr, Rank2{})),
0087                         std::true_type>::value;
0088   }
0089 
0090   // Returns true if destroy is trivial and can be omitted.
0091   template <class Alloc>
0092   static constexpr bool destroy_is_trivial() {
0093     return std::is_same<decltype(destroy<Alloc>(nullptr, nullptr)),
0094                         std::true_type>::value;
0095   }
0096 
0097  private:
0098   // Use go/ranked-overloads for dispatching.
0099   struct Rank0 {};
0100   struct Rank1 : Rank0 {};
0101   struct Rank2 : Rank1 {};
0102 
0103   // Use auto -> decltype as an enabler.
0104   // P::transfer returns std::true_type if transfer uses memcpy (e.g. in
0105   // node_slot_policy).
0106   template <class Alloc, class P = Policy>
0107   static auto transfer_impl(Alloc* alloc, slot_type* new_slot,
0108                             slot_type* old_slot,
0109                             Rank2) -> decltype(P::transfer(alloc, new_slot,
0110                                                            old_slot)) {
0111     return P::transfer(alloc, new_slot, old_slot);
0112   }
0113 #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
0114   // This overload returns true_type for the trait below.
0115   // The conditional_t is to make the enabler type dependent.
0116   template <class Alloc,
0117             typename = std::enable_if_t<absl::is_trivially_relocatable<
0118                 std::conditional_t<false, Alloc, value_type>>::value>>
0119   static std::true_type transfer_impl(Alloc*, slot_type* new_slot,
0120                                       slot_type* old_slot, Rank1) {
0121     // TODO(b/247130232): remove casts after fixing warnings.
0122     // TODO(b/251814870): remove casts after fixing warnings.
0123     std::memcpy(
0124         static_cast<void*>(std::launder(
0125             const_cast<std::remove_const_t<value_type>*>(&element(new_slot)))),
0126         static_cast<const void*>(&element(old_slot)), sizeof(value_type));
0127     return {};
0128   }
0129 #endif
0130 
0131   template <class Alloc>
0132   static void transfer_impl(Alloc* alloc, slot_type* new_slot,
0133                             slot_type* old_slot, Rank0) {
0134     construct(alloc, new_slot, std::move(element(old_slot)));
0135     destroy(alloc, old_slot);
0136   }
0137 };
0138 
0139 }  // namespace container_internal
0140 ABSL_NAMESPACE_END
0141 }  // namespace absl
0142 
0143 #endif  // ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_