Coverage Report

Created: 2026-05-30 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/abseil-cpp/absl/status/internal/statusor_internal.h
Line
Count
Source
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
33
    StatusOr;
34
35
namespace internal_statusor {
36
37
// Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator
38
// StatusOr<T>()`.
39
template <typename T, typename U, typename = void>
40
struct HasConversionOperatorToStatusOr : std::false_type {};
41
42
template <typename T, typename U>
43
void test(char (*absl_nullable)[sizeof(
44
    std::declval<U>().operator absl::StatusOr<T>())]);
45
46
template <typename T, typename U>
47
struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
48
    : std::true_type {};
49
50
// Detects whether `T` is equality-comparable.
51
template <typename T, typename = void>
52
struct IsEqualityComparable : std::false_type {};
53
54
template <typename T>
55
struct IsEqualityComparable<
56
    T, std::enable_if_t<std::is_convertible<
57
           decltype(std::declval<T>() == std::declval<T>()),
58
           bool>::value>> : std::true_type {};
59
60
// Detects whether `T` is constructible or convertible from `StatusOr<U>`.
61
template <typename T, typename U>
62
using IsConstructibleOrConvertibleFromStatusOr =
63
    absl::disjunction<std::is_constructible<T, StatusOr<U>&>,
64
                      std::is_constructible<T, const StatusOr<U>&>,
65
                      std::is_constructible<T, StatusOr<U>&&>,
66
                      std::is_constructible<T, const StatusOr<U>&&>,
67
                      std::is_convertible<StatusOr<U>&, T>,
68
                      std::is_convertible<const StatusOr<U>&, T>,
69
                      std::is_convertible<StatusOr<U>&&, T>,
70
                      std::is_convertible<const StatusOr<U>&&, T>>;
71
72
// Detects whether `T` is constructible or convertible or assignable from
73
// `StatusOr<U>`.
74
template <typename T, typename U>
75
using IsConstructibleOrConvertibleOrAssignableFromStatusOr =
76
    absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>,
77
                      std::is_assignable<T&, StatusOr<U>&>,
78
                      std::is_assignable<T&, const StatusOr<U>&>,
79
                      std::is_assignable<T&, StatusOr<U>&&>,
80
                      std::is_assignable<T&, const StatusOr<U>&&>>;
81
82
// Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e.
83
// when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`.
84
template <typename T, typename U>
85
struct IsDirectInitializationAmbiguous
86
    : public absl::conditional_t<
87
          std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type,
88
          IsDirectInitializationAmbiguous<T, absl::remove_cvref_t<U>>> {};
89
90
template <typename T, typename V>
91
struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>
92
    : public IsConstructibleOrConvertibleFromStatusOr<T, V> {};
93
94
// Checks whether the conversion from U to T can be done without dangling
95
// temporaries.
96
// REQUIRES: T and U are references.
97
template <typename T, typename U>
98
using IsReferenceConversionValid = absl::conjunction<  //
99
    std::is_reference<T>, std::is_reference<U>,
100
    // The references are convertible. This checks for
101
    // lvalue/rvalue compatibility.
102
    std::is_convertible<U, T>,
103
    // The pointers are convertible. This checks we don't have
104
    // a temporary.
105
    std::is_convertible<std::remove_reference_t<U>*,
106
                        std::remove_reference_t<T>*>>;
107
108
// Checks against the constraints of the direction initialization, i.e. when
109
// `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution.
110
template <typename T, typename U>
111
using IsDirectInitializationValid = absl::disjunction<
112
    // Short circuits if T is basically U.
113
    std::is_same<T, absl::remove_cvref_t<U>>,  //
114
    std::conditional_t<
115
        std::is_reference_v<T>,  //
116
        IsReferenceConversionValid<T, U>,
117
        absl::negation<absl::disjunction<
118
            std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
119
            std::is_same<absl::Status, absl::remove_cvref_t<U>>,
120
            std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
121
            IsDirectInitializationAmbiguous<T, U>>>>>;
122
123
// This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which
124
// is equivalent to whether all the following conditions are met:
125
// 1. `U` is `StatusOr<V>`.
126
// 2. `T` is constructible and assignable from `V`.
127
// 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`).
128
// For example, the following code is considered ambiguous:
129
// (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`)
130
//   StatusOr<bool> s1 = true;  // s1.ok() && s1.ValueOrDie() == true
131
//   StatusOr<bool> s2 = false;  // s2.ok() && s2.ValueOrDie() == false
132
//   s1 = s2;  // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`?
133
template <typename T, typename U>
134
struct IsForwardingAssignmentAmbiguous
135
    : public absl::conditional_t<
136
          std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type,
137
          IsForwardingAssignmentAmbiguous<T, absl::remove_cvref_t<U>>> {};
138
139
template <typename T, typename U>
140
struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>>
141
    : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {};
142
143
// Checks against the constraints of the forwarding assignment, i.e. whether
144
// `StatusOr<T>::operator(U&&)` should participate in overload resolution.
145
template <typename T, typename U>
146
using IsForwardingAssignmentValid = absl::disjunction<
147
    // Short circuits if T is basically U.
148
    std::is_same<T, absl::remove_cvref_t<U>>,
149
    absl::negation<absl::disjunction<
150
        std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
151
        std::is_same<absl::Status, absl::remove_cvref_t<U>>,
152
        std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
153
        IsForwardingAssignmentAmbiguous<T, U>>>>;
154
155
template <bool Value, typename T>
156
using Equality = std::conditional_t<Value, T, absl::negation<T>>;
157
158
template <bool Explicit, typename T, typename U, bool Lifetimebound>
159
using IsConstructionValid = absl::conjunction<
160
    Equality<Lifetimebound,
161
             absl::disjunction<
162
                 std::is_reference<T>,
163
                 type_traits_internal::IsLifetimeBoundAssignment<T, U>>>,
164
    IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>,
165
    Equality<!Explicit, std::is_convertible<U&&, T>>,
166
    absl::disjunction<
167
        std::is_same<T, absl::remove_cvref_t<U>>,
168
        absl::conjunction<
169
            std::conditional_t<
170
                Explicit,
171
                absl::negation<std::is_constructible<absl::Status, U&&>>,
172
                absl::negation<std::is_convertible<U&&, absl::Status>>>,
173
            absl::negation<
174
                internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>;
175
176
template <typename T, typename U, bool Lifetimebound>
177
using IsAssignmentValid = absl::conjunction<
178
    Equality<Lifetimebound,
179
             absl::disjunction<
180
                 std::is_reference<T>,
181
                 type_traits_internal::IsLifetimeBoundAssignment<T, U>>>,
182
    std::conditional_t<std::is_reference_v<T>,
183
                       IsReferenceConversionValid<T, U&&>,
184
                       absl::conjunction<std::is_constructible<T, U&&>,
185
                                         std::is_assignable<T&, U&&>>>,
186
    absl::disjunction<
187
        std::is_same<T, absl::remove_cvref_t<U>>,
188
        absl::conjunction<
189
            absl::negation<std::is_convertible<U&&, absl::Status>>,
190
            absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>,
191
    IsForwardingAssignmentValid<T, U&&>>;
192
193
template <bool Explicit, typename T, typename U>
194
using IsConstructionFromStatusValid = absl::conjunction<
195
    absl::negation<std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>>,
196
    absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
197
    absl::negation<std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>>,
198
    Equality<!Explicit, std::is_convertible<U, absl::Status>>,
199
    std::is_constructible<absl::Status, U>,
200
    absl::negation<HasConversionOperatorToStatusOr<T, U>>>;
201
202
template <bool Explicit, typename T, typename U, bool Lifetimebound,
203
          typename UQ>
204
using IsConstructionFromStatusOrValid = absl::conjunction<
205
    absl::negation<std::is_same<T, U>>,
206
    // If `T` is a reference, then U must be a compatible one.
207
    absl::disjunction<absl::negation<std::is_reference<T>>,
208
                      IsReferenceConversionValid<T, U>>,
209
    Equality<Lifetimebound,
210
             type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
211
    std::is_constructible<T, UQ>,
212
    Equality<!Explicit, std::is_convertible<UQ, T>>,
213
    absl::negation<IsConstructibleOrConvertibleFromStatusOr<T, U>>>;
214
215
template <typename T, typename U, bool Lifetimebound>
216
using IsStatusOrAssignmentValid = absl::conjunction<
217
    absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
218
    Equality<Lifetimebound,
219
             type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
220
    std::is_constructible<T, U>, std::is_assignable<T, U>,
221
    absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr<
222
        T, absl::remove_cvref_t<U>>>>;
223
224
template <typename T, typename U, bool Lifetimebound>
225
using IsValueOrValid = absl::conjunction<
226
    // If `T` is a reference, then U must be a compatible one.
227
    absl::disjunction<absl::negation<std::is_reference<T>>,
228
                      IsReferenceConversionValid<T, U>>,
229
    Equality<Lifetimebound,
230
             absl::disjunction<
231
                 std::is_reference<T>,
232
                 type_traits_internal::IsLifetimeBoundAssignment<T, U>>>>;
233
234
class Helper {
235
 public:
236
  // Move type-agnostic error handling to the .cc.
237
  static void HandleInvalidStatusCtorArg(Status* absl_nonnull);
238
  [[noreturn]] static void Crash(const absl::Status& status);
239
};
240
241
// Construct an instance of T in `p` through placement new, passing Args... to
242
// the constructor.
243
// This abstraction is here mostly for the gcc performance fix.
244
template <typename T, typename... Args>
245
ABSL_ATTRIBUTE_NONNULL(1)
246
void PlacementNew(void* absl_nonnull p, Args&&... args) {
247
  new (p) T(std::forward<Args>(args)...);
248
}
249
250
template <typename T>
251
class Reference {
252
 public:
253
  constexpr explicit Reference(T ref ABSL_ATTRIBUTE_LIFETIME_BOUND)
254
      : payload_(std::addressof(ref)) {}
255
256
  Reference(const Reference&) = default;
257
  Reference& operator=(const Reference&) = default;
258
  Reference& operator=(T value) {
259
    payload_ = std::addressof(value);
260
    return *this;
261
  }
262
263
  operator T() const { return static_cast<T>(*payload_); }  // NOLINT
264
  T get() const { return *this; }
265
266
 private:
267
  std::remove_reference_t<T>* absl_nonnull payload_;
268
};
269
270
// Helper base class to hold the data and all operations.
271
// We move all this to a base class to allow mixing with the appropriate
272
// TraitsBase specialization.
273
template <typename T>
274
class StatusOrData {
275
  template <typename U>
276
  friend class StatusOrData;
277
278
  decltype(auto) MaybeMoveData() {
279
    if constexpr (std::is_reference_v<T>) {
280
      return data_.get();
281
    } else {
282
      return std::move(data_);
283
    }
284
  }
285
286
 public:
287
  StatusOrData() = delete;
288
289
  StatusOrData(const StatusOrData& other) {
290
    if (other.ok()) {
291
      MakeValue(other.data_);
292
      MakeStatus();
293
    } else {
294
      MakeStatus(other.status_);
295
    }
296
  }
297
298
  StatusOrData(StatusOrData&& other) noexcept {
299
    if (other.ok()) {
300
      MakeValue(other.MaybeMoveData());
301
      MakeStatus();
302
    } else {
303
      MakeStatus(std::move(other.status_));
304
    }
305
  }
306
307
  template <typename U>
308
  explicit StatusOrData(const StatusOrData<U>& other) {
309
    if (other.ok()) {
310
      MakeValue(other.data_);
311
      MakeStatus();
312
    } else {
313
      MakeStatus(other.status_);
314
    }
315
  }
316
317
  template <typename U>
318
  explicit StatusOrData(StatusOrData<U>&& other) {
319
    if (other.ok()) {
320
      MakeValue(other.MaybeMoveData());
321
      MakeStatus();
322
    } else {
323
      MakeStatus(std::move(other.status_));
324
    }
325
  }
326
327
  template <typename... Args>
328
  explicit StatusOrData(absl::in_place_t, Args&&... args)
329
      : data_(std::forward<Args>(args)...) {
330
    MakeStatus();
331
  }
332
333
  template <typename U,
334
            absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value,
335
                              int> = 0>
336
  explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) {
337
    EnsureNotOk();
338
  }
339
340
  StatusOrData& operator=(const StatusOrData& other) {
341
    if (this == &other) return *this;
342
    if (other.ok())
343
      Assign(other.data_);
344
    else
345
      AssignStatus(other.status_);
346
    return *this;
347
  }
348
349
  StatusOrData& operator=(StatusOrData&& other) {
350
    if (this == &other) return *this;
351
    if (other.ok())
352
      Assign(other.MaybeMoveData());
353
    else
354
      AssignStatus(std::move(other.status_));
355
    return *this;
356
  }
357
358
  ~StatusOrData() {
359
    if (ok()) {
360
      status_.~Status();
361
      if constexpr (!std::is_trivially_destructible_v<T>) {
362
        data_.~T();
363
      }
364
    } else {
365
      status_.~Status();
366
    }
367
  }
368
369
  template <typename U>
370
  void Assign(U&& value) {
371
    if (ok()) {
372
      data_ = std::forward<U>(value);
373
    } else {
374
      MakeValue(std::forward<U>(value));
375
      status_ = OkStatus();
376
    }
377
  }
378
379
  template <typename U>
380
  void AssignStatus(U&& v) {
381
    Clear();
382
    status_ = static_cast<absl::Status>(std::forward<U>(v));
383
    EnsureNotOk();
384
  }
385
386
  bool ok() const { return status_.ok(); }
387
388
 protected:
389
  // status_ will always be active after the constructor.
390
  // We make it a union to be able to initialize exactly how we need without
391
  // waste.
392
  // Eg. in the copy constructor we use the default constructor of Status in
393
  // the ok() path to avoid an extra Ref call.
394
  union {
395
    Status status_;
396
  };
397
398
  // data_ is active iff status_.ok()==true
399
  struct Dummy {};
400
  union {
401
    // When T is const, we need some non-const object we can cast to void* for
402
    // the placement new. dummy_ is that object.
403
    Dummy dummy_;
404
    std::conditional_t<std::is_reference_v<T>, Reference<T>, T> data_;
405
  };
406
407
  void Clear() {
408
    if constexpr (!std::is_trivially_destructible_v<T>) {
409
      if (ok()) data_.~T();
410
    }
411
  }
412
413
  void EnsureOk() const {
414
    if (ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_);
415
  }
416
417
  void EnsureNotOk() {
418
    if (ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_);
419
  }
420
421
  // Construct the value (ie. data_) through placement new with the passed
422
  // argument.
423
  template <typename... Arg>
424
  void MakeValue(Arg&&... arg) {
425
    internal_statusor::PlacementNew<decltype(data_)>(&dummy_,
426
                                                     std::forward<Arg>(arg)...);
427
  }
428
429
  // Construct the status (ie. status_) through placement new with the passed
430
  // argument.
431
  template <typename... Args>
432
  void MakeStatus(Args&&... args) {
433
    internal_statusor::PlacementNew<Status>(&status_,
434
                                            std::forward<Args>(args)...);
435
  }
436
437
  template <typename U>
438
  T ValueOrImpl(U&& default_value) const& {
439
    if (ok()) {
440
      return data_;
441
    }
442
    return std::forward<U>(default_value);
443
  }
444
445
  template <typename U>
446
  T ValueOrImpl(U&& default_value) && {
447
    if (ok()) {
448
      return std::move(data_);
449
    }
450
    return std::forward<U>(default_value);
451
  }
452
};
453
454
[[noreturn]] void ThrowBadStatusOrAccess(absl::Status status);
455
456
template <typename T>
457
struct OperatorBase {
458
  auto& self() const { return static_cast<const StatusOr<T>&>(*this); }
459
  auto& self() { return static_cast<StatusOr<T>&>(*this); }
460
461
  const T& operator*() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
462
    self().EnsureOk();
463
    return self().data_;
464
  }
465
  T& operator*() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
466
    self().EnsureOk();
467
    return self().data_;
468
  }
469
  const T&& operator*() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND {
470
    self().EnsureOk();
471
    return std::move(self().data_);
472
  }
473
  T&& operator*() && ABSL_ATTRIBUTE_LIFETIME_BOUND {
474
    self().EnsureOk();
475
    return std::move(self().data_);
476
  }
477
478
  const T& value() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
479
    if (!self().ok()) internal_statusor::ThrowBadStatusOrAccess(self().status_);
480
    return self().data_;
481
  }
482
  T& value() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
483
    if (!self().ok()) internal_statusor::ThrowBadStatusOrAccess(self().status_);
484
    return self().data_;
485
  }
486
  const T&& value() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND {
487
    if (!self().ok()) {
488
      internal_statusor::ThrowBadStatusOrAccess(std::move(self().status_));
489
    }
490
    return std::move(self().data_);
491
  }
492
  T&& value() && ABSL_ATTRIBUTE_LIFETIME_BOUND {
493
    if (!self().ok()) {
494
      internal_statusor::ThrowBadStatusOrAccess(std::move(self().status_));
495
    }
496
    return std::move(self().data_);
497
  }
498
499
  const T* absl_nonnull operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
500
    return std::addressof(**this);
501
  }
502
  T* absl_nonnull operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND {
503
    return std::addressof(**this);
504
  }
505
};
506
507
template <typename T>
508
struct OperatorBase<T&> {
509
  auto& self() const { return static_cast<const StatusOr<T&>&>(*this); }
510
511
  T& operator*() const {
512
    self().EnsureOk();
513
    return self().data_;
514
  }
515
516
  T& value() const {
517
    if (!self().ok()) internal_statusor::ThrowBadStatusOrAccess(self().status_);
518
    return self().data_;
519
  }
520
521
  T* absl_nonnull operator->() const {
522
    return std::addressof(**this);
523
  }
524
};
525
526
// Helper base classes to allow implicitly deleted constructors and assignment
527
// operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete
528
// the copy constructor when T is not copy constructible and `StatusOr` will
529
// inherit that behavior implicitly.
530
template <typename T, bool = std::is_copy_constructible<T>::value>
531
struct CopyCtorBase {
532
  CopyCtorBase() = default;
533
  CopyCtorBase(const CopyCtorBase&) = default;
534
  CopyCtorBase(CopyCtorBase&&) = default;
535
  CopyCtorBase& operator=(const CopyCtorBase&) = default;
536
  CopyCtorBase& operator=(CopyCtorBase&&) = default;
537
};
538
539
template <typename T>
540
struct CopyCtorBase<T, false> {
541
  CopyCtorBase() = default;
542
  CopyCtorBase(const CopyCtorBase&) = delete;
543
  CopyCtorBase(CopyCtorBase&&) = default;
544
  CopyCtorBase& operator=(const CopyCtorBase&) = default;
545
  CopyCtorBase& operator=(CopyCtorBase&&) = default;
546
};
547
548
template <typename T, bool = std::is_move_constructible<T>::value>
549
struct MoveCtorBase {
550
  MoveCtorBase() = default;
551
  MoveCtorBase(const MoveCtorBase&) = default;
552
  MoveCtorBase(MoveCtorBase&&) = default;
553
  MoveCtorBase& operator=(const MoveCtorBase&) = default;
554
  MoveCtorBase& operator=(MoveCtorBase&&) = default;
555
};
556
557
template <typename T>
558
struct MoveCtorBase<T, false> {
559
  MoveCtorBase() = default;
560
  MoveCtorBase(const MoveCtorBase&) = default;
561
  MoveCtorBase(MoveCtorBase&&) = delete;
562
  MoveCtorBase& operator=(const MoveCtorBase&) = default;
563
  MoveCtorBase& operator=(MoveCtorBase&&) = default;
564
};
565
566
template <typename T, bool = (std::is_copy_constructible<T>::value &&
567
                              std::is_copy_assignable<T>::value) ||
568
                             std::is_reference_v<T>>
569
struct CopyAssignBase {
570
  CopyAssignBase() = default;
571
  CopyAssignBase(const CopyAssignBase&) = default;
572
  CopyAssignBase(CopyAssignBase&&) = default;
573
  CopyAssignBase& operator=(const CopyAssignBase&) = default;
574
  CopyAssignBase& operator=(CopyAssignBase&&) = default;
575
};
576
577
template <typename T>
578
struct CopyAssignBase<T, false> {
579
  CopyAssignBase() = default;
580
  CopyAssignBase(const CopyAssignBase&) = default;
581
  CopyAssignBase(CopyAssignBase&&) = default;
582
  CopyAssignBase& operator=(const CopyAssignBase&) = delete;
583
  CopyAssignBase& operator=(CopyAssignBase&&) = default;
584
};
585
586
template <typename T, bool = (std::is_move_constructible<T>::value &&
587
                              std::is_move_assignable<T>::value) ||
588
                             std::is_reference_v<T>>
589
struct MoveAssignBase {
590
  MoveAssignBase() = default;
591
  MoveAssignBase(const MoveAssignBase&) = default;
592
  MoveAssignBase(MoveAssignBase&&) = default;
593
  MoveAssignBase& operator=(const MoveAssignBase&) = default;
594
  MoveAssignBase& operator=(MoveAssignBase&&) = default;
595
};
596
597
template <typename T>
598
struct MoveAssignBase<T, false> {
599
  MoveAssignBase() = default;
600
  MoveAssignBase(const MoveAssignBase&) = default;
601
  MoveAssignBase(MoveAssignBase&&) = default;
602
  MoveAssignBase& operator=(const MoveAssignBase&) = default;
603
  MoveAssignBase& operator=(MoveAssignBase&&) = delete;
604
};
605
606
// Used to introduce jitter into the output of printing functions for
607
// `StatusOr` (i.e. `AbslStringify` and `operator<<`).
608
class StringifyRandom {
609
  enum BracesType {
610
    kBareParens = 0,
611
    kSpaceParens,
612
    kBareBrackets,
613
    kSpaceBrackets,
614
  };
615
616
  // Returns a random `BracesType` determined once per binary load.
617
0
  static BracesType RandomBraces() {
618
0
    static const BracesType kRandomBraces = static_cast<BracesType>(
619
0
        (reinterpret_cast<uintptr_t>(&kRandomBraces) >> 4) % 4);
620
0
    return kRandomBraces;
621
0
  }
622
623
 public:
624
0
  static inline absl::string_view OpenBrackets() {
625
0
    switch (RandomBraces()) {
626
0
      case kBareParens:
627
0
        return "(";
628
0
      case kSpaceParens:
629
0
        return "( ";
630
0
      case kBareBrackets:
631
0
        return "[";
632
0
      case kSpaceBrackets:
633
0
        return "[ ";
634
0
    }
635
0
    return "(";
636
0
  }
637
638
0
  static inline absl::string_view CloseBrackets() {
639
0
    switch (RandomBraces()) {
640
0
      case kBareParens:
641
0
        return ")";
642
0
      case kSpaceParens:
643
0
        return " )";
644
0
      case kBareBrackets:
645
0
        return "]";
646
0
      case kSpaceBrackets:
647
0
        return " ]";
648
0
    }
649
0
    return ")";
650
0
  }
651
};
652
653
}  // namespace internal_statusor
654
ABSL_NAMESPACE_END
655
}  // namespace absl
656
657
#endif  // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_