xref: /aosp_15_r20/external/federated-compute/fcp/base/unique_value.h (revision 14675a029014e728ec732f129a32e299b2da0601)
1 /*
2  * Copyright 2019 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef FCP_BASE_UNIQUE_VALUE_H_
18 #define FCP_BASE_UNIQUE_VALUE_H_
19 
20 #include <optional>
21 #include <utility>
22 
23 namespace fcp {
24 
25 /**
26  * UniqueValue<T> provides move-only semantics for some value of type T.
27  *
28  * Its semantics are much like std::unique_ptr, but without requiring an
29  * allocation and pointer indirection (recall a moved-from std::unique_ptr is
30  * reset to nullptr).
31  *
32  * Instead, UniqueValue is represented just like std::optional - but
33  * has_value() == false once moved-from. std::optional does *not* reset when
34  * moved from (even if the wrapped type is move-only); that's consistent, but
35  * not especially desirable.
36  *
37  * Since UniqueValue is always move-only, including a UniqueValue member is
38  * sufficient for a containing aggregate to be move-only.
39  */
40 template <typename T>
41 class UniqueValue {
42  public:
UniqueValue(std::nullopt_t)43   constexpr explicit UniqueValue(std::nullopt_t) : value_() {}
UniqueValue(T val)44   constexpr explicit UniqueValue(T val) : value_(std::move(val)) {}
45 
46   UniqueValue(UniqueValue const&) = delete;
UniqueValue(UniqueValue && other)47   UniqueValue(UniqueValue&& other) : value_(std::move(other.value_)) {
48     other.value_.reset();
49   }
50 
51   UniqueValue& operator=(UniqueValue other) {
52     value_.swap(other.value_);
53     return *this;
54   }
55 
56   /**
57    * Indicates if this instance holds a value (i.e. has not been moved away).
58    *
59    * It is an error to dereference this UniqueValue if !has_value().
60    */
has_value()61   constexpr bool has_value() const {
62     return value_.has_value();
63   }
64 
Take()65   constexpr T Take() && {
66     T v = *std::move(value_);
67     value_.reset();
68     return v;
69   }
70 
71   constexpr T const& operator*() const & {
72     return *value_;
73   }
74 
75   T& operator*() & {
76     return *value_;
77   }
78 
79   T const* operator->() const {
80     return &*value_;
81   }
82 
83   T* operator->() {
84     return &*value_;
85   }
86 
87   /**
88    * Replaces current value with a newly constructed one given constructor
89    * arguments for T (like std::optional::emplace).
90    */
91   template <class... _Args>
Emplace(_Args &&...__args)92   T& Emplace(_Args&&... __args) {
93     value_.emplace(std::forward<_Args>(__args)...);
94     return *value_;
95   }
96 
97   /**
98    * Removes (destructs) a value. No-op if absent;
99    */
Reset()100   void Reset() { value_.reset(); }
101 
102  private:
103   std::optional<T> value_;
104 };
105 
106 // Deduction guide allowing one to write UniqueValue(x) without an explicit
107 // template argument. This one would be implicitly generated; it's here to
108 // suppress -Wctad-maybe-unsupported.
109 template <typename T>
110 UniqueValue(T val) -> UniqueValue<T>;
111 
112 /**
113  * Makes a UniqueValue<T> given constructor arguments for T
114  * (like std::make_unique).
115  */
116 template <typename T, typename... Args>
MakeUniqueValue(Args &&...args)117 constexpr UniqueValue<T> MakeUniqueValue(Args&&... args) {
118   return UniqueValue<T>(T(std::forward<Args>(args)...));
119 }
120 
121 }  // namespace fcp
122 
123 #endif  // FCP_BASE_UNIQUE_VALUE_H_
124