Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:31:57

0001 // Copyright 2017 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_TYPES_INTERNAL_OPTIONAL_H_
0016 #define ABSL_TYPES_INTERNAL_OPTIONAL_H_
0017 
0018 #include <functional>
0019 #include <new>
0020 #include <type_traits>
0021 #include <utility>
0022 
0023 #include "absl/base/internal/inline_variable.h"
0024 #include "absl/memory/memory.h"
0025 #include "absl/meta/type_traits.h"
0026 #include "absl/utility/utility.h"
0027 
0028 namespace absl {
0029 ABSL_NAMESPACE_BEGIN
0030 
0031 // Forward declaration
0032 template <typename T>
0033 class optional;
0034 
0035 namespace optional_internal {
0036 
0037 // This tag type is used as a constructor parameter type for `nullopt_t`.
0038 struct init_t {
0039   explicit init_t() = default;
0040 };
0041 
0042 struct empty_struct {};
0043 
0044 // This class stores the data in optional<T>.
0045 // It is specialized based on whether T is trivially destructible.
0046 // This is the specialization for non trivially destructible type.
0047 template <typename T, bool unused = std::is_trivially_destructible<T>::value>
0048 class optional_data_dtor_base {
0049   struct dummy_type {
0050     static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
0051     // Use an array to avoid GCC 6 placement-new warning.
0052     empty_struct data[sizeof(T) / sizeof(empty_struct)];
0053   };
0054 
0055  protected:
0056   // Whether there is data or not.
0057   bool engaged_;
0058   // Data storage
0059   union {
0060     T data_;
0061     dummy_type dummy_;
0062   };
0063 
0064   void destruct() noexcept {
0065     if (engaged_) {
0066       // `data_` must be initialized if `engaged_` is true.
0067 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
0068 #pragma GCC diagnostic push
0069 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
0070 #endif
0071       data_.~T();
0072 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
0073 #pragma GCC diagnostic pop
0074 #endif
0075       engaged_ = false;
0076     }
0077   }
0078 
0079   // dummy_ must be initialized for constexpr constructor.
0080   constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
0081 
0082   template <typename... Args>
0083   constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
0084       : engaged_(true), data_(std::forward<Args>(args)...) {}
0085 
0086   ~optional_data_dtor_base() { destruct(); }
0087 };
0088 
0089 // Specialization for trivially destructible type.
0090 template <typename T>
0091 class optional_data_dtor_base<T, true> {
0092   struct dummy_type {
0093     static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
0094     // Use array to avoid GCC 6 placement-new warning.
0095     empty_struct data[sizeof(T) / sizeof(empty_struct)];
0096   };
0097 
0098  protected:
0099   // Whether there is data or not.
0100   bool engaged_;
0101   // Data storage
0102   union {
0103     T data_;
0104     dummy_type dummy_;
0105   };
0106   void destruct() noexcept { engaged_ = false; }
0107 
0108   // dummy_ must be initialized for constexpr constructor.
0109   constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
0110 
0111   template <typename... Args>
0112   constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
0113       : engaged_(true), data_(std::forward<Args>(args)...) {}
0114 };
0115 
0116 template <typename T>
0117 class optional_data_base : public optional_data_dtor_base<T> {
0118  protected:
0119   using base = optional_data_dtor_base<T>;
0120   using base::base;
0121 
0122   template <typename... Args>
0123   void construct(Args&&... args) {
0124     // Use dummy_'s address to work around casting cv-qualified T* to void*.
0125     ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
0126     this->engaged_ = true;
0127   }
0128 
0129   template <typename U>
0130   void assign(U&& u) {
0131     if (this->engaged_) {
0132       this->data_ = std::forward<U>(u);
0133     } else {
0134       construct(std::forward<U>(u));
0135     }
0136   }
0137 };
0138 
0139 // TODO(absl-team): Add another class using
0140 // std::is_trivially_move_constructible trait when available to match
0141 // http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
0142 // have trivial move but nontrivial copy.
0143 // Also, we should be checking is_trivially_copyable here, which is not
0144 // supported now, so we use is_trivially_* traits instead.
0145 template <typename T,
0146           bool unused = absl::is_trivially_copy_constructible<T>::value&&
0147               absl::is_trivially_copy_assignable<typename std::remove_cv<
0148                   T>::type>::value&& std::is_trivially_destructible<T>::value>
0149 class optional_data;
0150 
0151 // Trivially copyable types
0152 template <typename T>
0153 class optional_data<T, true> : public optional_data_base<T> {
0154  protected:
0155   using optional_data_base<T>::optional_data_base;
0156 };
0157 
0158 template <typename T>
0159 class optional_data<T, false> : public optional_data_base<T> {
0160  protected:
0161   using optional_data_base<T>::optional_data_base;
0162 
0163   optional_data() = default;
0164 
0165   optional_data(const optional_data& rhs) : optional_data_base<T>() {
0166     if (rhs.engaged_) {
0167       this->construct(rhs.data_);
0168     }
0169   }
0170 
0171   optional_data(optional_data&& rhs) noexcept(
0172       absl::default_allocator_is_nothrow::value ||
0173       std::is_nothrow_move_constructible<T>::value)
0174       : optional_data_base<T>() {
0175     if (rhs.engaged_) {
0176       this->construct(std::move(rhs.data_));
0177     }
0178   }
0179 
0180   optional_data& operator=(const optional_data& rhs) {
0181     if (rhs.engaged_) {
0182       this->assign(rhs.data_);
0183     } else {
0184       this->destruct();
0185     }
0186     return *this;
0187   }
0188 
0189   optional_data& operator=(optional_data&& rhs) noexcept(
0190       std::is_nothrow_move_assignable<T>::value&&
0191           std::is_nothrow_move_constructible<T>::value) {
0192     if (rhs.engaged_) {
0193       this->assign(std::move(rhs.data_));
0194     } else {
0195       this->destruct();
0196     }
0197     return *this;
0198   }
0199 };
0200 
0201 // Ordered by level of restriction, from low to high.
0202 // Copyable implies movable.
0203 enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
0204 
0205 // Base class for enabling/disabling copy/move constructor.
0206 template <copy_traits>
0207 class optional_ctor_base;
0208 
0209 template <>
0210 class optional_ctor_base<copy_traits::copyable> {
0211  public:
0212   constexpr optional_ctor_base() = default;
0213   optional_ctor_base(const optional_ctor_base&) = default;
0214   optional_ctor_base(optional_ctor_base&&) = default;
0215   optional_ctor_base& operator=(const optional_ctor_base&) = default;
0216   optional_ctor_base& operator=(optional_ctor_base&&) = default;
0217 };
0218 
0219 template <>
0220 class optional_ctor_base<copy_traits::movable> {
0221  public:
0222   constexpr optional_ctor_base() = default;
0223   optional_ctor_base(const optional_ctor_base&) = delete;
0224   optional_ctor_base(optional_ctor_base&&) = default;
0225   optional_ctor_base& operator=(const optional_ctor_base&) = default;
0226   optional_ctor_base& operator=(optional_ctor_base&&) = default;
0227 };
0228 
0229 template <>
0230 class optional_ctor_base<copy_traits::non_movable> {
0231  public:
0232   constexpr optional_ctor_base() = default;
0233   optional_ctor_base(const optional_ctor_base&) = delete;
0234   optional_ctor_base(optional_ctor_base&&) = delete;
0235   optional_ctor_base& operator=(const optional_ctor_base&) = default;
0236   optional_ctor_base& operator=(optional_ctor_base&&) = default;
0237 };
0238 
0239 // Base class for enabling/disabling copy/move assignment.
0240 template <copy_traits>
0241 class optional_assign_base;
0242 
0243 template <>
0244 class optional_assign_base<copy_traits::copyable> {
0245  public:
0246   constexpr optional_assign_base() = default;
0247   optional_assign_base(const optional_assign_base&) = default;
0248   optional_assign_base(optional_assign_base&&) = default;
0249   optional_assign_base& operator=(const optional_assign_base&) = default;
0250   optional_assign_base& operator=(optional_assign_base&&) = default;
0251 };
0252 
0253 template <>
0254 class optional_assign_base<copy_traits::movable> {
0255  public:
0256   constexpr optional_assign_base() = default;
0257   optional_assign_base(const optional_assign_base&) = default;
0258   optional_assign_base(optional_assign_base&&) = default;
0259   optional_assign_base& operator=(const optional_assign_base&) = delete;
0260   optional_assign_base& operator=(optional_assign_base&&) = default;
0261 };
0262 
0263 template <>
0264 class optional_assign_base<copy_traits::non_movable> {
0265  public:
0266   constexpr optional_assign_base() = default;
0267   optional_assign_base(const optional_assign_base&) = default;
0268   optional_assign_base(optional_assign_base&&) = default;
0269   optional_assign_base& operator=(const optional_assign_base&) = delete;
0270   optional_assign_base& operator=(optional_assign_base&&) = delete;
0271 };
0272 
0273 template <typename T>
0274 struct ctor_copy_traits {
0275   static constexpr copy_traits traits =
0276       std::is_copy_constructible<T>::value
0277           ? copy_traits::copyable
0278           : std::is_move_constructible<T>::value ? copy_traits::movable
0279                                                  : copy_traits::non_movable;
0280 };
0281 
0282 template <typename T>
0283 struct assign_copy_traits {
0284   static constexpr copy_traits traits =
0285       absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value
0286           ? copy_traits::copyable
0287           : absl::is_move_assignable<T>::value &&
0288                     std::is_move_constructible<T>::value
0289                 ? copy_traits::movable
0290                 : copy_traits::non_movable;
0291 };
0292 
0293 // Whether T is constructible or convertible from optional<U>.
0294 template <typename T, typename U>
0295 struct is_constructible_convertible_from_optional
0296     : std::integral_constant<
0297           bool, std::is_constructible<T, optional<U>&>::value ||
0298                     std::is_constructible<T, optional<U>&&>::value ||
0299                     std::is_constructible<T, const optional<U>&>::value ||
0300                     std::is_constructible<T, const optional<U>&&>::value ||
0301                     std::is_convertible<optional<U>&, T>::value ||
0302                     std::is_convertible<optional<U>&&, T>::value ||
0303                     std::is_convertible<const optional<U>&, T>::value ||
0304                     std::is_convertible<const optional<U>&&, T>::value> {};
0305 
0306 // Whether T is constructible or convertible or assignable from optional<U>.
0307 template <typename T, typename U>
0308 struct is_constructible_convertible_assignable_from_optional
0309     : std::integral_constant<
0310           bool, is_constructible_convertible_from_optional<T, U>::value ||
0311                     std::is_assignable<T&, optional<U>&>::value ||
0312                     std::is_assignable<T&, optional<U>&&>::value ||
0313                     std::is_assignable<T&, const optional<U>&>::value ||
0314                     std::is_assignable<T&, const optional<U>&&>::value> {};
0315 
0316 // Helper function used by [optional.relops], [optional.comp_with_t],
0317 // for checking whether an expression is convertible to bool.
0318 bool convertible_to_bool(bool);
0319 
0320 // Base class for std::hash<absl::optional<T>>:
0321 // If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
0322 // compute the hash; Otherwise, it is disabled.
0323 // Reference N4659 23.14.15 [unord.hash].
0324 template <typename T, typename = size_t>
0325 struct optional_hash_base {
0326   optional_hash_base() = delete;
0327   optional_hash_base(const optional_hash_base&) = delete;
0328   optional_hash_base(optional_hash_base&&) = delete;
0329   optional_hash_base& operator=(const optional_hash_base&) = delete;
0330   optional_hash_base& operator=(optional_hash_base&&) = delete;
0331 };
0332 
0333 template <typename T>
0334 struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
0335                                  std::declval<absl::remove_const_t<T> >()))> {
0336   using argument_type = absl::optional<T>;
0337   using result_type = size_t;
0338   size_t operator()(const absl::optional<T>& opt) const {
0339     absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
0340     if (opt) {
0341       return std::hash<absl::remove_const_t<T> >()(*opt);
0342     } else {
0343       return static_cast<size_t>(0x297814aaad196e6dULL);
0344     }
0345   }
0346 };
0347 
0348 }  // namespace optional_internal
0349 ABSL_NAMESPACE_END
0350 }  // namespace absl
0351 
0352 #endif  // ABSL_TYPES_INTERNAL_OPTIONAL_H_