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)117constexpr 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