]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | // This source code is licensed under both the GPLv2 (found in the | |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
5 | ||
6 | #pragma once | |
7 | ||
8 | /* | |
9 | * Optional - For conditional initialization of values, like boost::optional, | |
10 | * but with support for move semantics and emplacement. Reference type support | |
11 | * has not been included due to limited use cases and potential confusion with | |
12 | * semantics of assignment: Assigning to an optional reference could quite | |
13 | * reasonably copy its value or redirect the reference. | |
14 | * | |
15 | * Optional can be useful when a variable might or might not be needed: | |
16 | * | |
17 | * Optional<Logger> maybeLogger = ...; | |
18 | * if (maybeLogger) { | |
19 | * maybeLogger->log("hello"); | |
20 | * } | |
21 | * | |
22 | * Optional enables a 'null' value for types which do not otherwise have | |
23 | * nullability, especially useful for parameter passing: | |
24 | * | |
25 | * void testIterator(const unique_ptr<Iterator>& it, | |
26 | * initializer_list<int> idsExpected, | |
27 | * Optional<initializer_list<int>> ranksExpected = none) { | |
28 | * for (int i = 0; it->next(); ++i) { | |
29 | * EXPECT_EQ(it->doc().id(), idsExpected[i]); | |
30 | * if (ranksExpected) { | |
31 | * EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]); | |
32 | * } | |
33 | * } | |
34 | * } | |
35 | * | |
36 | * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a | |
37 | * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is | |
38 | * not: | |
39 | * | |
40 | * Optional<int> maybeInt = ...; | |
41 | * if (int* v = get_pointer(maybeInt)) { | |
42 | * cout << *v << endl; | |
43 | * } | |
44 | */ | |
45 | ||
46 | #include <cstddef> | |
47 | #include <functional> | |
48 | #include <new> | |
49 | #include <stdexcept> | |
50 | #include <type_traits> | |
51 | #include <utility> | |
52 | ||
53 | #include <folly/CPortability.h> | |
54 | #include <folly/Traits.h> | |
55 | #include <folly/Utility.h> | |
56 | ||
57 | namespace folly { | |
58 | ||
59 | template <class Value> | |
60 | class Optional; | |
61 | ||
62 | namespace detail { | |
63 | template <class Value> | |
64 | struct OptionalPromiseReturn; | |
65 | } // namespace detail | |
66 | ||
67 | struct None { | |
68 | enum class _secret { _token }; | |
69 | ||
70 | /** | |
71 | * No default constructor to support both `op = {}` and `op = none` | |
72 | * as syntax for clearing an Optional, just like std::nullopt_t. | |
73 | */ | |
74 | constexpr explicit None(_secret) {} | |
75 | }; | |
76 | constexpr None none{None::_secret::_token}; | |
77 | ||
78 | class FOLLY_EXPORT OptionalEmptyException : public std::runtime_error { | |
79 | public: | |
80 | OptionalEmptyException() | |
81 | : std::runtime_error("Empty Optional cannot be unwrapped") {} | |
82 | }; | |
83 | ||
84 | template <class Value> | |
85 | class Optional { | |
86 | public: | |
87 | typedef Value value_type; | |
88 | ||
89 | static_assert( | |
90 | !std::is_reference<Value>::value, | |
91 | "Optional may not be used with reference types"); | |
92 | static_assert( | |
93 | !std::is_abstract<Value>::value, | |
94 | "Optional may not be used with abstract types"); | |
95 | ||
96 | Optional() noexcept {} | |
97 | ||
98 | Optional(const Optional& src) noexcept( | |
99 | std::is_nothrow_copy_constructible<Value>::value) { | |
100 | if (src.hasValue()) { | |
101 | construct(src.value()); | |
102 | } | |
103 | } | |
104 | ||
105 | Optional(Optional&& src) noexcept( | |
106 | std::is_nothrow_move_constructible<Value>::value) { | |
107 | if (src.hasValue()) { | |
108 | construct(std::move(src.value())); | |
109 | src.clear(); | |
110 | } | |
111 | } | |
112 | ||
113 | /* implicit */ Optional(const None&) noexcept {} | |
114 | ||
115 | /* implicit */ Optional(Value&& newValue) noexcept( | |
116 | std::is_nothrow_move_constructible<Value>::value) { | |
117 | construct(std::move(newValue)); | |
118 | } | |
119 | ||
120 | /* implicit */ Optional(const Value& newValue) noexcept( | |
121 | std::is_nothrow_copy_constructible<Value>::value) { | |
122 | construct(newValue); | |
123 | } | |
124 | ||
125 | template <typename... Args> | |
126 | explicit Optional(in_place_t, Args&&... args) noexcept( | |
127 | std::is_nothrow_constructible<Value, Args...>::value) | |
128 | : Optional{PrivateConstructor{}, std::forward<Args>(args)...} {} | |
129 | ||
130 | template <typename U, typename... Args> | |
131 | explicit Optional( | |
132 | in_place_t, | |
133 | std::initializer_list<U> il, | |
134 | Args&&... args) noexcept(std:: | |
135 | is_nothrow_constructible< | |
136 | Value, | |
137 | std::initializer_list<U>, | |
138 | Args...>::value) | |
139 | : Optional{PrivateConstructor{}, il, std::forward<Args>(args)...} {} | |
140 | ||
141 | // Used only when an Optional is used with coroutines on MSVC | |
142 | /* implicit */ Optional(const detail::OptionalPromiseReturn<Value>& p) | |
143 | : Optional{} { | |
144 | p.promise_->value_ = this; | |
145 | } | |
146 | ||
147 | void assign(const None&) { | |
148 | clear(); | |
149 | } | |
150 | ||
151 | void assign(Optional&& src) { | |
152 | if (this != &src) { | |
153 | if (src.hasValue()) { | |
154 | assign(std::move(src.value())); | |
155 | src.clear(); | |
156 | } else { | |
157 | clear(); | |
158 | } | |
159 | } | |
160 | } | |
161 | ||
162 | void assign(const Optional& src) { | |
163 | if (src.hasValue()) { | |
164 | assign(src.value()); | |
165 | } else { | |
166 | clear(); | |
167 | } | |
168 | } | |
169 | ||
170 | void assign(Value&& newValue) { | |
171 | if (hasValue()) { | |
172 | storage_.value = std::move(newValue); | |
173 | } else { | |
174 | construct(std::move(newValue)); | |
175 | } | |
176 | } | |
177 | ||
178 | void assign(const Value& newValue) { | |
179 | if (hasValue()) { | |
180 | storage_.value = newValue; | |
181 | } else { | |
182 | construct(newValue); | |
183 | } | |
184 | } | |
185 | ||
186 | Optional& operator=(None) noexcept { | |
187 | reset(); | |
188 | return *this; | |
189 | } | |
190 | ||
191 | template <class Arg> | |
192 | Optional& operator=(Arg&& arg) { | |
193 | assign(std::forward<Arg>(arg)); | |
194 | return *this; | |
195 | } | |
196 | ||
197 | Optional& operator=(Optional&& other) noexcept( | |
198 | std::is_nothrow_move_assignable<Value>::value) { | |
199 | assign(std::move(other)); | |
200 | return *this; | |
201 | } | |
202 | ||
203 | Optional& operator=(const Optional& other) noexcept( | |
204 | std::is_nothrow_copy_assignable<Value>::value) { | |
205 | assign(other); | |
206 | return *this; | |
207 | } | |
208 | ||
209 | template <class... Args> | |
210 | Value& emplace(Args&&... args) { | |
211 | clear(); | |
212 | construct(std::forward<Args>(args)...); | |
213 | return value(); | |
214 | } | |
215 | ||
216 | template <class U, class... Args> | |
217 | typename std::enable_if< | |
218 | std::is_constructible<Value, std::initializer_list<U>&, Args&&...>::value, | |
219 | Value&>::type | |
220 | emplace(std::initializer_list<U> ilist, Args&&... args) { | |
221 | clear(); | |
222 | construct(ilist, std::forward<Args>(args)...); | |
223 | return value(); | |
224 | } | |
225 | ||
226 | void reset() noexcept { | |
227 | storage_.clear(); | |
228 | } | |
229 | ||
230 | void clear() noexcept { | |
231 | reset(); | |
232 | } | |
233 | ||
234 | void swap(Optional& that) noexcept(IsNothrowSwappable<Value>::value) { | |
235 | if (hasValue() && that.hasValue()) { | |
236 | using std::swap; | |
237 | swap(value(), that.value()); | |
238 | } else if (hasValue()) { | |
239 | that.emplace(std::move(value())); | |
240 | reset(); | |
241 | } else if (that.hasValue()) { | |
242 | emplace(std::move(that.value())); | |
243 | that.reset(); | |
244 | } | |
245 | } | |
246 | ||
247 | const Value& value() const& { | |
248 | require_value(); | |
249 | return storage_.value; | |
250 | } | |
251 | ||
252 | Value& value() & { | |
253 | require_value(); | |
254 | return storage_.value; | |
255 | } | |
256 | ||
257 | Value&& value() && { | |
258 | require_value(); | |
259 | return std::move(storage_.value); | |
260 | } | |
261 | ||
262 | const Value&& value() const&& { | |
263 | require_value(); | |
264 | return std::move(storage_.value); | |
265 | } | |
266 | ||
267 | const Value* get_pointer() const& { | |
268 | return storage_.hasValue ? &storage_.value : nullptr; | |
269 | } | |
270 | Value* get_pointer() & { | |
271 | return storage_.hasValue ? &storage_.value : nullptr; | |
272 | } | |
273 | Value* get_pointer() && = delete; | |
274 | ||
275 | bool has_value() const noexcept { | |
276 | return storage_.hasValue; | |
277 | } | |
278 | ||
279 | bool hasValue() const noexcept { | |
280 | return has_value(); | |
281 | } | |
282 | ||
283 | explicit operator bool() const noexcept { | |
284 | return has_value(); | |
285 | } | |
286 | ||
287 | const Value& operator*() const& { | |
288 | return value(); | |
289 | } | |
290 | Value& operator*() & { | |
291 | return value(); | |
292 | } | |
293 | const Value&& operator*() const&& { | |
294 | return std::move(value()); | |
295 | } | |
296 | Value&& operator*() && { | |
297 | return std::move(value()); | |
298 | } | |
299 | ||
300 | const Value* operator->() const { | |
301 | return &value(); | |
302 | } | |
303 | Value* operator->() { | |
304 | return &value(); | |
305 | } | |
306 | ||
307 | // Return a copy of the value if set, or a given default if not. | |
308 | template <class U> | |
309 | Value value_or(U&& dflt) const& { | |
310 | if (storage_.hasValue) { | |
311 | return storage_.value; | |
312 | } | |
313 | ||
314 | return std::forward<U>(dflt); | |
315 | } | |
316 | ||
317 | template <class U> | |
318 | Value value_or(U&& dflt) && { | |
319 | if (storage_.hasValue) { | |
320 | return std::move(storage_.value); | |
321 | } | |
322 | ||
323 | return std::forward<U>(dflt); | |
324 | } | |
325 | ||
326 | private: | |
327 | template <class T> | |
328 | friend Optional<_t<std::decay<T>>> make_optional(T&&); | |
329 | template <class T, class... Args> | |
330 | friend Optional<T> make_optional(Args&&... args); | |
331 | template <class T, class U, class... As> | |
332 | friend Optional<T> make_optional(std::initializer_list<U>, As&&...); | |
333 | ||
334 | /** | |
335 | * Construct the optional in place, this is duplicated as a non-explicit | |
336 | * constructor to allow returning values that are non-movable from | |
337 | * make_optional using list initialization. | |
338 | * | |
339 | * Until C++17, at which point this will become unnecessary because of | |
340 | * specified prvalue elision. | |
341 | */ | |
342 | struct PrivateConstructor { | |
343 | explicit PrivateConstructor() = default; | |
344 | }; | |
345 | template <typename... Args> | |
346 | Optional(PrivateConstructor, Args&&... args) noexcept( | |
347 | std::is_constructible<Value, Args&&...>::value) { | |
348 | construct(std::forward<Args>(args)...); | |
349 | } | |
350 | ||
351 | void require_value() const { | |
352 | if (!storage_.hasValue) { | |
353 | throw OptionalEmptyException{}; | |
354 | } | |
355 | } | |
356 | ||
357 | template <class... Args> | |
358 | void construct(Args&&... args) { | |
359 | const void* ptr = &storage_.value; | |
360 | // For supporting const types. | |
361 | new (const_cast<void*>(ptr)) Value(std::forward<Args>(args)...); | |
362 | storage_.hasValue = true; | |
363 | } | |
364 | ||
365 | struct StorageTriviallyDestructible { | |
366 | union { | |
367 | char emptyState; | |
368 | Value value; | |
369 | }; | |
370 | bool hasValue; | |
371 | ||
372 | StorageTriviallyDestructible() | |
373 | : emptyState('\0'), hasValue{false} {} | |
374 | void clear() { | |
375 | hasValue = false; | |
376 | } | |
377 | }; | |
378 | ||
379 | struct StorageNonTriviallyDestructible { | |
380 | union { | |
381 | char emptyState; | |
382 | Value value; | |
383 | }; | |
384 | bool hasValue; | |
385 | ||
386 | StorageNonTriviallyDestructible() : hasValue{false} {} | |
387 | ~StorageNonTriviallyDestructible() { | |
388 | clear(); | |
389 | } | |
390 | ||
391 | void clear() { | |
392 | if (hasValue) { | |
393 | hasValue = false; | |
394 | value.~Value(); | |
395 | } | |
396 | } | |
397 | }; | |
398 | ||
399 | using Storage = typename std::conditional< | |
400 | std::is_trivially_destructible<Value>::value, | |
401 | StorageTriviallyDestructible, | |
402 | StorageNonTriviallyDestructible>::type; | |
403 | ||
404 | Storage storage_; | |
405 | }; | |
406 | ||
407 | template <class T> | |
408 | const T* get_pointer(const Optional<T>& opt) { | |
409 | return opt.get_pointer(); | |
410 | } | |
411 | ||
412 | template <class T> | |
413 | T* get_pointer(Optional<T>& opt) { | |
414 | return opt.get_pointer(); | |
415 | } | |
416 | ||
417 | template <class T> | |
418 | void swap(Optional<T>& a, Optional<T>& b) noexcept(noexcept(a.swap(b))) { | |
419 | a.swap(b); | |
420 | } | |
421 | ||
422 | template <class T> | |
423 | Optional<_t<std::decay<T>>> make_optional(T&& v) { | |
424 | using PrivateConstructor = | |
425 | typename folly::Optional<_t<std::decay<T>>>::PrivateConstructor; | |
426 | return {PrivateConstructor{}, std::forward<T>(v)}; | |
427 | } | |
428 | ||
429 | template <class T, class... Args> | |
430 | folly::Optional<T> make_optional(Args&&... args) { | |
431 | using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor; | |
432 | return {PrivateConstructor{}, std::forward<Args>(args)...}; | |
433 | } | |
434 | ||
435 | template <class T, class U, class... Args> | |
436 | folly::Optional<T> make_optional( | |
437 | std::initializer_list<U> il, | |
438 | Args&&... args) { | |
439 | using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor; | |
440 | return {PrivateConstructor{}, il, std::forward<Args>(args)...}; | |
441 | } | |
442 | ||
443 | /////////////////////////////////////////////////////////////////////////////// | |
444 | // Comparisons. | |
445 | ||
446 | template <class U, class V> | |
447 | bool operator==(const Optional<U>& a, const V& b) { | |
448 | return a.hasValue() && a.value() == b; | |
449 | } | |
450 | ||
451 | template <class U, class V> | |
452 | bool operator!=(const Optional<U>& a, const V& b) { | |
453 | return !(a == b); | |
454 | } | |
455 | ||
456 | template <class U, class V> | |
457 | bool operator==(const U& a, const Optional<V>& b) { | |
458 | return b.hasValue() && b.value() == a; | |
459 | } | |
460 | ||
461 | template <class U, class V> | |
462 | bool operator!=(const U& a, const Optional<V>& b) { | |
463 | return !(a == b); | |
464 | } | |
465 | ||
466 | template <class U, class V> | |
467 | bool operator==(const Optional<U>& a, const Optional<V>& b) { | |
468 | if (a.hasValue() != b.hasValue()) { | |
469 | return false; | |
470 | } | |
471 | if (a.hasValue()) { | |
472 | return a.value() == b.value(); | |
473 | } | |
474 | return true; | |
475 | } | |
476 | ||
477 | template <class U, class V> | |
478 | bool operator!=(const Optional<U>& a, const Optional<V>& b) { | |
479 | return !(a == b); | |
480 | } | |
481 | ||
482 | template <class U, class V> | |
483 | bool operator<(const Optional<U>& a, const Optional<V>& b) { | |
484 | if (a.hasValue() != b.hasValue()) { | |
485 | return a.hasValue() < b.hasValue(); | |
486 | } | |
487 | if (a.hasValue()) { | |
488 | return a.value() < b.value(); | |
489 | } | |
490 | return false; | |
491 | } | |
492 | ||
493 | template <class U, class V> | |
494 | bool operator>(const Optional<U>& a, const Optional<V>& b) { | |
495 | return b < a; | |
496 | } | |
497 | ||
498 | template <class U, class V> | |
499 | bool operator<=(const Optional<U>& a, const Optional<V>& b) { | |
500 | return !(b < a); | |
501 | } | |
502 | ||
503 | template <class U, class V> | |
504 | bool operator>=(const Optional<U>& a, const Optional<V>& b) { | |
505 | return !(a < b); | |
506 | } | |
507 | ||
508 | // Suppress comparability of Optional<T> with T, despite implicit conversion. | |
509 | template <class V> | |
510 | bool operator<(const Optional<V>&, const V& other) = delete; | |
511 | template <class V> | |
512 | bool operator<=(const Optional<V>&, const V& other) = delete; | |
513 | template <class V> | |
514 | bool operator>=(const Optional<V>&, const V& other) = delete; | |
515 | template <class V> | |
516 | bool operator>(const Optional<V>&, const V& other) = delete; | |
517 | template <class V> | |
518 | bool operator<(const V& other, const Optional<V>&) = delete; | |
519 | template <class V> | |
520 | bool operator<=(const V& other, const Optional<V>&) = delete; | |
521 | template <class V> | |
522 | bool operator>=(const V& other, const Optional<V>&) = delete; | |
523 | template <class V> | |
524 | bool operator>(const V& other, const Optional<V>&) = delete; | |
525 | ||
526 | // Comparisons with none | |
527 | template <class V> | |
528 | bool operator==(const Optional<V>& a, None) noexcept { | |
529 | return !a.hasValue(); | |
530 | } | |
531 | template <class V> | |
532 | bool operator==(None, const Optional<V>& a) noexcept { | |
533 | return !a.hasValue(); | |
534 | } | |
535 | template <class V> | |
536 | bool operator<(const Optional<V>&, None) noexcept { | |
537 | return false; | |
538 | } | |
539 | template <class V> | |
540 | bool operator<(None, const Optional<V>& a) noexcept { | |
541 | return a.hasValue(); | |
542 | } | |
543 | template <class V> | |
544 | bool operator>(const Optional<V>& a, None) noexcept { | |
545 | return a.hasValue(); | |
546 | } | |
547 | template <class V> | |
548 | bool operator>(None, const Optional<V>&) noexcept { | |
549 | return false; | |
550 | } | |
551 | template <class V> | |
552 | bool operator<=(None, const Optional<V>&) noexcept { | |
553 | return true; | |
554 | } | |
555 | template <class V> | |
556 | bool operator<=(const Optional<V>& a, None) noexcept { | |
557 | return !a.hasValue(); | |
558 | } | |
559 | template <class V> | |
560 | bool operator>=(const Optional<V>&, None) noexcept { | |
561 | return true; | |
562 | } | |
563 | template <class V> | |
564 | bool operator>=(None, const Optional<V>& a) noexcept { | |
565 | return !a.hasValue(); | |
566 | } | |
567 | ||
568 | /////////////////////////////////////////////////////////////////////////////// | |
569 | ||
570 | } // namespace folly |