@@ -90,17 +90,34 @@ template <typename T, typename V>
9090struct IsDirectInitializationAmbiguous <T, absl::StatusOr<V>>
9191 : public IsConstructibleOrConvertibleFromStatusOr<T, V> {};
9292
93+ // Checks whether the conversion from U to T can be done without dangling
94+ // temporaries.
95+ // REQUIRES: T and U are references.
96+ template <typename T, typename U>
97+ using IsReferenceConversionValid = absl::conjunction< //
98+ std::is_reference<T>, std::is_reference<U>,
99+ // The references are convertible. This checks for
100+ // lvalue/rvalue compatibility.
101+ std::is_convertible<U, T>,
102+ // The pointers are convertible. This checks we don't have
103+ // a temporary.
104+ std::is_convertible<std::remove_reference_t <U>*,
105+ std::remove_reference_t <T>*>>;
106+
93107// Checks against the constraints of the direction initialization, i.e. when
94108// `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution.
95109template <typename T, typename U>
96110using IsDirectInitializationValid = absl::disjunction<
97111 // Short circuits if T is basically U.
98- std::is_same<T, absl::remove_cvref_t <U>>,
99- absl::negation<absl::disjunction<
100- std::is_same<absl::StatusOr<T>, absl::remove_cvref_t <U>>,
101- std::is_same<absl::Status, absl::remove_cvref_t <U>>,
102- std::is_same<absl::in_place_t , absl::remove_cvref_t <U>>,
103- IsDirectInitializationAmbiguous<T, U>>>>;
112+ std::is_same<T, absl::remove_cvref_t <U>>, //
113+ std::conditional_t <
114+ std::is_reference_v<T>, //
115+ IsReferenceConversionValid<T, U>,
116+ absl::negation<absl::disjunction<
117+ std::is_same<absl::StatusOr<T>, absl::remove_cvref_t <U>>,
118+ std::is_same<absl::Status, absl::remove_cvref_t <U>>,
119+ std::is_same<absl::in_place_t , absl::remove_cvref_t <U>>,
120+ IsDirectInitializationAmbiguous<T, U>>>>>;
104121
105122// This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which
106123// is equivalent to whether all the following conditions are met:
@@ -140,7 +157,9 @@ using Equality = std::conditional_t<Value, T, absl::negation<T>>;
140157template <bool Explicit, typename T, typename U, bool Lifetimebound>
141158using IsConstructionValid = absl::conjunction<
142159 Equality<Lifetimebound,
143- type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
160+ absl::disjunction<
161+ std::is_reference<T>,
162+ type_traits_internal::IsLifetimeBoundAssignment<T, U>>>,
144163 IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>,
145164 Equality<!Explicit, std::is_convertible<U&&, T>>,
146165 absl::disjunction<
@@ -156,8 +175,13 @@ using IsConstructionValid = absl::conjunction<
156175template <typename T, typename U, bool Lifetimebound>
157176using IsAssignmentValid = absl::conjunction<
158177 Equality<Lifetimebound,
159- type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
160- std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
178+ absl::disjunction<
179+ std::is_reference<T>,
180+ type_traits_internal::IsLifetimeBoundAssignment<T, U>>>,
181+ std::conditional_t <std::is_reference_v<T>,
182+ IsReferenceConversionValid<T, U&&>,
183+ absl::conjunction<std::is_constructible<T, U&&>,
184+ std::is_assignable<T&, U&&>>>,
161185 absl::disjunction<
162186 std::is_same<T, absl::remove_cvref_t <U>>,
163187 absl::conjunction<
@@ -178,6 +202,9 @@ template <bool Explicit, typename T, typename U, bool Lifetimebound,
178202 typename UQ>
179203using IsConstructionFromStatusOrValid = absl::conjunction<
180204 absl::negation<std::is_same<T, U>>,
205+ // If `T` is a reference, then U must be a compatible one.
206+ absl::disjunction<absl::negation<std::is_reference<T>>,
207+ IsReferenceConversionValid<T, U>>,
181208 Equality<Lifetimebound,
182209 type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
183210 std::is_constructible<T, UQ>,
@@ -193,6 +220,16 @@ using IsStatusOrAssignmentValid = absl::conjunction<
193220 absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr<
194221 T, absl::remove_cvref_t <U>>>>;
195222
223+ template <typename T, typename U, bool Lifetimebound>
224+ using IsValueOrValid = absl::conjunction<
225+ // If `T` is a reference, then U must be a compatible one.
226+ absl::disjunction<absl::negation<std::is_reference<T>>,
227+ IsReferenceConversionValid<T, U>>,
228+ Equality<Lifetimebound,
229+ absl::disjunction<
230+ std::is_reference<T>,
231+ type_traits_internal::IsLifetimeBoundAssignment<T, U>>>>;
232+
196233class Helper {
197234 public:
198235 // Move type-agnostic error handling to the .cc.
@@ -209,6 +246,26 @@ void PlacementNew(void* absl_nonnull p, Args&&... args) {
209246 new (p) T (std::forward<Args>(args)...);
210247}
211248
249+ template <typename T>
250+ class Reference {
251+ public:
252+ constexpr explicit Reference (T ref ABSL_ATTRIBUTE_LIFETIME_BOUND)
253+ : payload_(std::addressof(ref)) {}
254+
255+ Reference (const Reference&) = default ;
256+ Reference& operator =(const Reference&) = default ;
257+ Reference& operator =(T value) {
258+ payload_ = std::addressof (value);
259+ return *this ;
260+ }
261+
262+ operator T () const { return static_cast <T>(*payload_); } // NOLINT
263+ T get () const { return *this ; }
264+
265+ private:
266+ std::remove_reference_t <T>* absl_nonnull payload_;
267+ };
268+
212269// Helper base class to hold the data and all operations.
213270// We move all this to a base class to allow mixing with the appropriate
214271// TraitsBase specialization.
@@ -217,6 +274,14 @@ class StatusOrData {
217274 template <typename U>
218275 friend class StatusOrData ;
219276
277+ decltype (auto ) MaybeMoveData() {
278+ if constexpr (std::is_reference_v<T>) {
279+ return data_.get ();
280+ } else {
281+ return std::move (data_);
282+ }
283+ }
284+
220285 public:
221286 StatusOrData () = delete ;
222287
@@ -231,7 +296,7 @@ class StatusOrData {
231296
232297 StatusOrData (StatusOrData&& other) noexcept {
233298 if (other.ok ()) {
234- MakeValue (std::move ( other.data_ ));
299+ MakeValue (other.MaybeMoveData ( ));
235300 MakeStatus ();
236301 } else {
237302 MakeStatus (std::move (other.status_ ));
@@ -251,7 +316,7 @@ class StatusOrData {
251316 template <typename U>
252317 explicit StatusOrData (StatusOrData<U>&& other) {
253318 if (other.ok ()) {
254- MakeValue (std::move ( other.data_ ));
319+ MakeValue (other.MaybeMoveData ( ));
255320 MakeStatus ();
256321 } else {
257322 MakeStatus (std::move (other.status_ ));
@@ -264,13 +329,6 @@ class StatusOrData {
264329 MakeStatus ();
265330 }
266331
267- explicit StatusOrData (const T& value) : data_(value) {
268- MakeStatus ();
269- }
270- explicit StatusOrData (T&& value) : data_(std::move(value)) {
271- MakeStatus ();
272- }
273-
274332 template <typename U,
275333 absl::enable_if_t <std::is_constructible<absl::Status, U&&>::value,
276334 int > = 0 >
@@ -290,7 +348,7 @@ class StatusOrData {
290348 StatusOrData& operator =(StatusOrData&& other) {
291349 if (this == &other) return *this ;
292350 if (other.ok ())
293- Assign (std::move ( other.data_ ));
351+ Assign (other.MaybeMoveData ( ));
294352 else
295353 AssignStatus (std::move (other.status_ ));
296354 return *this ;
@@ -299,7 +357,9 @@ class StatusOrData {
299357 ~StatusOrData () {
300358 if (ok ()) {
301359 status_.~Status ();
302- data_.~T ();
360+ if constexpr (!std::is_trivially_destructible_v<T>) {
361+ data_.~T ();
362+ }
303363 } else {
304364 status_.~Status ();
305365 }
@@ -340,11 +400,13 @@ class StatusOrData {
340400 // When T is const, we need some non-const object we can cast to void* for
341401 // the placement new. dummy_ is that object.
342402 Dummy dummy_;
343- T data_;
403+ std:: conditional_t <std::is_reference_v<T>, Reference<T>, T> data_;
344404 };
345405
346406 void Clear () {
347- if (ok ()) data_.~T ();
407+ if constexpr (!std::is_trivially_destructible_v<T>) {
408+ if (ok ()) data_.~T ();
409+ }
348410 }
349411
350412 void EnsureOk () const {
@@ -359,7 +421,8 @@ class StatusOrData {
359421 // argument.
360422 template <typename ... Arg>
361423 void MakeValue (Arg&&... arg) {
362- internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...);
424+ internal_statusor::PlacementNew<decltype (data_)>(&dummy_,
425+ std::forward<Arg>(arg)...);
363426 }
364427
365428 // Construct the status (ie. status_) through placement new with the passed
@@ -369,6 +432,22 @@ class StatusOrData {
369432 internal_statusor::PlacementNew<Status>(&status_,
370433 std::forward<Args>(args)...);
371434 }
435+
436+ template <typename U>
437+ T ValueOrImpl (U&& default_value) const & {
438+ if (ok ()) {
439+ return data_;
440+ }
441+ return std::forward<U>(default_value);
442+ }
443+
444+ template <typename U>
445+ T ValueOrImpl (U&& default_value) && {
446+ if (ok ()) {
447+ return std::move (data_);
448+ }
449+ return std::forward<U>(default_value);
450+ }
372451};
373452
374453// Helper base classes to allow implicitly deleted constructors and assignment
@@ -411,8 +490,9 @@ struct MoveCtorBase<T, false> {
411490 MoveCtorBase& operator =(MoveCtorBase&&) = default ;
412491};
413492
414- template <typename T, bool = std::is_copy_constructible<T>::value&&
415- std::is_copy_assignable<T>::value>
493+ template <typename T, bool = (std::is_copy_constructible<T>::value &&
494+ std::is_copy_assignable<T>::value) ||
495+ std::is_reference_v<T>>
416496struct CopyAssignBase {
417497 CopyAssignBase () = default ;
418498 CopyAssignBase (const CopyAssignBase&) = default ;
@@ -430,8 +510,9 @@ struct CopyAssignBase<T, false> {
430510 CopyAssignBase& operator =(CopyAssignBase&&) = default ;
431511};
432512
433- template <typename T, bool = std::is_move_constructible<T>::value&&
434- std::is_move_assignable<T>::value>
513+ template <typename T, bool = (std::is_move_constructible<T>::value &&
514+ std::is_move_assignable<T>::value) ||
515+ std::is_reference_v<T>>
435516struct MoveAssignBase {
436517 MoveAssignBase () = default ;
437518 MoveAssignBase (const MoveAssignBase&) = default ;
0 commit comments