tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

statusor_internal.h (17066B)


      1 // Copyright 2020 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_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
     15 #define ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
     16 
     17 #include <cstdint>
     18 #include <type_traits>
     19 #include <utility>
     20 
     21 #include "absl/base/attributes.h"
     22 #include "absl/base/nullability.h"
     23 #include "absl/meta/type_traits.h"
     24 #include "absl/status/status.h"
     25 #include "absl/strings/string_view.h"
     26 #include "absl/utility/utility.h"
     27 
     28 namespace absl {
     29 ABSL_NAMESPACE_BEGIN
     30 
     31 template <typename T>
     32 class ABSL_MUST_USE_RESULT StatusOr;
     33 
     34 namespace internal_statusor {
     35 
     36 // Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator
     37 // StatusOr<T>()`.
     38 template <typename T, typename U, typename = void>
     39 struct HasConversionOperatorToStatusOr : std::false_type {};
     40 
     41 template <typename T, typename U>
     42 void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]);
     43 
     44 template <typename T, typename U>
     45 struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
     46    : std::true_type {};
     47 
     48 // Detects whether `T` is constructible or convertible from `StatusOr<U>`.
     49 template <typename T, typename U>
     50 using IsConstructibleOrConvertibleFromStatusOr =
     51    absl::disjunction<std::is_constructible<T, StatusOr<U>&>,
     52                      std::is_constructible<T, const StatusOr<U>&>,
     53                      std::is_constructible<T, StatusOr<U>&&>,
     54                      std::is_constructible<T, const StatusOr<U>&&>,
     55                      std::is_convertible<StatusOr<U>&, T>,
     56                      std::is_convertible<const StatusOr<U>&, T>,
     57                      std::is_convertible<StatusOr<U>&&, T>,
     58                      std::is_convertible<const StatusOr<U>&&, T>>;
     59 
     60 // Detects whether `T` is constructible or convertible or assignable from
     61 // `StatusOr<U>`.
     62 template <typename T, typename U>
     63 using IsConstructibleOrConvertibleOrAssignableFromStatusOr =
     64    absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>,
     65                      std::is_assignable<T&, StatusOr<U>&>,
     66                      std::is_assignable<T&, const StatusOr<U>&>,
     67                      std::is_assignable<T&, StatusOr<U>&&>,
     68                      std::is_assignable<T&, const StatusOr<U>&&>>;
     69 
     70 // Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e.
     71 // when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`.
     72 template <typename T, typename U>
     73 struct IsDirectInitializationAmbiguous
     74    : public absl::conditional_t<
     75          std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type,
     76          IsDirectInitializationAmbiguous<T, absl::remove_cvref_t<U>>> {};
     77 
     78 template <typename T, typename V>
     79 struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>
     80    : public IsConstructibleOrConvertibleFromStatusOr<T, V> {};
     81 
     82 // Checks against the constraints of the direction initialization, i.e. when
     83 // `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution.
     84 template <typename T, typename U>
     85 using IsDirectInitializationValid = absl::disjunction<
     86    // Short circuits if T is basically U.
     87    std::is_same<T, absl::remove_cvref_t<U>>,
     88    absl::negation<absl::disjunction<
     89        std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
     90        std::is_same<absl::Status, absl::remove_cvref_t<U>>,
     91        std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
     92        IsDirectInitializationAmbiguous<T, U>>>>;
     93 
     94 // This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which
     95 // is equivalent to whether all the following conditions are met:
     96 // 1. `U` is `StatusOr<V>`.
     97 // 2. `T` is constructible and assignable from `V`.
     98 // 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`).
     99 // For example, the following code is considered ambiguous:
    100 // (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`)
    101 //   StatusOr<bool> s1 = true;  // s1.ok() && s1.ValueOrDie() == true
    102 //   StatusOr<bool> s2 = false;  // s2.ok() && s2.ValueOrDie() == false
    103 //   s1 = s2;  // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`?
    104 template <typename T, typename U>
    105 struct IsForwardingAssignmentAmbiguous
    106    : public absl::conditional_t<
    107          std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type,
    108          IsForwardingAssignmentAmbiguous<T, absl::remove_cvref_t<U>>> {};
    109 
    110 template <typename T, typename U>
    111 struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>>
    112    : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {};
    113 
    114 // Checks against the constraints of the forwarding assignment, i.e. whether
    115 // `StatusOr<T>::operator(U&&)` should participate in overload resolution.
    116 template <typename T, typename U>
    117 using IsForwardingAssignmentValid = absl::disjunction<
    118    // Short circuits if T is basically U.
    119    std::is_same<T, absl::remove_cvref_t<U>>,
    120    absl::negation<absl::disjunction<
    121        std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
    122        std::is_same<absl::Status, absl::remove_cvref_t<U>>,
    123        std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
    124        IsForwardingAssignmentAmbiguous<T, U>>>>;
    125 
    126 template <bool Value, typename T>
    127 using Equality = std::conditional_t<Value, T, absl::negation<T>>;
    128 
    129 template <bool Explicit, typename T, typename U, bool Lifetimebound>
    130 using IsConstructionValid = absl::conjunction<
    131    Equality<Lifetimebound,
    132             type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
    133    IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>,
    134    Equality<!Explicit, std::is_convertible<U&&, T>>,
    135    absl::disjunction<
    136        std::is_same<T, absl::remove_cvref_t<U>>,
    137        absl::conjunction<
    138            std::conditional_t<
    139                Explicit,
    140                absl::negation<std::is_constructible<absl::Status, U&&>>,
    141                absl::negation<std::is_convertible<U&&, absl::Status>>>,
    142            absl::negation<
    143                internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>;
    144 
    145 template <typename T, typename U, bool Lifetimebound>
    146 using IsAssignmentValid = absl::conjunction<
    147    Equality<Lifetimebound,
    148             type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
    149    std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
    150    absl::disjunction<
    151        std::is_same<T, absl::remove_cvref_t<U>>,
    152        absl::conjunction<
    153            absl::negation<std::is_convertible<U&&, absl::Status>>,
    154            absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>,
    155    IsForwardingAssignmentValid<T, U&&>>;
    156 
    157 template <bool Explicit, typename T, typename U>
    158 using IsConstructionFromStatusValid = absl::conjunction<
    159    absl::negation<std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>>,
    160    absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
    161    absl::negation<std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>>,
    162    Equality<!Explicit, std::is_convertible<U, absl::Status>>,
    163    std::is_constructible<absl::Status, U>,
    164    absl::negation<HasConversionOperatorToStatusOr<T, U>>>;
    165 
    166 template <bool Explicit, typename T, typename U, bool Lifetimebound,
    167          typename UQ>
    168 using IsConstructionFromStatusOrValid = absl::conjunction<
    169    absl::negation<std::is_same<T, U>>,
    170    Equality<Lifetimebound,
    171             type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
    172    std::is_constructible<T, UQ>,
    173    Equality<!Explicit, std::is_convertible<UQ, T>>,
    174    absl::negation<IsConstructibleOrConvertibleFromStatusOr<T, U>>>;
    175 
    176 template <typename T, typename U, bool Lifetimebound>
    177 using IsStatusOrAssignmentValid = absl::conjunction<
    178    absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
    179    Equality<Lifetimebound,
    180             type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
    181    std::is_constructible<T, U>, std::is_assignable<T, U>,
    182    absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr<
    183        T, absl::remove_cvref_t<U>>>>;
    184 
    185 class Helper {
    186 public:
    187  // Move type-agnostic error handling to the .cc.
    188  static void HandleInvalidStatusCtorArg(absl::Nonnull<Status*>);
    189  [[noreturn]] static void Crash(const absl::Status& status);
    190 };
    191 
    192 // Construct an instance of T in `p` through placement new, passing Args... to
    193 // the constructor.
    194 // This abstraction is here mostly for the gcc performance fix.
    195 template <typename T, typename... Args>
    196 ABSL_ATTRIBUTE_NONNULL(1)
    197 void PlacementNew(absl::Nonnull<void*> p, Args&&... args) {
    198  new (p) T(std::forward<Args>(args)...);
    199 }
    200 
    201 // Helper base class to hold the data and all operations.
    202 // We move all this to a base class to allow mixing with the appropriate
    203 // TraitsBase specialization.
    204 template <typename T>
    205 class StatusOrData {
    206  template <typename U>
    207  friend class StatusOrData;
    208 
    209 public:
    210  StatusOrData() = delete;
    211 
    212  StatusOrData(const StatusOrData& other) {
    213    if (other.ok()) {
    214      MakeValue(other.data_);
    215      MakeStatus();
    216    } else {
    217      MakeStatus(other.status_);
    218    }
    219  }
    220 
    221  StatusOrData(StatusOrData&& other) noexcept {
    222    if (other.ok()) {
    223      MakeValue(std::move(other.data_));
    224      MakeStatus();
    225    } else {
    226      MakeStatus(std::move(other.status_));
    227    }
    228  }
    229 
    230  template <typename U>
    231  explicit StatusOrData(const StatusOrData<U>& other) {
    232    if (other.ok()) {
    233      MakeValue(other.data_);
    234      MakeStatus();
    235    } else {
    236      MakeStatus(other.status_);
    237    }
    238  }
    239 
    240  template <typename U>
    241  explicit StatusOrData(StatusOrData<U>&& other) {
    242    if (other.ok()) {
    243      MakeValue(std::move(other.data_));
    244      MakeStatus();
    245    } else {
    246      MakeStatus(std::move(other.status_));
    247    }
    248  }
    249 
    250  template <typename... Args>
    251  explicit StatusOrData(absl::in_place_t, Args&&... args)
    252      : data_(std::forward<Args>(args)...) {
    253    MakeStatus();
    254  }
    255 
    256  explicit StatusOrData(const T& value) : data_(value) {
    257    MakeStatus();
    258  }
    259  explicit StatusOrData(T&& value) : data_(std::move(value)) {
    260    MakeStatus();
    261  }
    262 
    263  template <typename U,
    264            absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value,
    265                              int> = 0>
    266  explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) {
    267    EnsureNotOk();
    268  }
    269 
    270  StatusOrData& operator=(const StatusOrData& other) {
    271    if (this == &other) return *this;
    272    if (other.ok())
    273      Assign(other.data_);
    274    else
    275      AssignStatus(other.status_);
    276    return *this;
    277  }
    278 
    279  StatusOrData& operator=(StatusOrData&& other) {
    280    if (this == &other) return *this;
    281    if (other.ok())
    282      Assign(std::move(other.data_));
    283    else
    284      AssignStatus(std::move(other.status_));
    285    return *this;
    286  }
    287 
    288  ~StatusOrData() {
    289    if (ok()) {
    290      status_.~Status();
    291      data_.~T();
    292    } else {
    293      status_.~Status();
    294    }
    295  }
    296 
    297  template <typename U>
    298  void Assign(U&& value) {
    299    if (ok()) {
    300      data_ = std::forward<U>(value);
    301    } else {
    302      MakeValue(std::forward<U>(value));
    303      status_ = OkStatus();
    304    }
    305  }
    306 
    307  template <typename U>
    308  void AssignStatus(U&& v) {
    309    Clear();
    310    status_ = static_cast<absl::Status>(std::forward<U>(v));
    311    EnsureNotOk();
    312  }
    313 
    314  bool ok() const { return status_.ok(); }
    315 
    316 protected:
    317  // status_ will always be active after the constructor.
    318  // We make it a union to be able to initialize exactly how we need without
    319  // waste.
    320  // Eg. in the copy constructor we use the default constructor of Status in
    321  // the ok() path to avoid an extra Ref call.
    322  union {
    323    Status status_;
    324  };
    325 
    326  // data_ is active iff status_.ok()==true
    327  struct Dummy {};
    328  union {
    329    // When T is const, we need some non-const object we can cast to void* for
    330    // the placement new. dummy_ is that object.
    331    Dummy dummy_;
    332    T data_;
    333  };
    334 
    335  void Clear() {
    336    if (ok()) data_.~T();
    337  }
    338 
    339  void EnsureOk() const {
    340    if (ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_);
    341  }
    342 
    343  void EnsureNotOk() {
    344    if (ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_);
    345  }
    346 
    347  // Construct the value (ie. data_) through placement new with the passed
    348  // argument.
    349  template <typename... Arg>
    350  void MakeValue(Arg&&... arg) {
    351    internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...);
    352  }
    353 
    354  // Construct the status (ie. status_) through placement new with the passed
    355  // argument.
    356  template <typename... Args>
    357  void MakeStatus(Args&&... args) {
    358    internal_statusor::PlacementNew<Status>(&status_,
    359                                            std::forward<Args>(args)...);
    360  }
    361 };
    362 
    363 // Helper base classes to allow implicitly deleted constructors and assignment
    364 // operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete
    365 // the copy constructor when T is not copy constructible and `StatusOr` will
    366 // inherit that behavior implicitly.
    367 template <typename T, bool = std::is_copy_constructible<T>::value>
    368 struct CopyCtorBase {
    369  CopyCtorBase() = default;
    370  CopyCtorBase(const CopyCtorBase&) = default;
    371  CopyCtorBase(CopyCtorBase&&) = default;
    372  CopyCtorBase& operator=(const CopyCtorBase&) = default;
    373  CopyCtorBase& operator=(CopyCtorBase&&) = default;
    374 };
    375 
    376 template <typename T>
    377 struct CopyCtorBase<T, false> {
    378  CopyCtorBase() = default;
    379  CopyCtorBase(const CopyCtorBase&) = delete;
    380  CopyCtorBase(CopyCtorBase&&) = default;
    381  CopyCtorBase& operator=(const CopyCtorBase&) = default;
    382  CopyCtorBase& operator=(CopyCtorBase&&) = default;
    383 };
    384 
    385 template <typename T, bool = std::is_move_constructible<T>::value>
    386 struct MoveCtorBase {
    387  MoveCtorBase() = default;
    388  MoveCtorBase(const MoveCtorBase&) = default;
    389  MoveCtorBase(MoveCtorBase&&) = default;
    390  MoveCtorBase& operator=(const MoveCtorBase&) = default;
    391  MoveCtorBase& operator=(MoveCtorBase&&) = default;
    392 };
    393 
    394 template <typename T>
    395 struct MoveCtorBase<T, false> {
    396  MoveCtorBase() = default;
    397  MoveCtorBase(const MoveCtorBase&) = default;
    398  MoveCtorBase(MoveCtorBase&&) = delete;
    399  MoveCtorBase& operator=(const MoveCtorBase&) = default;
    400  MoveCtorBase& operator=(MoveCtorBase&&) = default;
    401 };
    402 
    403 template <typename T, bool = std::is_copy_constructible<T>::value&&
    404                          std::is_copy_assignable<T>::value>
    405 struct CopyAssignBase {
    406  CopyAssignBase() = default;
    407  CopyAssignBase(const CopyAssignBase&) = default;
    408  CopyAssignBase(CopyAssignBase&&) = default;
    409  CopyAssignBase& operator=(const CopyAssignBase&) = default;
    410  CopyAssignBase& operator=(CopyAssignBase&&) = default;
    411 };
    412 
    413 template <typename T>
    414 struct CopyAssignBase<T, false> {
    415  CopyAssignBase() = default;
    416  CopyAssignBase(const CopyAssignBase&) = default;
    417  CopyAssignBase(CopyAssignBase&&) = default;
    418  CopyAssignBase& operator=(const CopyAssignBase&) = delete;
    419  CopyAssignBase& operator=(CopyAssignBase&&) = default;
    420 };
    421 
    422 template <typename T, bool = std::is_move_constructible<T>::value&&
    423                          std::is_move_assignable<T>::value>
    424 struct MoveAssignBase {
    425  MoveAssignBase() = default;
    426  MoveAssignBase(const MoveAssignBase&) = default;
    427  MoveAssignBase(MoveAssignBase&&) = default;
    428  MoveAssignBase& operator=(const MoveAssignBase&) = default;
    429  MoveAssignBase& operator=(MoveAssignBase&&) = default;
    430 };
    431 
    432 template <typename T>
    433 struct MoveAssignBase<T, false> {
    434  MoveAssignBase() = default;
    435  MoveAssignBase(const MoveAssignBase&) = default;
    436  MoveAssignBase(MoveAssignBase&&) = default;
    437  MoveAssignBase& operator=(const MoveAssignBase&) = default;
    438  MoveAssignBase& operator=(MoveAssignBase&&) = delete;
    439 };
    440 
    441 [[noreturn]] void ThrowBadStatusOrAccess(absl::Status status);
    442 
    443 // Used to introduce jitter into the output of printing functions for
    444 // `StatusOr` (i.e. `AbslStringify` and `operator<<`).
    445 class StringifyRandom {
    446  enum BracesType {
    447    kBareParens = 0,
    448    kSpaceParens,
    449    kBareBrackets,
    450    kSpaceBrackets,
    451  };
    452 
    453  // Returns a random `BracesType` determined once per binary load.
    454  static BracesType RandomBraces() {
    455    static const BracesType kRandomBraces = static_cast<BracesType>(
    456        (reinterpret_cast<uintptr_t>(&kRandomBraces) >> 4) % 4);
    457    return kRandomBraces;
    458  }
    459 
    460 public:
    461  static inline absl::string_view OpenBrackets() {
    462    switch (RandomBraces()) {
    463      case kBareParens:
    464        return "(";
    465      case kSpaceParens:
    466        return "( ";
    467      case kBareBrackets:
    468        return "[";
    469      case kSpaceBrackets:
    470        return "[ ";
    471    }
    472    return "(";
    473  }
    474 
    475  static inline absl::string_view CloseBrackets() {
    476    switch (RandomBraces()) {
    477      case kBareParens:
    478        return ")";
    479      case kSpaceParens:
    480        return " )";
    481      case kBareBrackets:
    482        return "]";
    483      case kSpaceBrackets:
    484        return " ]";
    485    }
    486    return ")";
    487  }
    488 };
    489 
    490 }  // namespace internal_statusor
    491 ABSL_NAMESPACE_END
    492 }  // namespace absl
    493 
    494 #endif  // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_