1/*
2 * Copyright 2012-present Facebook, Inc.
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#pragma once
17
18/*
19 * Optional - For conditional initialization of values, like boost::optional,
20 * but with support for move semantics and emplacement. Reference type support
21 * has not been included due to limited use cases and potential confusion with
22 * semantics of assignment: Assigning to an optional reference could quite
23 * reasonably copy its value or redirect the reference.
24 *
25 * Optional can be useful when a variable might or might not be needed:
26 *
27 * Optional<Logger> maybeLogger = ...;
28 * if (maybeLogger) {
29 * maybeLogger->log("hello");
30 * }
31 *
32 * Optional enables a 'null' value for types which do not otherwise have
33 * nullability, especially useful for parameter passing:
34 *
35 * void testIterator(const unique_ptr<Iterator>& it,
36 * initializer_list<int> idsExpected,
37 * Optional<initializer_list<int>> ranksExpected = none) {
38 * for (int i = 0; it->next(); ++i) {
39 * EXPECT_EQ(it->doc().id(), idsExpected[i]);
40 * if (ranksExpected) {
41 * EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]);
42 * }
43 * }
44 * }
45 *
46 * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a
47 * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is
48 * not:
49 *
50 * Optional<int> maybeInt = ...;
51 * if (int* v = get_pointer(maybeInt)) {
52 * cout << *v << endl;
53 * }
54 */
55
56#include <cstddef>
57#include <functional>
58#include <new>
59#include <stdexcept>
60#include <type_traits>
61#include <utility>
62
63#include <folly/Portability.h>
64#include <folly/Traits.h>
65#include <folly/Utility.h>
66#include <folly/lang/Exception.h>
67
68namespace folly {
69
70template <class Value>
71class Optional;
72
73namespace detail {
74template <class Value>
75struct OptionalPromiseReturn;
76} // namespace detail
77
78struct None {
79 enum class _secret { _token };
80
81 /**
82 * No default constructor to support both `op = {}` and `op = none`
83 * as syntax for clearing an Optional, just like std::nullopt_t.
84 */
85 explicit constexpr None(_secret) {}
86};
87constexpr None none{None::_secret::_token};
88
89class FOLLY_EXPORT OptionalEmptyException : public std::runtime_error {
90 public:
91 OptionalEmptyException()
92 : std::runtime_error("Empty Optional cannot be unwrapped") {}
93};
94
95template <class Value>
96class Optional {
97 public:
98 typedef Value value_type;
99
100 static_assert(
101 !std::is_reference<Value>::value,
102 "Optional may not be used with reference types");
103 static_assert(
104 !std::is_abstract<Value>::value,
105 "Optional may not be used with abstract types");
106
107 FOLLY_CPP14_CONSTEXPR Optional() noexcept {}
108
109 Optional(const Optional& src) noexcept(
110 std::is_nothrow_copy_constructible<Value>::value) {
111 if (src.hasValue()) {
112 construct(src.value());
113 }
114 }
115
116 Optional(Optional&& src) noexcept(
117 std::is_nothrow_move_constructible<Value>::value) {
118 if (src.hasValue()) {
119 construct(std::move(src.value()));
120 src.clear();
121 }
122 }
123
124 FOLLY_CPP14_CONSTEXPR /* implicit */ Optional(const None&) noexcept {}
125
126 FOLLY_CPP14_CONSTEXPR /* implicit */ Optional(Value&& newValue) noexcept(
127 std::is_nothrow_move_constructible<Value>::value) {
128 construct(std::move(newValue));
129 }
130
131 FOLLY_CPP14_CONSTEXPR /* implicit */ Optional(const Value& newValue) noexcept(
132 std::is_nothrow_copy_constructible<Value>::value) {
133 construct(newValue);
134 }
135
136 /**
137 * Explicitly disallow converting nullptr to non-pointer
138 * types. Optional used to support initialization from nullptr as if
139 * it were folly::none. Without this constructor,
140 * folly::Optional<bool> could be constructed from nullptr,
141 * producing {false} instead of {}. This would be a change in
142 * behavior from the old code, so explicitly disallow it. Note that
143 * std::optional<bool> can be constructed from nullptr, also
144 * producing {false}.
145 *
146 * This constructor is temporary and should be removed when all call
147 * sites are fixed.
148 */
149 template <typename Null = std::nullptr_t>
150 /* implicit */
151 Optional(typename std::enable_if<
152 std::is_convertible<Null, Value>::value,
153 Null>::type) noexcept = delete;
154
155 template <typename... Args>
156 FOLLY_CPP14_CONSTEXPR explicit Optional(in_place_t, Args&&... args) noexcept(
157 std::is_nothrow_constructible<Value, Args...>::value)
158 : Optional{PrivateConstructor{}, std::forward<Args>(args)...} {}
159
160 template <typename U, typename... Args>
161 FOLLY_CPP14_CONSTEXPR explicit Optional(
162 in_place_t,
163 std::initializer_list<U> il,
164 Args&&... args) noexcept(std::
165 is_nothrow_constructible<
166 Value,
167 std::initializer_list<U>,
168 Args...>::value)
169 : Optional{PrivateConstructor{}, il, std::forward<Args>(args)...} {}
170
171 // Used only when an Optional is used with coroutines on MSVC
172 /* implicit */ Optional(const detail::OptionalPromiseReturn<Value>& p)
173 : Optional{} {
174 p.promise_->value_ = this;
175 }
176
177 void assign(const None&) {
178 clear();
179 }
180
181 void assign(Optional&& src) {
182 if (this != &src) {
183 if (src.hasValue()) {
184 assign(std::move(src.value()));
185 src.clear();
186 } else {
187 clear();
188 }
189 }
190 }
191
192 void assign(const Optional& src) {
193 if (src.hasValue()) {
194 assign(src.value());
195 } else {
196 clear();
197 }
198 }
199
200 void assign(Value&& newValue) {
201 if (hasValue()) {
202 storage_.value = std::move(newValue);
203 } else {
204 construct(std::move(newValue));
205 }
206 }
207
208 void assign(const Value& newValue) {
209 if (hasValue()) {
210 storage_.value = newValue;
211 } else {
212 construct(newValue);
213 }
214 }
215
216 Optional& operator=(None) noexcept {
217 reset();
218 return *this;
219 }
220
221 template <class Arg>
222 Optional& operator=(Arg&& arg) {
223 assign(std::forward<Arg>(arg));
224 return *this;
225 }
226
227 Optional& operator=(Optional&& other) noexcept(
228 std::is_nothrow_move_assignable<Value>::value) {
229 assign(std::move(other));
230 return *this;
231 }
232
233 Optional& operator=(const Optional& other) noexcept(
234 std::is_nothrow_copy_assignable<Value>::value) {
235 assign(other);
236 return *this;
237 }
238
239 template <class... Args>
240 Value& emplace(Args&&... args) {
241 clear();
242 construct(std::forward<Args>(args)...);
243 return value();
244 }
245
246 template <class U, class... Args>
247 typename std::enable_if<
248 std::is_constructible<Value, std::initializer_list<U>&, Args&&...>::value,
249 Value&>::type
250 emplace(std::initializer_list<U> ilist, Args&&... args) {
251 clear();
252 construct(ilist, std::forward<Args>(args)...);
253 return value();
254 }
255
256 void reset() noexcept {
257 storage_.clear();
258 }
259
260 void clear() noexcept {
261 reset();
262 }
263
264 void swap(Optional& that) noexcept(IsNothrowSwappable<Value>::value) {
265 if (hasValue() && that.hasValue()) {
266 using std::swap;
267 swap(value(), that.value());
268 } else if (hasValue()) {
269 that.emplace(std::move(value()));
270 reset();
271 } else if (that.hasValue()) {
272 emplace(std::move(that.value()));
273 that.reset();
274 }
275 }
276
277 FOLLY_CPP14_CONSTEXPR const Value& value() const& {
278 require_value();
279 return storage_.value;
280 }
281
282 FOLLY_CPP14_CONSTEXPR Value& value() & {
283 require_value();
284 return storage_.value;
285 }
286
287 FOLLY_CPP14_CONSTEXPR Value&& value() && {
288 require_value();
289 return std::move(storage_.value);
290 }
291
292 FOLLY_CPP14_CONSTEXPR const Value&& value() const&& {
293 require_value();
294 return std::move(storage_.value);
295 }
296
297 const Value* get_pointer() const& {
298 return storage_.hasValue ? &storage_.value : nullptr;
299 }
300 Value* get_pointer() & {
301 return storage_.hasValue ? &storage_.value : nullptr;
302 }
303 Value* get_pointer() && = delete;
304
305 FOLLY_CPP14_CONSTEXPR bool has_value() const noexcept {
306 return storage_.hasValue;
307 }
308
309 FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept {
310 return has_value();
311 }
312
313 FOLLY_CPP14_CONSTEXPR explicit operator bool() const noexcept {
314 return has_value();
315 }
316
317 FOLLY_CPP14_CONSTEXPR const Value& operator*() const& {
318 return value();
319 }
320 FOLLY_CPP14_CONSTEXPR Value& operator*() & {
321 return value();
322 }
323 FOLLY_CPP14_CONSTEXPR const Value&& operator*() const&& {
324 return std::move(value());
325 }
326 FOLLY_CPP14_CONSTEXPR Value&& operator*() && {
327 return std::move(value());
328 }
329
330 FOLLY_CPP14_CONSTEXPR const Value* operator->() const {
331 return &value();
332 }
333 FOLLY_CPP14_CONSTEXPR Value* operator->() {
334 return &value();
335 }
336
337 // Return a copy of the value if set, or a given default if not.
338 template <class U>
339 FOLLY_CPP14_CONSTEXPR Value value_or(U&& dflt) const& {
340 if (storage_.hasValue) {
341 return storage_.value;
342 }
343
344 return std::forward<U>(dflt);
345 }
346
347 template <class U>
348 FOLLY_CPP14_CONSTEXPR Value value_or(U&& dflt) && {
349 if (storage_.hasValue) {
350 return std::move(storage_.value);
351 }
352
353 return std::forward<U>(dflt);
354 }
355
356 private:
357 template <class T>
358 friend constexpr Optional<std::decay_t<T>> make_optional(T&&);
359 template <class T, class... Args>
360 friend constexpr Optional<T> make_optional(Args&&... args);
361 template <class T, class U, class... As>
362 friend constexpr Optional<T> make_optional(std::initializer_list<U>, As&&...);
363
364 /**
365 * Construct the optional in place, this is duplicated as a non-explicit
366 * constructor to allow returning values that are non-movable from
367 * make_optional using list initialization.
368 *
369 * Until C++17, at which point this will become unnecessary because of
370 * specified prvalue elision.
371 */
372 struct PrivateConstructor {
373 explicit PrivateConstructor() = default;
374 };
375 template <typename... Args>
376 FOLLY_CPP14_CONSTEXPR Optional(PrivateConstructor, Args&&... args) noexcept(
377 std::is_constructible<Value, Args&&...>::value) {
378 construct(std::forward<Args>(args)...);
379 }
380
381 void require_value() const {
382 if (!storage_.hasValue) {
383 throw_exception<OptionalEmptyException>();
384 }
385 }
386
387 template <class... Args>
388 void construct(Args&&... args) {
389 const void* ptr = &storage_.value;
390 // For supporting const types.
391 new (const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
392 storage_.hasValue = true;
393 }
394
395 struct StorageTriviallyDestructible {
396 union {
397 char emptyState;
398 Value value;
399 };
400 bool hasValue;
401
402 StorageTriviallyDestructible() : hasValue{false} {}
403 void clear() {
404 hasValue = false;
405 }
406 };
407
408 struct StorageNonTriviallyDestructible {
409 union {
410 char emptyState;
411 Value value;
412 };
413 bool hasValue;
414
415 FOLLY_PUSH_WARNING
416 // These are both informational warnings, but they trigger rare
417 // enough that we've left them enabled. Needed as long as MSVC
418 // 2015 is supported.
419 FOLLY_MSVC_DISABLE_WARNING(4587) // constructor of .value is not called
420 FOLLY_MSVC_DISABLE_WARNING(4588) // destructor of .value is not called
421 StorageNonTriviallyDestructible() : hasValue{false} {}
422 ~StorageNonTriviallyDestructible() {
423 clear();
424 }
425 FOLLY_POP_WARNING
426
427 void clear() {
428 if (hasValue) {
429 hasValue = false;
430 value.~Value();
431 }
432 }
433 };
434
435 using Storage = typename std::conditional<
436 std::is_trivially_destructible<Value>::value,
437 StorageTriviallyDestructible,
438 StorageNonTriviallyDestructible>::type;
439
440 Storage storage_;
441};
442
443template <class T>
444const T* get_pointer(const Optional<T>& opt) {
445 return opt.get_pointer();
446}
447
448template <class T>
449T* get_pointer(Optional<T>& opt) {
450 return opt.get_pointer();
451}
452
453template <class T>
454void swap(Optional<T>& a, Optional<T>& b) noexcept(noexcept(a.swap(b))) {
455 a.swap(b);
456}
457
458template <class T>
459constexpr Optional<std::decay_t<T>> make_optional(T&& v) {
460 using PrivateConstructor =
461 typename folly::Optional<std::decay_t<T>>::PrivateConstructor;
462 return {PrivateConstructor{}, std::forward<T>(v)};
463}
464
465template <class T, class... Args>
466constexpr folly::Optional<T> make_optional(Args&&... args) {
467 using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor;
468 return {PrivateConstructor{}, std::forward<Args>(args)...};
469}
470
471template <class T, class U, class... Args>
472constexpr folly::Optional<T> make_optional(
473 std::initializer_list<U> il,
474 Args&&... args) {
475 using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor;
476 return {PrivateConstructor{}, il, std::forward<Args>(args)...};
477}
478
479///////////////////////////////////////////////////////////////////////////////
480// Comparisons.
481
482template <class U, class V>
483constexpr bool operator==(const Optional<U>& a, const V& b) {
484 return a.hasValue() && a.value() == b;
485}
486
487template <class U, class V>
488constexpr bool operator!=(const Optional<U>& a, const V& b) {
489 return !(a == b);
490}
491
492template <class U, class V>
493constexpr bool operator==(const U& a, const Optional<V>& b) {
494 return b.hasValue() && b.value() == a;
495}
496
497template <class U, class V>
498constexpr bool operator!=(const U& a, const Optional<V>& b) {
499 return !(a == b);
500}
501
502template <class U, class V>
503FOLLY_CPP14_CONSTEXPR bool operator==(
504 const Optional<U>& a,
505 const Optional<V>& b) {
506 if (a.hasValue() != b.hasValue()) {
507 return false;
508 }
509 if (a.hasValue()) {
510 return a.value() == b.value();
511 }
512 return true;
513}
514
515template <class U, class V>
516constexpr bool operator!=(const Optional<U>& a, const Optional<V>& b) {
517 return !(a == b);
518}
519
520template <class U, class V>
521FOLLY_CPP14_CONSTEXPR bool operator<(
522 const Optional<U>& a,
523 const Optional<V>& b) {
524 if (a.hasValue() != b.hasValue()) {
525 return a.hasValue() < b.hasValue();
526 }
527 if (a.hasValue()) {
528 return a.value() < b.value();
529 }
530 return false;
531}
532
533template <class U, class V>
534constexpr bool operator>(const Optional<U>& a, const Optional<V>& b) {
535 return b < a;
536}
537
538template <class U, class V>
539constexpr bool operator<=(const Optional<U>& a, const Optional<V>& b) {
540 return !(b < a);
541}
542
543template <class U, class V>
544constexpr bool operator>=(const Optional<U>& a, const Optional<V>& b) {
545 return !(a < b);
546}
547
548// Suppress comparability of Optional<T> with T, despite implicit conversion.
549template <class V>
550bool operator<(const Optional<V>&, const V& other) = delete;
551template <class V>
552bool operator<=(const Optional<V>&, const V& other) = delete;
553template <class V>
554bool operator>=(const Optional<V>&, const V& other) = delete;
555template <class V>
556bool operator>(const Optional<V>&, const V& other) = delete;
557template <class V>
558bool operator<(const V& other, const Optional<V>&) = delete;
559template <class V>
560bool operator<=(const V& other, const Optional<V>&) = delete;
561template <class V>
562bool operator>=(const V& other, const Optional<V>&) = delete;
563template <class V>
564bool operator>(const V& other, const Optional<V>&) = delete;
565
566// Comparisons with none
567template <class V>
568constexpr bool operator==(const Optional<V>& a, None) noexcept {
569 return !a.hasValue();
570}
571template <class V>
572constexpr bool operator==(None, const Optional<V>& a) noexcept {
573 return !a.hasValue();
574}
575template <class V>
576constexpr bool operator<(const Optional<V>&, None) noexcept {
577 return false;
578}
579template <class V>
580constexpr bool operator<(None, const Optional<V>& a) noexcept {
581 return a.hasValue();
582}
583template <class V>
584constexpr bool operator>(const Optional<V>& a, None) noexcept {
585 return a.hasValue();
586}
587template <class V>
588constexpr bool operator>(None, const Optional<V>&) noexcept {
589 return false;
590}
591template <class V>
592constexpr bool operator<=(None, const Optional<V>&) noexcept {
593 return true;
594}
595template <class V>
596constexpr bool operator<=(const Optional<V>& a, None) noexcept {
597 return !a.hasValue();
598}
599template <class V>
600constexpr bool operator>=(const Optional<V>&, None) noexcept {
601 return true;
602}
603template <class V>
604constexpr bool operator>=(None, const Optional<V>& a) noexcept {
605 return !a.hasValue();
606}
607
608///////////////////////////////////////////////////////////////////////////////
609
610} // namespace folly
611
612// Allow usage of Optional<T> in std::unordered_map and std::unordered_set
613FOLLY_NAMESPACE_STD_BEGIN
614template <class T>
615struct hash<folly::Optional<T>> {
616 size_t operator()(folly::Optional<T> const& obj) const {
617 if (!obj.hasValue()) {
618 return 0;
619 }
620 return hash<typename remove_const<T>::type>()(*obj);
621 }
622};
623FOLLY_NAMESPACE_STD_END
624
625// Enable the use of folly::Optional with `co_await`
626// Inspired by https://github.com/toby-allsopp/coroutine_monad
627#if FOLLY_HAS_COROUTINES
628#include <experimental/coroutine>
629
630namespace folly {
631namespace detail {
632template <typename Value>
633struct OptionalPromise;
634
635template <typename Value>
636struct OptionalPromiseReturn {
637 Optional<Value> storage_;
638 OptionalPromise<Value>* promise_;
639 /* implicit */ OptionalPromiseReturn(OptionalPromise<Value>& promise) noexcept
640 : promise_(&promise) {
641 promise.value_ = &storage_;
642 }
643 OptionalPromiseReturn(OptionalPromiseReturn&& that) noexcept
644 : OptionalPromiseReturn{*that.promise_} {}
645 ~OptionalPromiseReturn() {}
646 /* implicit */ operator Optional<Value>() & {
647 return std::move(storage_);
648 }
649};
650
651template <typename Value>
652struct OptionalPromise {
653 Optional<Value>* value_ = nullptr;
654 OptionalPromise() = default;
655 OptionalPromise(OptionalPromise const&) = delete;
656 // This should work regardless of whether the compiler generates:
657 // folly::Optional<Value> retobj{ p.get_return_object(); } // MSVC
658 // or:
659 // auto retobj = p.get_return_object(); // clang
660 OptionalPromiseReturn<Value> get_return_object() noexcept {
661 return *this;
662 }
663 std::experimental::suspend_never initial_suspend() const noexcept {
664 return {};
665 }
666 std::experimental::suspend_never final_suspend() const {
667 return {};
668 }
669 template <typename U>
670 void return_value(U&& u) {
671 *value_ = static_cast<U&&>(u);
672 }
673 void unhandled_exception() {
674 // Technically, throwing from unhandled_exception is underspecified:
675 // https://github.com/GorNishanov/CoroutineWording/issues/17
676 throw;
677 }
678};
679
680template <typename Value>
681struct OptionalAwaitable {
682 Optional<Value> o_;
683 bool await_ready() const noexcept {
684 return o_.hasValue();
685 }
686 Value await_resume() {
687 return std::move(o_.value());
688 }
689
690 // Explicitly only allow suspension into an OptionalPromise
691 template <typename U>
692 void await_suspend(
693 std::experimental::coroutine_handle<OptionalPromise<U>> h) const {
694 // Abort the rest of the coroutine. resume() is not going to be called
695 h.destroy();
696 }
697};
698} // namespace detail
699
700template <typename Value>
701detail::OptionalAwaitable<Value>
702/* implicit */ operator co_await(Optional<Value> o) {
703 return {std::move(o)};
704}
705} // namespace folly
706
707// This makes folly::Optional<Value> useable as a coroutine return type..
708namespace std {
709namespace experimental {
710template <typename Value, typename... Args>
711struct coroutine_traits<folly::Optional<Value>, Args...> {
712 using promise_type = folly::detail::OptionalPromise<Value>;
713};
714} // namespace experimental
715} // namespace std
716#endif // FOLLY_HAS_COROUTINES
717