/* * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FCP_BASE_UNIQUE_VALUE_H_ #define FCP_BASE_UNIQUE_VALUE_H_ #include #include namespace fcp { /** * UniqueValue provides move-only semantics for some value of type T. * * Its semantics are much like std::unique_ptr, but without requiring an * allocation and pointer indirection (recall a moved-from std::unique_ptr is * reset to nullptr). * * Instead, UniqueValue is represented just like std::optional - but * has_value() == false once moved-from. std::optional does *not* reset when * moved from (even if the wrapped type is move-only); that's consistent, but * not especially desirable. * * Since UniqueValue is always move-only, including a UniqueValue member is * sufficient for a containing aggregate to be move-only. */ template class UniqueValue { public: constexpr explicit UniqueValue(std::nullopt_t) : value_() {} constexpr explicit UniqueValue(T val) : value_(std::move(val)) {} UniqueValue(UniqueValue const&) = delete; UniqueValue(UniqueValue&& other) : value_(std::move(other.value_)) { other.value_.reset(); } UniqueValue& operator=(UniqueValue other) { value_.swap(other.value_); return *this; } /** * Indicates if this instance holds a value (i.e. has not been moved away). * * It is an error to dereference this UniqueValue if !has_value(). */ constexpr bool has_value() const { return value_.has_value(); } constexpr T Take() && { T v = *std::move(value_); value_.reset(); return v; } constexpr T const& operator*() const & { return *value_; } T& operator*() & { return *value_; } T const* operator->() const { return &*value_; } T* operator->() { return &*value_; } /** * Replaces current value with a newly constructed one given constructor * arguments for T (like std::optional::emplace). */ template T& Emplace(_Args&&... __args) { value_.emplace(std::forward<_Args>(__args)...); return *value_; } /** * Removes (destructs) a value. No-op if absent; */ void Reset() { value_.reset(); } private: std::optional value_; }; // Deduction guide allowing one to write UniqueValue(x) without an explicit // template argument. This one would be implicitly generated; it's here to // suppress -Wctad-maybe-unsupported. template UniqueValue(T val) -> UniqueValue; /** * Makes a UniqueValue given constructor arguments for T * (like std::make_unique). */ template constexpr UniqueValue MakeUniqueValue(Args&&... args) { return UniqueValue(T(std::forward(args)...)); } } // namespace fcp #endif // FCP_BASE_UNIQUE_VALUE_H_