// Copyright 2020 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ #define ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ #include <cstdint> #include <type_traits> #include <utility> #include "absl/base/attributes.h" #include "absl/base/nullability.h" #include "absl/meta/type_traits.h" #include "absl/status/status.h" #include "absl/strings/string_view.h" #include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN template <typename T> class ABSL_MUST_USE_RESULT StatusOr; namespace internal_statusor { // Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator // StatusOr<T>()`. template <typename T, typename U, typename = void> struct HasConversionOperatorToStatusOr : std::false_type { … }; template <typename T, typename U> void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]); HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>; // Detects whether `T` is constructible or convertible from `StatusOr<U>`. IsConstructibleOrConvertibleFromStatusOr; // Detects whether `T` is constructible or convertible or assignable from // `StatusOr<U>`. IsConstructibleOrConvertibleOrAssignableFromStatusOr; // Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e. // when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`. template <typename T, typename U> struct IsDirectInitializationAmbiguous : public absl::conditional_t< std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type, IsDirectInitializationAmbiguous<T, absl::remove_cvref_t<U>>> { … }; IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>; // Checks against the constraints of the direction initialization, i.e. when // `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution. IsDirectInitializationValid; // This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which // is equivalent to whether all the following conditions are met: // 1. `U` is `StatusOr<V>`. // 2. `T` is constructible and assignable from `V`. // 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`). // For example, the following code is considered ambiguous: // (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`) // StatusOr<bool> s1 = true; // s1.ok() && s1.ValueOrDie() == true // StatusOr<bool> s2 = false; // s2.ok() && s2.ValueOrDie() == false // s1 = s2; // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`? template <typename T, typename U> struct IsForwardingAssignmentAmbiguous : public absl::conditional_t< std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type, IsForwardingAssignmentAmbiguous<T, absl::remove_cvref_t<U>>> { … }; IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>>; // Checks against the constraints of the forwarding assignment, i.e. whether // `StatusOr<T>::operator(U&&)` should participate in overload resolution. IsForwardingAssignmentValid; Equality; IsConstructionValid; IsAssignmentValid; IsConstructionFromStatusValid; IsConstructionFromStatusOrValid; IsStatusOrAssignmentValid; class Helper { … }; // Construct an instance of T in `p` through placement new, passing Args... to // the constructor. // This abstraction is here mostly for the gcc performance fix. template <typename T, typename... Args> ABSL_ATTRIBUTE_NONNULL(1) void PlacementNew(absl::Nonnull<void*> p, Args&&... args) { … } // Helper base class to hold the data and all operations. // We move all this to a base class to allow mixing with the appropriate // TraitsBase specialization. template <typename T> class StatusOrData { … }; // Helper base classes to allow implicitly deleted constructors and assignment // operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete // the copy constructor when T is not copy constructible and `StatusOr` will // inherit that behavior implicitly. template <typename T, bool = std::is_copy_constructible<T>::value> struct CopyCtorBase { … }; CopyCtorBase<T, false>; template <typename T, bool = std::is_move_constructible<T>::value> struct MoveCtorBase { … }; MoveCtorBase<T, false>; template <typename T, bool = std::is_copy_constructible<T>::value&& std::is_copy_assignable<T>::value> struct CopyAssignBase { … }; CopyAssignBase<T, false>; template <typename T, bool = std::is_move_constructible<T>::value&& std::is_move_assignable<T>::value> struct MoveAssignBase { … }; MoveAssignBase<T, false>; [[noreturn]] void ThrowBadStatusOrAccess(absl::Status status); // Used to introduce jitter into the output of printing functions for // `StatusOr` (i.e. `AbslStringify` and `operator<<`). class StringifyRandom { … }; } // namespace internal_statusor ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_