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