2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * Optional - For conditional initialization of values, like boost::optional,
21 * but with support for move semantics and emplacement. Reference type support
22 * has not been included due to limited use cases and potential confusion with
23 * semantics of assignment: Assigning to an optional reference could quite
24 * reasonably copy its value or redirect the reference.
26 * Optional can be useful when a variable might or might not be needed:
28 * Optional<Logger> maybeLogger = ...;
30 * maybeLogger->log("hello");
33 * Optional enables a 'null' value for types which do not otherwise have
34 * nullability, especially useful for parameter passing:
36 * void testIterator(const unique_ptr<Iterator>& it,
37 * initializer_list<int> idsExpected,
38 * Optional<initializer_list<int>> ranksExpected = none) {
39 * for (int i = 0; it->next(); ++i) {
40 * EXPECT_EQ(it->doc().id(), idsExpected[i]);
41 * if (ranksExpected) {
42 * EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]);
47 * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a
48 * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is
51 * Optional<int> maybeInt = ...;
52 * if (int* v = get_pointer(maybeInt)) {
61 #include <type_traits>
64 #include <folly/Launder.h>
65 #include <folly/Portability.h>
66 #include <folly/Utility.h>
73 // Allow each translation unit to control its own -fexceptions setting.
74 // If exceptions are disabled, std::terminate() will be called instead of
75 // throwing OptionalEmptyException when the condition fails.
76 [[noreturn]] void throw_optional_empty_exception();
79 typedef int detail::NoneHelper::*None;
81 const None none = nullptr;
83 class OptionalEmptyException : public std::runtime_error {
85 OptionalEmptyException()
86 : std::runtime_error("Empty Optional cannot be unwrapped") {}
89 template <class Value>
92 typedef Value value_type;
95 !std::is_reference<Value>::value,
96 "Optional may not be used with reference types");
98 !std::is_abstract<Value>::value,
99 "Optional may not be used with abstract types");
101 Optional() noexcept {}
103 Optional(const Optional& src) noexcept(
104 std::is_nothrow_copy_constructible<Value>::value) {
105 if (src.hasValue()) {
106 storage_.construct(src.value());
110 Optional(Optional&& src) noexcept(
111 std::is_nothrow_move_constructible<Value>::value) {
112 if (src.hasValue()) {
113 storage_.construct(std::move(src.value()));
118 /* implicit */ Optional(const None&) noexcept {}
120 /* implicit */ Optional(Value&& newValue) noexcept(
121 std::is_nothrow_move_constructible<Value>::value) {
122 storage_.construct(std::move(newValue));
125 /* implicit */ Optional(const Value& newValue) noexcept(
126 std::is_nothrow_copy_constructible<Value>::value) {
127 storage_.construct(newValue);
130 template <typename... Args>
131 explicit Optional(in_place_t, Args&&... args) noexcept(
132 std::is_nothrow_constructible<Value, Args...>::value) {
133 storage_.construct(std::forward<Args>(args)...);
136 void assign(const None&) {
140 void assign(Optional&& src) {
142 if (src.hasValue()) {
143 assign(std::move(src.value()));
151 void assign(const Optional& src) {
152 if (src.hasValue()) {
159 void assign(Value&& newValue) {
161 *storage_.value_pointer() = std::move(newValue);
163 storage_.construct(std::move(newValue));
167 void assign(const Value& newValue) {
169 *storage_.value_pointer() = newValue;
171 storage_.construct(newValue);
176 Optional& operator=(Arg&& arg) {
177 assign(std::forward<Arg>(arg));
181 Optional& operator=(Optional&& other) noexcept(
182 std::is_nothrow_move_assignable<Value>::value) {
183 assign(std::move(other));
187 Optional& operator=(const Optional& other) noexcept(
188 std::is_nothrow_copy_assignable<Value>::value) {
193 template <class... Args>
194 void emplace(Args&&... args) {
196 storage_.construct(std::forward<Args>(args)...);
203 const Value& value() const & {
205 return *storage_.value_pointer();
210 return *storage_.value_pointer();
215 return std::move(*storage_.value_pointer());
218 const Value&& value() const && {
220 return std::move(*storage_.value_pointer());
223 const Value* get_pointer() const & {
224 return storage_.value_pointer();
226 Value* get_pointer() & {
227 return storage_.value_pointer();
229 Value* get_pointer() && = delete;
231 bool hasValue() const {
232 return storage_.hasValue();
235 explicit operator bool() const {
239 const Value& operator*() const & {
242 Value& operator*() & {
245 const Value&& operator*() const && {
246 return std::move(value());
248 Value&& operator*() && {
249 return std::move(value());
252 const Value* operator->() const {
255 Value* operator->() {
259 // Return a copy of the value if set, or a given default if not.
261 Value value_or(U&& dflt) const & {
262 if (storage_.hasValue()) {
263 return *storage_.value_pointer();
266 return std::forward<U>(dflt);
270 Value value_or(U&& dflt) && {
271 if (storage_.hasValue()) {
272 return std::move(*storage_.value_pointer());
275 return std::forward<U>(dflt);
279 void require_value() const {
280 if (!storage_.hasValue()) {
281 detail::throw_optional_empty_exception();
285 struct StorageTriviallyDestructible {
288 std::aligned_storage_t<sizeof(Value), alignof(Value)> value_[1];
291 StorageTriviallyDestructible() : hasValue_{false} {}
297 struct StorageNonTriviallyDestructible {
300 std::aligned_storage_t<sizeof(Value), alignof(Value)> value_[1];
303 StorageNonTriviallyDestructible() : hasValue_{false} {}
304 ~StorageNonTriviallyDestructible() {
311 launder(reinterpret_cast<Value*>(value_))->~Value();
316 struct Storage : std::conditional_t<
317 std::is_trivially_destructible<Value>::value,
318 StorageTriviallyDestructible,
319 StorageNonTriviallyDestructible> {
320 bool hasValue() const {
321 return this->hasValue_;
324 Value* value_pointer() {
325 if (this->hasValue_) {
326 return launder(reinterpret_cast<Value*>(this->value_));
331 Value const* value_pointer() const {
332 if (this->hasValue_) {
333 return launder(reinterpret_cast<Value const*>(this->value_));
338 template <class... Args>
339 void construct(Args&&... args) {
340 new (raw_pointer()) Value(std::forward<Args>(args)...);
341 this->hasValue_ = true;
345 void* raw_pointer() {
346 return static_cast<void*>(this->value_);
354 const T* get_pointer(const Optional<T>& opt) {
355 return opt.get_pointer();
359 T* get_pointer(Optional<T>& opt) {
360 return opt.get_pointer();
364 void swap(Optional<T>& a, Optional<T>& b) {
365 if (a.hasValue() && b.hasValue()) {
368 swap(a.value(), b.value());
369 } else if (a.hasValue() || b.hasValue()) {
370 std::swap(a, b); // fall back to default implementation if they're mixed.
374 template <class T, class Opt = Optional<std::decay_t<T>>>
375 Opt make_optional(T&& v) {
376 return Opt(std::forward<T>(v));
379 ///////////////////////////////////////////////////////////////////////////////
382 template <class U, class V>
383 bool operator==(const Optional<U>& a, const V& b) {
384 return a.hasValue() && a.value() == b;
387 template <class U, class V>
388 bool operator!=(const Optional<U>& a, const V& b) {
392 template <class U, class V>
393 bool operator==(const U& a, const Optional<V>& b) {
394 return b.hasValue() && b.value() == a;
397 template <class U, class V>
398 bool operator!=(const U& a, const Optional<V>& b) {
402 template <class U, class V>
403 bool operator==(const Optional<U>& a, const Optional<V>& b) {
404 if (a.hasValue() != b.hasValue()) {
408 return a.value() == b.value();
413 template <class U, class V>
414 bool operator!=(const Optional<U>& a, const Optional<V>& b) {
418 template <class U, class V>
419 bool operator<(const Optional<U>& a, const Optional<V>& b) {
420 if (a.hasValue() != b.hasValue()) {
421 return a.hasValue() < b.hasValue();
424 return a.value() < b.value();
429 template <class U, class V>
430 bool operator>(const Optional<U>& a, const Optional<V>& b) {
434 template <class U, class V>
435 bool operator<=(const Optional<U>& a, const Optional<V>& b) {
439 template <class U, class V>
440 bool operator>=(const Optional<U>& a, const Optional<V>& b) {
444 // Suppress comparability of Optional<T> with T, despite implicit conversion.
446 bool operator<(const Optional<V>&, const V& other) = delete;
448 bool operator<=(const Optional<V>&, const V& other) = delete;
450 bool operator>=(const Optional<V>&, const V& other) = delete;
452 bool operator>(const Optional<V>&, const V& other) = delete;
454 bool operator<(const V& other, const Optional<V>&) = delete;
456 bool operator<=(const V& other, const Optional<V>&) = delete;
458 bool operator>=(const V& other, const Optional<V>&) = delete;
460 bool operator>(const V& other, const Optional<V>&) = delete;
462 ///////////////////////////////////////////////////////////////////////////////
466 // Allow usage of Optional<T> in std::unordered_map and std::unordered_set
467 FOLLY_NAMESPACE_STD_BEGIN
469 struct hash<folly::Optional<T>> {
470 size_t operator()(folly::Optional<T> const& obj) const {
471 if (!obj.hasValue()) {
474 return hash<remove_const_t<T>>()(*obj);
477 FOLLY_NAMESPACE_STD_END