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 | |
69 | namespace folly { |
70 | |
71 | template <class Value> |
72 | class Optional; |
73 | |
74 | namespace detail { |
75 | template <class Value> |
76 | struct OptionalPromiseReturn; |
77 | } // namespace detail |
78 | |
79 | struct 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 | }; |
88 | constexpr None none{None::_secret::_token}; |
89 | |
90 | class FOLLY_EXPORT OptionalEmptyException : public std::runtime_error { |
91 | public: |
92 | OptionalEmptyException() |
93 | : std::runtime_error("Empty Optional cannot be unwrapped" ) {} |
94 | }; |
95 | |
96 | template <class Value> |
97 | class 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 | |
419 | template <class T> |
420 | const T* get_pointer(const Optional<T>& opt) { |
421 | return opt.get_pointer(); |
422 | } |
423 | |
424 | template <class T> |
425 | T* get_pointer(Optional<T>& opt) { |
426 | return opt.get_pointer(); |
427 | } |
428 | |
429 | template <class T> |
430 | void swap(Optional<T>& a, Optional<T>& b) noexcept(noexcept(a.swap(b))) { |
431 | a.swap(b); |
432 | } |
433 | |
434 | template <class T> |
435 | constexpr 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 | |
441 | template <class T, class... Args> |
442 | constexpr folly::Optional<T> make_optional(Args&&... args) { |
443 | using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor; |
444 | return {PrivateConstructor{}, std::forward<Args>(args)...}; |
445 | } |
446 | |
447 | template <class T, class U, class... Args> |
448 | constexpr 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 | |
458 | template <class U, class V> |
459 | constexpr bool operator==(const Optional<U>& a, const V& b) { |
460 | return a.hasValue() && a.value() == b; |
461 | } |
462 | |
463 | template <class U, class V> |
464 | constexpr bool operator!=(const Optional<U>& a, const V& b) { |
465 | return !(a == b); |
466 | } |
467 | |
468 | template <class U, class V> |
469 | constexpr bool operator==(const U& a, const Optional<V>& b) { |
470 | return b.hasValue() && b.value() == a; |
471 | } |
472 | |
473 | template <class U, class V> |
474 | constexpr bool operator!=(const U& a, const Optional<V>& b) { |
475 | return !(a == b); |
476 | } |
477 | |
478 | template <class U, class V> |
479 | constexpr 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 | |
489 | template <class U, class V> |
490 | constexpr bool operator!=(const Optional<U>& a, const Optional<V>& b) { |
491 | return !(a == b); |
492 | } |
493 | |
494 | template <class U, class V> |
495 | constexpr 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 | |
505 | template <class U, class V> |
506 | constexpr bool operator>(const Optional<U>& a, const Optional<V>& b) { |
507 | return b < a; |
508 | } |
509 | |
510 | template <class U, class V> |
511 | constexpr bool operator<=(const Optional<U>& a, const Optional<V>& b) { |
512 | return !(b < a); |
513 | } |
514 | |
515 | template <class U, class V> |
516 | constexpr 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. |
521 | template <class V> |
522 | bool operator<(const Optional<V>&, const V& other) = delete; |
523 | template <class V> |
524 | bool operator<=(const Optional<V>&, const V& other) = delete; |
525 | template <class V> |
526 | bool operator>=(const Optional<V>&, const V& other) = delete; |
527 | template <class V> |
528 | bool operator>(const Optional<V>&, const V& other) = delete; |
529 | template <class V> |
530 | bool operator<(const V& other, const Optional<V>&) = delete; |
531 | template <class V> |
532 | bool operator<=(const V& other, const Optional<V>&) = delete; |
533 | template <class V> |
534 | bool operator>=(const V& other, const Optional<V>&) = delete; |
535 | template <class V> |
536 | bool operator>(const V& other, const Optional<V>&) = delete; |
537 | |
538 | // Comparisons with none |
539 | template <class V> |
540 | constexpr bool operator==(const Optional<V>& a, None) noexcept { |
541 | return !a.hasValue(); |
542 | } |
543 | template <class V> |
544 | constexpr bool operator==(None, const Optional<V>& a) noexcept { |
545 | return !a.hasValue(); |
546 | } |
547 | template <class V> |
548 | constexpr bool operator<(const Optional<V>&, None) noexcept { |
549 | return false; |
550 | } |
551 | template <class V> |
552 | constexpr bool operator<(None, const Optional<V>& a) noexcept { |
553 | return a.hasValue(); |
554 | } |
555 | template <class V> |
556 | constexpr bool operator>(const Optional<V>& a, None) noexcept { |
557 | return a.hasValue(); |
558 | } |
559 | template <class V> |
560 | constexpr bool operator>(None, const Optional<V>&) noexcept { |
561 | return false; |
562 | } |
563 | template <class V> |
564 | constexpr bool operator<=(None, const Optional<V>&) noexcept { |
565 | return true; |
566 | } |
567 | template <class V> |
568 | constexpr bool operator<=(const Optional<V>& a, None) noexcept { |
569 | return !a.hasValue(); |
570 | } |
571 | template <class V> |
572 | constexpr bool operator>=(const Optional<V>&, None) noexcept { |
573 | return true; |
574 | } |
575 | template <class V> |
576 | constexpr 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 |
585 | FOLLY_NAMESPACE_STD_BEGIN |
586 | template <class T> |
587 | struct 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 | }; |
595 | FOLLY_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 | |
602 | namespace folly { |
603 | namespace detail { |
604 | template <typename Value> |
605 | struct OptionalPromise; |
606 | |
607 | template <typename Value> |
608 | struct 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 | |
623 | template <typename Value> |
624 | struct 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 | |
652 | template <typename Value> |
653 | struct 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 | |
672 | template <typename Value> |
673 | detail::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.. |
680 | namespace std { |
681 | namespace experimental { |
682 | template <typename Value, typename... Args> |
683 | struct 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 | |